简体   繁体   English

JAXB绑定文件将@XmlElement类型设置为String而不是XMLGregorianCalendar

[英]JAXB Bindings File Sets @XmlElement type to String instead of XMLGregorianCalendar

I'm trying to create an XmlAdapter that takes in an XMLGregorianCalendar and outputs an XMLGregorianCalendar . 我正在尝试创建一个XmlAdapter ,它接受XMLGregorianCalendar并输出XMLGregorianCalendar The purpose is simlply to remove timezone data from the element when unmarshalling data. 目的是简单地在解组数据时从元素中删除时区数据。

It looks like this: 它看起来像这样:

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;
    }
}

This works fine for the following code: 这适用于以下代码:

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

Unfortunately, when I generate the code using a jaxb-bindings.xml file, the above code looks like this: 不幸的是,当我使用jaxb-bindings.xml文件生成代码时,上面的代码如下所示:

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

It sets the type to String , so my above method doesn't work. 它将类型设置为String ,因此我的上述方法不起作用。 The type String setting is overriding the XMLGregorianCalendar type that it should be. String类型设置将覆盖它应该是的XMLGregorianCalendar类型。 I can manually change it, but I'd rather not have to remember to update it every time the jaxb files are regenerated. 我可以手动更改它,但我不必记住每次重新生成jaxb文件时都要更新它。 Does anyone know if there's an option to manually set the @XmlElement type or have it ignored? 有没有人知道是否有手动设置@XmlElement类型或忽略它的选项?

Here is the relevant portion of the jaxb-bindings.xml file: 这是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>

UPDATE UPDATE

summarizing: 总结:

  1. you have a schema that uses date style somewhere, and you cannot change the schema 您有一个在某处使用日期样式的架构,并且您无法更改架构
  2. you have some XML data that uses that schema and specify some date with timezone (so it's yyyy-MM-ddXXX format) 你有一些XML数据使用该模式并指定一些日期与时区(所以它是yyyy-MM-ddXXX格式)
  3. you want to remove the XXX part from the representation of the date in that file (date itself does not ship any timezone, date is just a number) 你想从该文件中的日期表示中删除XXX部分(日期本身不发送任何时区,日期只是一个数字)

so this could be a sample schema: 所以这可能是一个示例模式:

<?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>

this could be a sample data: 这可能是一个示例数据:

<?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>

this is JAXB annotated class 这是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
}

this is date adapter 这是日期适配器

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);
    }
}

this is the main, validating against the schema: 这是主要的,验证模式:

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);
}

and this is the output, timezone has been removed and date representation has obviously changed 这是输出,时区已被删除,日期表示已明显改变

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>

maybe this date representation change is not what you'd expect, but this is not a JAXB concern, the date represented has not changed. 也许这个日期表示更改不是您所期望的,但这不是JAXB关注的问题,所代表的日期没有改变。

i was forgetting the bindings to reverse generate Foo: 我忘了绑定反向生成Foo:

<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>

END OF UPDATE 更新结束


sorry, too long for a comment... 对不起,评论太久了......

i can't understand: 我无法理解:

  1. why the hell are you using XmlGregorianCalendar ? 为什么你在使用XmlGregorianCalendar
  2. why should you marshal / unmarshal ( serialize / deserialize ) to the very same data structure? 为什么要marshal / unmarshalserialize / deserialize serialize )到完全相同的数据结构?
  3. why should you remove timezone?? 为什么要删除时区?

and

  1. i use straight and simple java.util.Date 我使用直接和简单的java.util.Date
  2. marshal / unmarshal should always involve String s (at least for XML) marshal / unmarshal应该总是涉及String (至少对于XML)
  3. i really don' see a good reason to arbitrarily remove a piece of a date representation. 我真的没有理由任意删除一个日期表示。 maybe you want to serialize it in an absolute way. 也许你想以绝对的方式序列化它。

however 然而

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
    }
}

You have to specify the java type differently, in your case: 在您的情况下,您必须以不同的方式指定java类型:

<jxb:javaType 
     name="javax.xml.datatype.XMLGregorianCalendar" 
     xmlType="xs:date"  
     printMethod="foo.bar.TimezoneRemoverAdapter.marshall" 
     parseMethod="foo.bar.TimezoneRemoverAdapter.unmarshall" 
/>

It works fine for me and I did something similar with more adapters: 它适用于我,我做了类似的更多适配器:

<jaxb:globalBindings>    
     <xjc:serializable uid="12343" />
     <jaxb:javaType name="java.util.Date" xmlType="xs:date" printMethod="com.foo.DateAdapter.printDate" parseMethod="com.foo.DateAdapter.parseDate" />
     <jaxb:javaType name="java.util.Date" xmlType="xs:dateTime" printMethod="com.foo.DateAdapter.printDate" parseMethod="com.foo.DateAdapter.parseDate" />
     <jaxb:javaType name="java.util.Date" xmlType="xs:time" printMethod="com.foo.TimeAdapter.printTime" parseMethod="com.foo.TimeAdapter.parseTime" />
</jaxb:globalBindings>

I put the above bindings as a globalBindings in a different file with .xjb extension and I use it everywhere I need it. 我把上面的绑定作为globalBindings在不同的文件.xjb扩展,我用它无处不在,我需要它。

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

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