3

我再次对带有外部元数据映射文件的 Eclipselink/MOXy 有疑问。

我有一个适用于类的参考 xml。此 xml 包含适用于类可以包含的某些但并非总是所有属性的数据。

我还为日期字段设置了自定义日期时间适配器。

我的问题是我正在解组的 xml 不包含 endDate 属性的任何数据,但是当我做这个简单的测试时:

  • 将引用 xml 解组到类
  • 将该类编组到一个新的 xml 文件
  • 比较两个xml文件

该属性 endDate (不应编组,因为它尚未设置)被编组为 09/01/2012 17:05:28 (它总是编组为设置为当前时间的新 Date() )。

这是一个示例 XML 元数据文件:

<?xml version="1.0"?>
<xml-bindings  xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
                version="2.1">
    <java-types>
        <java-type name="sample.clazz.Task" xml-accessor-type="NONE">
            <xml-root-element name="Task" />
            <xml-type prop-order="startDate endDate id ci ch cr" />
            <java-attributes>
                <xml-element java-attribute="startDate" xml-path="StartDate/text()">
                    <xml-java-type-adapter value="utils.JaxBDateTimeAdapter" type="java.util.Date"/>
                </xml-element>
                <xml-element java-attribute="endDate" required="false" xml-path="EndDate/text()">
                    <xml-java-type-adapter value="utils.JaxBDateTimeAdapter" type="java.util.Date"/>
                </xml-element>
                <xml-element java-attribute="id" xml-path="TaskId/text()" />
                <xml-element java-attribute="ci" xml-path="CIPR/text()" />
                <xml-element java-attribute="ch" xml-path="CHPR/text()" />
                <xml-element java-attribute="cr" xml-path="CRPR/text()" />
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

这是课程:

package sample.clazz;

public class Task{

    private int id;
    private Date startDate;
    private Date endDate;
    private String ci;
    private String ch;
    private String cr;

    public Task(){

    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public Date getStartDate() {
        return startDate;
    }
    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }
    public Date getEndDate() {
        return endDate;
    }
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }
    public String getCi() {
        return ci;
    }
    public void setCi(String ci) {
        this.ci = ci;
    }
    public String getCh() {
        return ch;
    }
    public void setCh(String ch) {
        this.ch = ch;
    }
    public String getCr() {
        return cr;
    }
    public void setCr(String cr) {
        this.cr = cr;
    }

}

这是我的自定义 DateTimeAdapter :

package utils;

import java.util.Date;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class JaxBDateTimeAdapter extends XmlAdapter<String, Date>  {


    @Override
    public String marshal(Date d) throws Exception {
        if(d != null){
            return DateUtil.getFormatedDateTimeString(d);
        }
        else{
            return null;
        }
    }

    @Override
    public Date unmarshal(String d) throws Exception {
        if(d != null && !"".equals(d)){
            return DateUtil.getDateFromString(d);
        }
        else{
            return null;
        }
    }
}

这是我的参考 XML

<?xml version="1.0" encoding="UTF-8"?>
<Task>
    <TaskId>147</TaskId>
    <CRPR>0087</CRPR>
    <CIPR>A683557</CIPR>
    <CHPR>BV</CHPR>
    <StartDate>22/01/2009 20:56:29</StartDate>
</Task>

这是我在重新编组对象时得到的 XML:

<?xml version="1.0" encoding="UTF-8"?>
<Task>
    <TaskId>147</TaskId>
    <CRPR>0087</CRPR>
    <CIPR>A683557</CIPR>
    <CHPR>BV</CHPR>
    <StartDate>01/01/2012 20:56:29</StartDate>
    <EndDate>09/01/2012 17:05:28</EndDate> <!-- That element should not exist ! -->
</Task>

似乎 Jaxb 为空字段生成了一个新日期,我如何通过外部元数据映射文件告诉他不要为空值或空值生成节点?我尝试在元数据文件上设置 required=false,如果值为 null,我尝试使用我的自定义 DateTimeAdapter 进行测试,但似乎 Jaxb 创建了一个新的 Date 对象并将其传递给适配器的 marshal 方法。我想不出任何办法阻止他这样做。

至于我以前的问题,我无法控制传入的 XML 或模型类。

请注意:这个数据是我写的一个样本,它可能不准确,因为我不能暴露真实的数据或名字,可能有一些打字错误。

谢谢你的帮助。

4

1 回答 1

2

我是EclipseLink JAXB (MOXy)负责人,我无法重现您的问题。DateUtil你的班级可能有问题。以下是我尝试过的:

oxm.xml

我对您的元数据文件做了一个小改动。基本上我将其更改为在xml-bindings元素上指定包名称而不是单个java-type元素:

<?xml version="1.0"?>
<xml-bindings  
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    version="2.3"
    package-name="sample.clazz">
    <java-types>
        <java-type name="Task" xml-accessor-type="NONE">
            <xml-root-element name="Task" />
            <xml-type prop-order="startDate endDate id ci ch cr" />
            <java-attributes>
                <xml-element java-attribute="startDate" xml-path="StartDate/text()">
                    <xml-java-type-adapter value="forum8791782.JaxBDateTimeAdapter" type="java.util.Date"/>
                </xml-element>
                <xml-element java-attribute="endDate" required="false" xml-path="EndDate/text()">
                    <xml-java-type-adapter value="forum8791782.JaxBDateTimeAdapter" type="java.util.Date"/>
                </xml-element>
                <xml-element java-attribute="id" xml-path="TaskId/text()" />
                <xml-element java-attribute="ci" xml-path="CIPR/text()" />
                <xml-element java-attribute="ch" xml-path="CHPR/text()" />
                <xml-element java-attribute="cr" xml-path="CRPR/text()" />
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

日期实用程序

您没有DateUtil在您的问题中提供实现,所以我使用了以下内容。我的猜测是您的实现中有代码DateUtil导致您看到的输出:

package forum8791782;

import java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtil {

    private static SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");

    public static String getFormatedDateTimeString(Date d) {
        return formatter.format(d);
    }

    public static Date getDateFromString(String d) {
        try {
            return formatter.parse(d);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

}

演示

下面是我用来运行这个例子的代码。 input.xml是您在问题中引用的参考 XML:

package forum8791782;

import java.io.File;
import java.util.*;
import javax.xml.bind.*;

import org.eclipse.persistence.Version;
import org.eclipse.persistence.jaxb.JAXBContextFactory;

import sample.clazz.Task;

public class Demo {

    public static void main(String[] args) throws Exception {
        System.out.println(Version.getVersionString());

        Map<String, Object> properties = new HashMap<String, Object>(1);
        properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum8791782/oxm.xml");
        JAXBContext jc = JAXBContext.newInstance(new Class[] {Task.class}, properties);

        File xml = new File("src/forum8791782/input.xml");
        Unmarshaller u = jc.createUnmarshaller();
        Task task = (Task) u.unmarshal(xml);

        Marshaller m = jc.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        m.marshal(task, System.out);
    }

}

输出

以下是我运行示例代码得到的输出。我没有看到EndDate写出的元素。

2.3.2.v20111125-r10461
<?xml version="1.0" encoding="UTF-8"?>
<Task>
   <StartDate>22/01/2009 20:56:29</StartDate>
   <TaskId>147</TaskId>
   <CIPR>A683557</CIPR>
   <CHPR>BV</CHPR>
   <CRPR>0087</CRPR>
</Task>
于 2012-01-09T17:27:51.140 回答