Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does JAXB need a no arg constructor for marshalling?

If you try to marshal a class which references a complex type that does not have a no-arg constructor, such as:

import java.sql.Date;  @XmlRootElement(name = "Foo") @XmlAccessorType(XmlAccessType.FIELD) public class Foo {     int i;     Date d; //java.sql.Date does not have a no-arg constructor } 

with the JAXB implementation that is part of Java, as follows:

    Foo foo = new Foo();     JAXBContext jc = JAXBContext.newInstance(Foo.class);     ByteArrayOutputStream baos = new ByteArrayOutputStream();     Marshaller marshaller = jc.createMarshaller();     marshaller.marshal(foo, baos); 

JAXB will throw a

com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions java.sql.Date does not have a no-arg default constructor 

Now, I understand why JAXB needs a no-arg constructor on unmarshalling - because it needs to instantiate the object. But why does JAXB need a no-arg constructor while marshalling?

Also, another nit, why does Java's JAXB implementation throw an exception if the field is null, and isn't going to be marshalled anyway?

Am I missing something or are these just bad implementation choices in Java's JAXB implementation?

like image 427
rouble Avatar asked Feb 13 '12 21:02

rouble


People also ask

How does JAXB marshalling work?

In JAXB, marshalling involves parsing an XML content object tree and writing out an XML document that is an accurate representation of the original XML document, and is valid with respect the source schema. JAXB can marshal XML data to XML documents, SAX content handlers, and DOM nodes.

What is JAXB marshalling?

JAXB stands for Java Architecture for XML Binding. It provides mechanism to marshal (write) java objects into XML and unmarshal (read) XML into object. Simply, you can say it is used to convert java object into xml and vice-versa.

Is JAXB Marshaller thread safe?

A: The JAXB Specification currently does not address the thread safety of any of the runtime classes. In the case of the Oracle JAXB RI, the JAXBContext class is thread safe, but the Marshaller , Unmarshaller , and Validator classes are not thread safe.


1 Answers

When a JAXB (JSR-222) implementation initializes its metadata it ensures that it can support both marshalling and unmarshalling.

For POJO classes that do not have a no-arg constructor you can use a type level XmlAdapter to handle it:

  • http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html

java.sql.Date is not supported by default (although in EclipseLink JAXB (MOXy) it is). This can also be handled using an XmlAdapter specified via @XmlJavaTypeAdapter at field, property, or package level:

  • http://blog.bdoughan.com/2011/05/jaxb-and-joda-time-dates-and-times.html
  • http://blog.bdoughan.com/2011/01/jaxb-and-datetime-properties.html

Also, another nit, why does Java's JAXB implementation throw an exception if the field is null, and isn't going to be marshalled anyway?

What exception are you seeing? Normally when a field is null it is not included in the XML result, unless it is annotated with @XmlElement(nillable=true) in which case the element will include xsi:nil="true".


UPDATE

You could do the following:

SqlDateAdapter

Below is an XmlAdapter that will convert from the java.sql.Date that your JAXB implementation doesn't know how to handle to a java.util.Date which it does:

package forum9268074;  import javax.xml.bind.annotation.adapters.*;  public class SqlDateAdapter extends XmlAdapter<java.util.Date, java.sql.Date> {      @Override     public java.util.Date marshal(java.sql.Date sqlDate) throws Exception {         if(null == sqlDate) {             return null;         }         return new java.util.Date(sqlDate.getTime());     }      @Override     public java.sql.Date unmarshal(java.util.Date utilDate) throws Exception {         if(null == utilDate) {             return null;         }         return new java.sql.Date(utilDate.getTime());     }  } 

Foo

The XmlAdapter is registered via the @XmlJavaTypeAdapter annotation:

package forum9268074;  import java.sql.Date; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;  @XmlRootElement(name = "Foo") @XmlAccessorType(XmlAccessType.FIELD) public class Foo {     int i;      @XmlJavaTypeAdapter(SqlDateAdapter.class)     Date d; //java.sql.Date does not have a no-arg constructor } 
like image 159
bdoughan Avatar answered Oct 09 '22 04:10

bdoughan