【问题标题】:JAXB - marshall generic type (Date)JAXB - 编组泛型类型(日期)
【发布时间】:2012-10-26 09:41:52
【问题描述】:

我无法使用 JAXB 编组/解组泛型类型。 一切正常,但是当我的通用字段是 Date (java.util.Date) 时,解组将生成 XMLGregorianCalendar

这是我正在谈论的一段代码:

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)

你能帮我解决它吗?我正在考虑一些仅当字段为 Date 时才会“活动”的适配器,但我认为这是不可能的

谢谢

【问题讨论】:

  • 我猜你犯了一个错误,错误就在ent2.getField()?

标签: java generics jaxb


【解决方案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 或任何其他 Date 实现吗?
  • 首先可以使用一个适配器(扩展 XMLAdapter)。第二种方法,收到消息后,使用 xmlGregorianCalendar.toGregorianCalendar().getTime() 方法将其转换为日期对象。
【解决方案2】:

抽象类中的泛型字段也有类似的问题。我通过添加一个带注释的 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);
    }
}

希望对您有所帮助...

【讨论】:

    猜你喜欢
    • 2010-10-24
    • 1970-01-01
    • 2011-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多