繁体   English   中英

未指定时间时,JAXB编组dateTime为空白值

[英]JAXB marshalling dateTime to blank value when time not specified

我有一个XMLGregorianCalendar对象,试图将其编组为xml字符串。 我通过解组另一个xml对象收到了该对象。 两者都是“ dateTime”类型,因此它们应该完全相同...

但是,当我编组它时,它在xml中显示为空白。

为了说明这个问题, 在此示例中 ,我将所有内容都剥了皮,并使其变得通用。 2个Java文件按原样复制,粘贴,运行。 应该收到的输出将是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TheObject>
    <DOB>2016-09-16</DOB>
</TheObject>

但是,a,它返回:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TheObject>
    <DOB></DOB>
</TheObject>

注意:在pastebin示例中,我动态创建了一个xmlGregorianCalendar,而不是从另一个对象(如下面的代码)中获取一个,因此从技术上讲这不是同一回事,但我认为最终它可以说明完全相同的问题...我错了...

要为我的特定问题添加更多背景信息:

//Here are the objects themselves (names changed to protect the innocent)
//complete with annotations... 
public class Object1{
    ...
    @XmlElement(name = "DOB")
    @XmlSchemaType(name = "dateTime")
    protected XMLGregorianCalendar dob;
    ...
}

public class Object2{
    ...
    @XmlElement(name = "DOB")
    @XmlSchemaType(name = "dateTime")
    protected XMLGregorianCalendar dob;
    ...
}

//and here's the snippet where the date object(date of birth) gets set
//from one object to another.
object2.setDOB(object1.getDOB());

//and finally, marshalling it to an xml string
private String marshallTheObject(Object2 theObject) throws JAXBException{
    JAXBContext jaxbContext = JAXBContext.newInstance(Object2.class);
    Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
    jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    StringWriter sw = new StringWriter();
    jaxbMarshaller.marshal(object2, sw);
    String output = sw.toString();
    return output;
}

//the xml output shows: <DOB></DOB> instead of the date

我正在使用Java 8捆绑的jaxb版本...

所以我的问题是:这是某种错误吗? 如果没有,我在做什么错? 如何解决这个问题而不必修改生成的Java代码? 我也无法编辑用于生成它的xsd文件...

编辑:作为参考,xsd文件将DOB列出为:

<xs:element name="DOB" type="xs:dateTime" />

JAXB不喜欢您将日期时间设置为DatatypeConstants.FIELD_UNDEFINED 如果您注释掉该行:

// calendar.setTime(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);

它将封送类似:

<DOB>2016-09-16T00:00:00.000</DOB>

或者您可以更改生成的注释(或使用的自定义绑定)以将dateTime更改为date,例如:

@XmlSchemaType(name = "date")
protected XMLGregorianCalendar dob;

如果您想看:

<DOB>2016-09-16</DOB>

如果您想更深入一点,那么类似的事情可能是一个起点,或者这就是您所需要的。

虽然不允许我直接修改xsd文件,但我没有意识到我可以更改通过绑定文件生成类本身的方式。 在这种情况下,我没有使用maven,因此确定解决方案有点困难。 我通过使用eclipse中内置的功能来生成类,该功能从xsd文件生成jaxb类。

在这里了解了更多关于绑定文件的信息

我不确定要相对于Maven将该文件放置在何处,但是以eclipse的方式无关紧要-您可以在jaxb类生成向导中指定绑定文件的位置。

生成后,您需要编写自己的xml适配器。

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

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

public class CalendarDateTimeAdapter extends XmlAdapter<String, Date> {

    //Sadly my specific situation requires me to strip the time off of all dateTime objects
    //It's bad, but I didn't get to design the system, so this is the best compromise...
    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    @Override public Date unmarshal(String value) throws ParseException {
        synchronized (sdf){
            return sdf.parse(value);
        }
    }

    @Override public String marshal(Date value) {
        if(value == null) { return null; }
        synchronized(sdf){
            return sdf.format(value);
        }
    }
}

确保您的类与您在绑定文件中指定的类匹配...

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jaxb:bindings>

<jaxb:bindings version="2.1"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">

    <!-- Prevent wrapping data types into JAXBElements. -->
    <jaxb:globalBindings generateElementProperty="false">

        <!-- Use java.util.Date instead of XMLGregorianCalendar. -->
        <xjc:javaType name="java.util.Date" xmlType="xs:dateTime"
            adapter="com.package.location.adapter.CalendarDateTimeAdapter"/>
        <xjc:javaType name="java.util.Date" xmlType="xs:date"
            adapter="com.package.location.adapter.CalendarDateAdapter"/>
        <xjc:javaType name="java.util.Date" xmlType="xs:time"
            adapter="com.package.location.adapter.CalendarTimeAdapter"/>

    </jaxb:globalBindings>
</jaxb:bindings>

然后,在进行编组时,请使用setAdapter函数来使用它。

private String marshallObject(MyObject myObject) throws JAXBException{
    JAXBContext jaxbContext = JAXBContext.newInstance(MyObject.class);
    Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
    jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    jaxbMarshaller.setAdapter(new CalendarDateTimeAdapter());
    StringWriter sw = new StringWriter();
    jaxbMarshaller.marshal(myObject, sw);
    String output = sw.toString();
    return output;
}

现在,他们将解析为Date对象,而不是XMLGregorianCalendar对象。 显然,Date对象比XMLGregorianCalendars更好。

我仍然感到困惑的是,进入的未编组的xml不会封送成为相同的xml,但是无论如何,这正是我所做的一切,以使它们全部开始工作。 我确定我在这里做了一些违背常规的事情,如果有,请告诉我。

再次提醒读者,我没有使用maven,也没有任何框架(例如SpringMVC)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM