JAXB Bindings File Sets @XmlElement type to String instead of XMLGregorianCalendar JAXB Bindings File Sets @XmlElement type to String instead of XMLGregorianCalendar xml xml

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


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

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

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

i was forgetting the bindings to reverse generate 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?
  2. why should you marshal/unmarshal (serialize/deserialize) to the very same data structure?
  3. why should you remove timezone??

and

  1. i use straight and simple java.util.Date
  2. marshal/unmarshal should always involve Strings (at least for 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:

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