java - JAXB 绑定(bind)文件将 @XmlElement 类型设置为 String 而不是 XMLGregorianCalendar

标签 java xml generics jaxb

我正在尝试创建一个XmlAdapter,它接收一个XMLGregorianCalendar 并输出一个XMLGregorianCalendar。目的只是在解码数据时从元素中删除时区数据。

看起来像这样:

public class TimezoneRemoverAdapter extends XmlAdapter<XMLGregorianCalendar, XMLGregorianCalendar> {
    public XMLGregorianCalendar unmarshal(XMLGregorianCalendar xgc) {
        if(xgc == null) {
            return null;
        }
        xgc.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
        return xgc;
    }

    public XMLGregorianCalendar marshal(XMLGregorianCalendar xgc) {
        return xgc;
    }
}

这适用于以下代码:

public class FooElement {
    @XmlElement(name="bar-date")
    @XmlJavaTypeAdapter(TimezoneRemoverAdapter.class)
    @XmlSchemaType(name = "date")
    protected XMLGregorianCalendar barDate;
}

不幸的是,当我使用 jaxb-bindings.xml 文件生成代码时,上面的代码如下所示:

public class FooElement {
    @XmlElement(name="bar-date", type=java.lang.String.class)
    @XmlJavaTypeAdapter(TimezoneRemoverAdapter.class)
    @XmlSchemaType(name = "date")
    protected XMLGregorianCalendar barDate;
}

它将类型设置为String,所以我上面的方法不起作用。 String 类型设置覆盖了它应该是的 XMLGregorianCalendar 类型。我可以手动更改它,但我宁愿不必记住每次重新生成 jaxb 文件时都更新它。有谁知道是否可以手动设置 @XmlElement 类型或忽略它?

这是 jaxb-bindings.xml 文件的相关部分:

<jxb:bindings node=".//xs:element[@name=bar-date]">
    <jxb:property>
        <jxb:baseType>
            <jxb:javaType name="javax.xml.datatype.XMLGregorianCalendar" adapter="foo.bar.TimezoneRemoverAdapter" />
        </jxb:baseType>
    </jxb:property>
</jxb:bindings>

最佳答案

更新

总结:

  1. 您的架构在某处使用日期样式,并且您无法更改架构
  2. 您有一些使用该架构的 XML 数据,并指定了一些带有时区的日期(所以它是 yyyy-MM-ddXXX 格式)
  3. 您想从该文件中日期的表示形式中删除 XXX 部分(日期本身不提供任何时区,日期只是一个数字)<

所以这可能是一个示例架构:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <element name="foo">
        <complexType>
            <sequence>
                <element name="bar" type="date" minOccurs="1" maxOccurs="1"/>
            </sequence>
        </complexType>
    </element>
</schema>

这可能是一个示例数据:

<?xml version="1.0" encoding="UTF-8"?>
<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="foo.xsd">
    <bar>2014-01-01+06:00</bar>
</foo>

这是 JAXB 注释类

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo implements Serializable
{
    private static final long serialVersionUID = 1L;

    @XmlElement(name = "bar")
    @XmlJavaTypeAdapter(DateAdapter.class)
    @XmlSchemaType(name = "date")
    private Date bar;

    // getters/setters
}

这是日期适配器

public class DateAdapter extends XmlAdapter<String, Date>
{
    @Override
    public String marshal(Date date)
    {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        df.setTimeZone(TimeZone.getTimeZone("GMT"));
        return df.format(date);
    }

    @Override
    public Date unmarshal(String date) throws ParseException
    {
        DateFormat df = new SimpleDateFormat("yyyy-MM-ddXXX");
        return df.parse(date);
    }
}

这是主要的,针对架构进行验证:

public static void main(String[] args) throws JAXBException, SAXException
{
    JAXBContext context = JAXBContext.newInstance(Foo.class);

    SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = sf.newSchema(Foo.class.getResource("/foo.xsd"));

    Unmarshaller unmarshaller = context.createUnmarshaller();
    unmarshaller.setSchema(schema);
    Foo foo = (Foo) unmarshaller.unmarshal(Foo.class.getResource("/foo.xml"));
    System.out.println("unmarshalled: " + foo.getBar());

    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "foo.xsd");
    marshaller.setSchema(schema);
    marshaller.marshal(foo, System.out);
}

这是输出,时区已被删除,日期表示已明显改变

unmarshalled: Tue Dec 31 19:00:00 CET 2013
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="foo.xsd">
    <bar>2013-12-31</bar>
</foo>

也许这个日期表示的变化不是你所期望的,但这不是 JAXB 的问题,表示的日期没有改变。

我忘记了反向生成 Foo 的绑定(bind):

<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.0">
    <jaxb:globalBindings>
        <xjc:javaType name="java.util.Date" xmlType="xsd:date" adapter="aaa.DateAdapter" />
    </jaxb:globalBindings>
</jaxb:bindings>

更新结束


抱歉,评论太长了……

我不明白:

  1. 你为什么要使用 XmlGregorianCalendar
  2. 为什么要marshal/unmarshal(serialize/deserialize)到完全相同的数据结构?
  3. 为什么要删除时区??

  1. 我使用简单直接的java.util.Date
  2. marshal/unmarshal 应该始终包含 String(至少对于 XML)
  3. 我真的没有理由任意删除日期表示。也许你想以绝对的方式序列化它。

然而

public class DateAdapter extends XmlAdapter<String, Date>
{
    @Override
    public String marshal(Date date)
    {
        DateFormat df = DateFormat.getDateTimeInstance();
        df.setTimeZone(TimeZone.getTimeZone("GMT"));

        return df.format(date);
    }

    @Override
    public Date unmarshal(String date) throws ParseException
    {
        DateFormat df = DateFormat.getDateTimeInstance();
        df.setTimeZone(TimeZone.getTimeZone("GMT"));

        return df.parse(date);
    }

    public static void main(String[] args) throws ParseException
    {
        DateAdapter adapter = new DateAdapter();

        String str = adapter.marshal(new Date());
        System.out.println(str); // 16-dic-2013 10.02.09  --> to gmt

        Date date = adapter.unmarshal(str);
        System.out.println(date); // Mon Dec 16 11:02:09 CET 2013  --> correct, i'm gmt+1
    }
}

关于java - JAXB 绑定(bind)文件将 @XmlElement 类型设置为 String 而不是 XMLGregorianCalendar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15936368/

相关文章:

swift - 返回一个符合泛型约束的对象

java - 我应该使用 Quartz XML 作业文件还是使用代码配置作业

java - JiBX 解码 - 是否可以告诉 JiBX 忽略元素的顺序?

java - 使用 DTO 的 Post 方法

java - Maven忽略依赖包的签名

xml - 用 Java 托管 XML 的简单服务器

python - odoo TreeView 中无法识别的字段

vb.net - 如何使用表单中的属性网格来编辑任何类型

ios - 如何为所有实体编写一个简单的通用核心数据函数

java - java中的二进制数据操作