JAXB - 将通用类型(日期)编组

3

我希望你能帮忙翻译一下关于使用JAXB进行通用类型的序列化/反序列化的问题。

在我的代码中,当通用字段是Date(java.util.Date)类型时,反序列化会产生XMLGregorianCalendar类型而不是期望的Date类型。虽然其他情况下都能正常工作。

以下是相关代码:

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Entity<T> {
    private T field;

    public Entity() {
    }

    public T getField() {
        return field;
    }

    public void setField(T field) {
        this.field = field;
    }
}
import java.io.*;
import java.util.Date;
import javax.xml.bind.*;

public class JaxbTest {
    public JaxbTest() {

        Entity<Date> ent = new Entity<Date>();
        ent.setField(new Date());

        StringWriter sw = new StringWriter();

        try {
            // marshall
            JAXBContext jaxbContext = JAXBContext.newInstance(Entity.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            jaxbMarshaller.marshal(ent, sw);

            // unmarshall
            JAXBContext jc = JAXBContext.newInstance(Entity.class);
            Unmarshaller u = jc.createUnmarshaller();
            Entity<Date> ent2 = (Entity<Date>) u.unmarshal(new StringReader(sw
                    .toString()));// exception is thrown here
            System.out.println(ent2.getField());
        } catch (JAXBException e11) {
            e11.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new JaxbTest();
    }

}
上述代码会抛出异常:
java.lang.ClassCastException: com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl cannot be cast to java.util.Date
    at JaxbTest.<init>(JaxbTest.java:31)
    at JaxbTest.main(JaxbTest.java:38)

你能帮我解决这个问题吗?我在考虑一些适配器,只有在字段为日期时才会“激活”,但我认为这是不可能的。

谢谢


我猜你犯了一个错误,错误在ent2.getField()这一行吧? - Mark Peters
2个回答

1
一个 JAXBContext 是基于类而不是类型构建的。就你的 JAXB (JSR-222) 实现而言,field 属性是 Object 类型。如果你在代码中添加以下内容:
        String xml = sw.toString();
        System.out.println(xml);
您将看到以下输出XML。已添加xsi:type属性以保留文本值包含日期信息的事实。在unmarshal操作中,由于JAXB认为该属性的类型为Object,它将识别xsi:type属性并将值转换为默认日期类型,即XMLGregorianCalendar
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<entity>
    <field xsi:type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2012-10-29T15:20:17.763-04:00</field>
</entity>

你有什么想法可以教JAXB如何使用java.util.Date或任何其他日期实现吗? - Gregor Valentin
首先,可以使用扩展XMLAdapter的适配器来实现。第二种方法是,在接收到消息后,使用xmlGregorianCalendar.toGregorianCalendar().getTime()方法将其转换为日期对象。 - Mustafa Kemal

0

我在抽象类中的一个通用字段上遇到了类似的问题。我通过添加一个带注释的getter/setter来解决它,该getter/setter将值解析为/从字符串。然后,在我的子类中覆盖getter/setter。

这是我的解决方案:

@XmlSeeAlso({DateEntity.class})
@XmlType
public abstract class Entity<T> {
    private T field;

    public Entity() {}

    public T getField() {
        return this.field;
    }

    public void setField(T field) {
        this.field = field;
    }

    @XmlAttribute(name="value", required = true)
    public abstract String getSerializeField();
    public abstract void setSerializeField(String value);
}

我的日期子类:

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name="dateEntity")
public class DateEntity extends Entity<Date> {

    public DateEntity() {}

    @Override
    public String getSerializeField(){
        DateFormat formatter = DateFormat.getInstance();
        return formatter.format(field);
    }

    @Override
    public void setSerializeField(String value) {
        DateFormat formatter = DateFormat.getInstance();
        this.value = formatter.parse(value);
    }
}

希望这对你有所帮助...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,