October 6, 2010

How Does JAXB Compare to XStream?

The XStream FAQ states the following when being compared to JAXB:

JAXB is a Java binding tool. It generates Java code from a schema and you are able to transform from those classes into XML matching the processed schema and back. Note, that you cannot use your own objects, you have to use what is generated.
In this post I will provide an alternative answer to that question.


Java Model

We will use the following model for this example.  The classes represent customer data.  The get/set methods have been omitted to save space.

Customer
package comparison;

import java.util.ArrayList;
import java.util.List;

public class Customer {

    private long id;
    private String name;
    private Address address;
    private List<phonenumber> phoneNumbers;

    public Customer() {
        phoneNumbers = new ArrayList<PhoneNumber>();
    }

}

Address
package comparison;

public class Address {

    private String city;
    private String street;

}

PhoneNumber
package comparison;

public class PhoneNumber {

    private String type;
    private String number;

}

Customer Data

The following instance of Customer will be marshalled to XML using both JAXB and XStream.

package comparison;

public class Data {

    public static Customer CUSTOMER;

    static {
        CUSTOMER = new Customer();
        CUSTOMER.setId(123);
        CUSTOMER.setName("Jane Doe");

        Address address = new Address();
        address.setStreet("1 A Street");
        address.setCity("Any Town");
        CUSTOMER.setAddress(address);

        PhoneNumber workPhoneNumber = new PhoneNumber();
        workPhoneNumber.setType("work");
        workPhoneNumber.setNumber("555-WORK");
        CUSTOMER.getPhoneNumbers().add(workPhoneNumber);

        PhoneNumber cellPhoneNumber = new PhoneNumber();
        cellPhoneNumber.setType("cell");
        cellPhoneNumber.setNumber("555-CELL");
        CUSTOMER.getPhoneNumbers().add(cellPhoneNumber);
    }

}

Marshal Code

This is the code we will use to convert the objects to XML.

XStream

The following code will be used to marshal the instance of Customer to an OutputStream.  The XStream code is quite compact.

package comparison.xstream;

import com.thoughtworks.xstream.XStream;

import static comparison.Data.CUSTOMER;

public class XStreamDemo {

    public static void main(String[] args) {
        XStream xstream = new XStream();
        xstream.autodetectAnnotations(true);
        xstream.toXML(CUSTOMER, System.out);
    }
}

JAXB

The following code will be used to marshal the instance of Customer to an OutputStream.  A couple of differences are already apparent:
  1. A JAXBContext needs to be initialized on the binding metadata before the marshal operation can occur.
  2. Unlike XStream JAXB does not format the XML by default, so we will enable this feature.
  3. With no metadata specified we need to supply JAXB with a root element name (and namespace).
package comparison.jaxb;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import comparison.Customer;

import static comparison.Data.CUSTOMER;

public class JAXBDemo {

    public static void main(String[] args) throws Exception {

        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        JAXBElement<Customer> jaxbElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, CUSTOMER);
        marshaller.marshal(jaxbElement, System.out);
    }
}

Default XML Output

First we will examine the XML output produced by both XStream and JAXB if no metadata is used to customize the output.

XStream

XStream will produce the following XML.  Note some of the elements are named after the fully qualified class name.
<comparison.Customer>
    <id>123</id>
    <name>Jane Doe</name>
    <address>
        <city>Any Town</city>
        <street>1 A Street</street>
    </address>
    <phoneNumbers>
        <comparison.PhoneNumber>
            <type>work</type>
            <number>555-WORK</number>
        </comparison.PhoneNumber>
        <comparison.PhoneNumber>
            <type>cell</type>
            <number>555-CELL</number>
        </comparison.PhoneNumber>
    </phoneNumbers>
</comparison.Customer>

JAXB

JAXB produces the following XML.  The representation is straight forward and more compact than the XStream representation.

<customer>
    <id>123</id>
    <address>
        <city>Any Town</city>
        <street>1 A Street</street>
    </address>
    <name>Jane Doe</name>
    <phoneNumbers>
        <number>555-WORK</number>
        <type>work</type>
    </phoneNumbers>
    <phoneNumbers>
        <number>555-CELL</number>
        <type>cell</type>
    </phoneNumbers>
</customer>

Field Access

For this example we will configure our XML binding tools to interact directly with the fields (instance variables).

XStream

XStream uses field access by default.

JAXB

By default JAXB will access public fields and properties.  We can configure JAXB to use field access with the following package level annotation:

@XmlAccessorType(XmlAccessType.FIELD)
package comparison;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

Renaming Elements

Next we will look at how to tweak the XML output using the appropriate mapping metadata.  First we will rename some elements.  As you will see the amount of configuration required is almost identical.

XStream

For XStream we will use @XStreamAlias to configure the root element, and @XStreamImplicit to configure the phoneNumbers property.

import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

@XStreamAlias("customer")
public class Customer {

    private long id;
    private String name;
    private Address address;

    @XStreamImplicit(itemFieldName="phone-number")
    private List<PhoneNumber> phoneNumbers;

    public Customer() {
        phoneNumbers = new ArrayList<PhoneNumber>();
    }

}

JAXB

For JAXB we will use @XmlRootElement to configure the root element, and @XmlElement to configure the phoneNumbers property.
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Customer {

    private long id;
    private String name;
    private Address address;

    @XmlElement(name="phone-number")
    private List<PhoneNumber> phoneNumbers;

    public Customer() {
        phoneNumbers = new ArrayList<PhoneNumber>();
    }

}

Note:  The JAXB Marshal code can now be simplified since we no longer need to supply the root element information:

package comparison.jaxb;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import comparison.Customer;

import static comparison.Data.CUSTOMER;

public class JAXBDemo {

    public static void main(String[] args) throws Exception {

        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(CUSTOMER, System.out);
    }
}

XML Output

At this point the same XML is being produced by XStream and JAXB.

<customer>
    <id>123</id>
    <name>Jane Doe</name>
    <address>
        <city>Any Town</city>
        <street>1 A Street</street>
    </address>
    <phone-number>
        <type>work</type>
        <number>555-WORK</number>
    </phone-number>
    <phone-number>
        <type>cell</type>
        <number>555-CELL</number>
    </phone-number>
</customer>

Change the Order of Elements

We will tweak the document again to make sure that when marshalling an Address object the "street" element will always appear before the "city" element.

XStream

For XStream we will need to change our marshal code.  The following is based on instructions given in the XStream FAQ:

package comparison.xstream;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.reflection.FieldDictionary;
import com.thoughtworks.xstream.converters.reflection.SortableFieldKeySorter;
import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;

import comparison.Address;

import static comparison.Data.CUSTOMER;

public class XStreamDemo {

    public static void main(String[] args) {
        SortableFieldKeySorter sorter = new SortableFieldKeySorter();
        sorter.registerFieldOrder(Address.class, new String[] { "street", "city"});
        FieldDictionary fieldDictionary = new FieldDictionary(sorter);
        Sun14ReflectionProvider reflectionProvider = new Sun14ReflectionProvider(fieldDictionary);

        XStream xstream = new XStream(reflectionProvider);

        xstream.autodetectAnnotations(true);

        xstream.toXML(CUSTOMER, System.out);
    }

}

JAXB

For JAXB we can configure the ordering of elements right on the model class.  We will use @XmlType to do this.

package comparison;

import javax.xml.bind.annotation.XmlType;

@XmlType(propOrder={"street", "city"})
public class Address {

    private String city;
    private String street;

}

XML Output

The XML output is the same for both JAXB and XStream.
<customer>
    <id>123</id>
    <name>Jane Doe</name>
    <address>
        <street>1 A Street</street>
        <city>Any Town</city>
    </address>
    <phone-number>
        <type>work</type>
        <number>555-WORK</number>
    </phone-number>
    <phone-number>
        <type>cell</type>
        <number>555-CELL</number>
    </phone-number>
</customer>

Mapping to an Attribute

Now we will look at how to tweak the XML output using the appropriate mapping metadata to produce XML attributes.  As you will see the amount of configuration required is almost identical.

XStream

For XStream we will use @XStreamAsAttribute to configure the id property to be represented as an XML attribute.

package comparison;

import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

@XStreamAlias("customer")
public class Customer {

    @XStreamAsAttribute
    private long id;

    private String name;
    private Address address;

    @XStreamImplicit(itemFieldName="phone-number")
    private List<PhoneNumber> phoneNumbers;

    public Customer() {
        phoneNumbers = new ArrayList<PhoneNumber>();
    }

}

JAXB

For JAXB we will use @XmlAttribute to configure the id property to be represented as an XML attribute.
package comparison;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Customer {

    @XmlAttribute
    private long id;

    private String name;
    private Address address;

    @XmlElement(name="phone-number")
    private List<PhoneNumber> phoneNumbers;

    public Customer() {
        phoneNumbers = new ArrayList<PhoneNumber>();
    }

}

XML Output

The XML output is the same for both JAXB and XStream.
<customer id="123">
    <name>Jane Doe</name>
    <address>
        <city>Any Town</city>
        <street>1 A Street</street>
    </address>
    <phone-number>
        <type>work</type>
        <number>555-WORK</number>
    </phone-number>
    <phone-number>
        <type>cell</type>
        <number>555-CELL</number>
    </phone-number>
</customer>

Mapping Objects to Simple Content

To compact our document even further we will map the PhoneNumber class to a complex type with simple content.

XStream

With XStream we can do this using a converter.  Examples of creating converters can be found on the XStream website:
We can reference the converter on the phoneNumbers property using @XStreamConverter.

package comparison;

import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

@XStreamAlias("customer")
public class Customer {

    @XmlAttribute
    private long id;

    private String name;
    private Address address;

    @XStreamImplicit(itemFieldName="phone-number")
    @XStreamConverter(PhoneNumberConverter.class)
    private List<PhoneNumber> phoneNumbers;

    public Customer() {
        phoneNumbers = new ArrayList<PhoneNumber>();
    }

}

The converter can be implemented as follows:

package comparison;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class PhoneNumberConverter implements Converter {

    public boolean canConvert(Class clazz) {
        return PhoneNumber.class == clazz;
    }

    public void marshal(Object object, HierarchicalStreamWriter hsw, MarshallingContext mc) {
        PhoneNumber phoneNumber = (PhoneNumber) object;
        hsw.addAttribute("type", phoneNumber.getType());
        hsw.setValue(phoneNumber.getNumber());
    }

    public Object unmarshal(HierarchicalStreamReader hsr, UnmarshallingContext uc) {
        PhoneNumber phoneNumber = new PhoneNumber();
        phoneNumber.setType(hsr.getAttribute("type"));
        phoneNumber.setNumber(hsr.getValue());
        return phoneNumber;
    }

}

JAXB

For JAXB we will use the @XmlAttribute and @XmlValue annotations on the PhoneNumber class.

package comparison;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlValue;

public class PhoneNumber {

    @XmlAttribute
    private String type;

    @XmlValue
    private String number;

}

XML Output:

The XML output is the same for both JAXB and XStream.

<customer id="123">
    <name>Jane Doe</name>
    <address>
        <street>1 A Street</street>
        <city>Any Town</city>
    </address>
    <phone-number type="work">555-WORK</phone-number>
    <phone-number type="cell">555-CELL</phone-number>
</customer>

Applying Namespaces

We will now namespace qualify the XML document.

XStream

Namespace support in XStream appears to be limited to the StaxDriver.  For more information see:
package comparison.xstream;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.reflection.FieldDictionary;
import com.thoughtworks.xstream.converters.reflection.SortableFieldKeySorter;
import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;
import com.thoughtworks.xstream.io.xml.QNameMap;
import com.thoughtworks.xstream.io.xml.StaxDriver;

import comparison.Address;

import static comparison.Data.CUSTOMER;

public class XStreamDemo {

    public static void main(String[] args) {
        QNameMap nsm = new QNameMap();
        nsm.setDefaultNamespace("http://www.example.com");
        StaxDriver staxDriver = new StaxDriver(nsm);

        SortableFieldKeySorter sorter = new SortableFieldKeySorter();
        sorter.registerFieldOrder(Address.class, new String[] { "street", "city"});
        FieldDictionary fieldDictionary = new FieldDictionary(sorter);
        Sun14ReflectionProvider reflectionProvider = new Sun14ReflectionProvider(fieldDictionary);

        XStream xstream = new XStream(reflectionProvider, staxDriver);

        xstream.autodetectAnnotations(true);

        xstream.toXML(CUSTOMER, System.out);
    }

}

Note: With this change I lost XML formatting, the following was produced.

<customer xmlns="http://www.example.com" id="123"><name>Jane Doe</name><address><street>1 A Street</street><city>Any Town</city></address><phone-number type="work">555-WORK</phone-number><phone-number type="cell">555-CELL</phone-number></customer>
 

JAXB

We can configure the namespace information using the @XmlSchema package level annotation:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlSchema(namespace="http://www.example.com", 
           elementFormDefault=XmlNsForm.QUALIFIED)
package comparison;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

The following XML was produced

<customer xmlns="http://www.example.com" id="123">
    <name>Jane Doe</name>
    <address>
        <street>1 A Street</street>
        <city>Any Town</city>
    </address>
    <phone-number type="work">555-WORK</phone-number>
    <phone-number type="cell">555-CELL</phone-number>
</customer>
Summary

As can be seen from this example JAXB compares very well to XStream.

57 comments:

  1. Blaise,

    thanks for this comprehensive summary, really great.

    One addition where I personally found JAXB to be superior to xstream is when you apply model transformations (as opposed to simple type conversions).

    I think that JAXB's XmlAdapter is much simpler to deal with than xstream's custom mappers. I often see XSLT being used with xstream instead, but than you're using an additional language (and one which many java developers find cumbersome).

    Thanks again,
    Wolfgang

    ReplyDelete
  2. Wolfgang,

    I agree on XmlAdapter, it is my favourite JAXB feature. It was actually the topic of my first blog post XmlAdapter - JAXB's Secret Weapon.

    -Blaise

    ReplyDelete
  3. Excellent post, also note that JAXB now comes bundled on JDK, so the use of XStream gets a bit unneeded if the xml to be marshaled/unmarshaled are simple enough

    ReplyDelete
  4. sombriks,

    In this example JAXB handled the XML better than XStream. This was especially true WRT namespace handling. For more information on JAXB's namespace support see:

    - JAXB & Namespaces

    XStream does have the converter concept, but JAXB has the much more powerful XmlAdapter feature:

    - XmlAdapter - JAXB's Secret Weapon

    Plus since JAXB is a spec, individual implementations can offer their own extensions such as MOXy's XPath based mapping:

    - XPath Based Mapping
    - XPath Based Mapping - Geocode Example

    JAXB is not only a standard part of Java SE 6, but the default binding layer for two Java EE Web Service standards JAX-WS & JAX-RS. JAXB is the enterprise Java binding layer.

    -Blaise

    ReplyDelete
  5. Blaise,

    I guess the XStream FAQ primarily just needs an update for JAXB 2.0 ;-)

    My experience with XStream is that it's great for serializing/deserializing arbitrary object graphs, but it's very hard to make the xml comply to some given schema. JAXB is at times more heavy-weight, but much more powerful as well.

    But both by 95% serve the same purpose. I even started a little adapter class that uses XStream as an JAXB implementation... it's yet not much more than a proof of concept, though:

    https://messageapi.dev.java.net/source/browse/messageapi/trunk/adapter/src/main/java/com/oneandone/consumer/messageapi/xstream

    One thing that annoys me, though, is that the JDK "reference implementation" does not seem to comply to the standard paragraph 8.5.4, which says that Maps have to be supported. MOXy does, but the RI does not... or am I getting something wrong?


    -Rüdiger

    ReplyDelete
  6. Rüdiger,

    The XStream FAQ definitely needs to be updated for JAXB 2.0 :).

    To be fair XStream has times when it is more heavy weight. This can be seen in this post:
    - A field dictionary had to be created to control the order of elements.
    - A converter need to be created to map an object to simple content.
    - The driver had to be changed to apply namespaces.

    WRT 95%:
    - XStream cannot generate classes from XML Schema. There FAQ recommends using XMLBeans for this purpose.
    - XStream cannot generate an XML schema from Java classes
    - XStream is not a Web Service binding layer.
    - XStream does not cover 100% of XML schema concepts.
    - XStream cannot preserve the XML infoset.

    Section 8.5.4 of the JAXB spec clearly states that java.util.Map (and its subtypes) must be supported. This is probably a bug in the reference implementation, you can report this here:
    - https://jaxb.dev.java.net/issues/

    Don't forgot that JAXB implementations are free to go beyond the specification. Below are some of the EclipseLink MOXy extensions:
    - XPath base mapping
    - XML metadata file
    - JPA entity mapping support

    -Blaise

    ReplyDelete
  7. It looks like XStream can map inheritance better than JAXB.

    http://www.natpryce.com/articles/000766.html

    Can JAXB do the same?

    ReplyDelete
  8. Andrew,

    I read the article "Mapping Inheritance Cleanly with XStream", and it demonstrates how to write a converter to represent multiple classes as the same XML element. The JAXB equivalent would be to write an XmlAdapter.

    - XmlAdapter - JAXB's Secret Weapon

    The following posts demonstrate how to easily represent object inheritance in JAXB by leveraging existing XML schema concepts:

    - JAXB and Inheritance - Using the xsi:type Attribute
    - JAXB and Inheritance - Using Substitution Groups

    -Blaise

    ReplyDelete
  9. Nice post. I was really happy with XStream, but JAXB looks cool for those cases also.
    By the way, int the XML output, in XStram you can "map" the qualified name to an alias: xstream.alias("customer", Customer.class);

    ReplyDelete
  10. Nice post. I too was under the impression that to use JAXB, you needed to start out with a schema, generate the java classes, etc. Was this ever the case? Either way, the tutorial you just went through needs to be front and center on Oracle's JAXB main page. It's great to know that JAXB can handle the hard stuff, but it's more important to get the word out how easy it is to use JAXB for the easy stuff. I mean, come on, one of the alternate libraries was probably named "Simple" for a reason. :)

    ReplyDelete
  11. Thanks Ken,

    JAXB 1 required that you start with an XML schema and generate standard interfaces backed by vendor specific implementation classes.

    JAXB 2 moved to POJOs with standard annotations, making the classes portable between JAXB implementations. But somehow the stigma still persisted. It could be because JAXB still offers a schema to Java compiler to generate classes from an XML schema as a convenience mechanism.

    I have also writted a post comparing Simple and JAXB. For that example they are both easy to use. The difference is in all the extra feaures that JAXB implementations (Metro, MOXy, JaxMe, etc) have:

    - http://bdoughan.blogspot.com/2010/10/how-does-jaxb-compare-to-simple.html

    -Blaise

    ReplyDelete
  12. Blaise,
    This is a very informative blog. I'm trying to decide between XStream and JAXB. It was useful to see that you don't have to use an XML schema with JAXB. I'm not a fan of annotations. I just don't like to pollute my code with it. Personal taste...

    You can configure XStream to do your second example by registering aliases. Can this be done in JAXB without annotations? Also, can the examples in JAXB be done without using annotations? Are they required?

    ReplyDelete
  13. Hi Manuel,

    JAXB as defined in the specification (JSR-222) requires annotations. However individual implementations may offer extensions to this.

    EclipseLink MOXy (I'm the tech lead)

    We offer an XML representation of the metadata. An example of it can be seen here:

    - Extending JAXB - Representing Metadata as XML

    Metro JAXB (The reference implementation)

    Can leverage Annox and JAXBIntroductions to get an XML representation of the metadata. With a few lines of code MOXy can also be adapted to work with these formats.

    - http://jaxb.java.net/

    Other JAXB implementations such as JaxMe may address the use case in other ways.

    One of the advantages of JAXB is that it is a standard with multiple implementations. This avoids the vendor lockin you get with a library like XStream.

    -Blaise

    ReplyDelete
  14. Interesting post. I am after XML serialization/deserialization of Java object tree. Is there a way to do this using JAXB without tinkering with XmlAdapter or explicit mappings?

    ReplyDelete
  15. Blaise,

    Excellent post!

    I wonder if you can recommend an approach for handling evoloving classes. Class A, version1 is used at first. Then some of the clients update to Class A version2 (which introduces a new field). But other clients do not upgrade yet. They have the Class A version1 on their classpath. They should be able to read the xml representation of Class A version2 (by just ignoring the new field).

    What's the best way to accomplish that? Can JAXB 'ignore' fields if the class does not have them? Can XStream? I saw that XMT can be used to read version1 with version2 code. But I'm talking about reading version2 with version1 code.

    Any help would be great.

    ReplyDelete
  16. Hi Alex,

    JAXB can be used to marshal an object to XML without the use of any metadata. JAXB metadata only needs to be supplied to override the default behavior. For an example see:

    - http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted/TheBasics

    -Blaise

    ReplyDelete
  17. Hi Anonymous,

    Regarding evolving classes, JAXB handles this case easily. When JAXB finds an element/attribute it does not recognize it is simply ignored.

    From the XStream FAQ if XStream finds an element/attribute it does not recognize an exception is thrown:

    "If a field is removed from the class, deserializing an old version that contains that field will cause an exception."

    -Blaise

    ReplyDelete
  18. Hmm, I looked at it some time ago, but at the time Java 6 bundled jaxb could not do the following:
    - If an object tree I serialize/deserialize has fields of interface types JAXB would not do it OOB
    - If a field is declared as base class, but is assigned a subclass jaxb marshall/unmarshall looses this
    - If I have multiple fields in the object tree that point to the same object instance, after jaxb unmarshalling they will become two independent instances.
    - Java proxy serialization another issue

    Is there an easy way to address all this without creating adapters?

    ReplyDelete
  19. Hi Alex,

    The JAXB specification does not define behavior for interfaces, but this is handled in EclipseLink JAXB (MOXy):

    - MOXy JAXB - Map Interfaces to XML

    JAXB does support inheritance. You need to ensure that the JAXBContext is aware of the subclasses:

    - JAXB and Inheritance - Using the xsi:type Attribute
    - JAXB and Inheritance - Using Substitution Groups

    To handle shared references you do need to supply JAXB metadata to handle this:

    - JAXB and Shared References: @XmlID and @XmlIDREF

    For proxy serialization, refer to the post about mapping to interfaces.

    -Blaise

    ReplyDelete
  20. Hi, what about performance comparison?

    ReplyDelete
  21. Hi byF,

    I do not have a performance comparison for JAXB and XStream. JAXB should be faster since if offers and initialization stage where the metadata can be optimized before unmarshalling/marshalling is done.

    -Blaise

    ReplyDelete
  22. Hi, Blaise,

    Have you used Jaxb in a OSGI/bundle environment? Do you know if it is supported on Felix?

    I am facing a weird problem where the same code executes fine in a standalone java project, but complains that it does not see @XmlRootElement when this code runs in a bundle (in Felix) when it really is there.

    Thanks in advance!

    ReplyDelete
  23. Hi Xianguan,

    Most of the work I have done with JAXB and OSGi has been with Equinox.

    In your manifest you will need to ensure that you are importing all the JAXB packages. You will also need to ensure that JAXB is available as a bundle. GlassFish provides one, and one is available in EclipseLink.

    EclipseLink JAXB (MOXy) is also available as an OSGi bundle and can be obtained from the download site:

    - http://www.eclipse.org/eclipselink/downloads/

    -Blaise

    ReplyDelete
  24. thanks for the answer, Blaise. Really appreciate it.

    ReplyDelete
  25. Does Xstream support multiple namespaces...??
    We can always set QnameMap.setDefaultNamespace() to set a default namesapce for the entire xml..but vat if I have to use more than one namespace in the same xml?

    ReplyDelete
  26. For specifics on how/if XStream handles multiple namespaces you will need to contact someone on that project.

    JAXB implementations (Metro, EclipseLink MOXy, Apache JaxMe) have an elegant solution for this:
    - JAXB & Namespaces

    -Blaise

    ReplyDelete
  27. Hi there - Great information. WIth respect to speed, in my own testing I've seen JAXB outperform XStream on the order of 5 to 1. I'd be interested how it shook out with other peoples' use cases.

    ReplyDelete
  28. BlaZe, you are the man. This page helped me tremendously decide between JAXB and XStream. It has so much useful information (annotations esp.). I could totally build my marshalling strategy without creating any XSD etc...beautiful.

    ReplyDelete
  29. Hi Amit,

    I hope that means you chose JAXB :).

    -Blaise

    ReplyDelete
  30. Hello Blaise
    Please, as I implement the @xmlInverseReference of JAXB in XStream ?

    Thanks

    ReplyDelete
  31. Hi Odete,

    I am not aware if XStream has an equivalent of @XmlInverseReference. I'm the EclipseLink JAXB (MOXy) lead, and am more than happy to help you with MOXy (or any JAXB implementation), but I can't spend any cycles helping with XStream.

    -Blaise

    ReplyDelete
  32. Hello Blaise,

    Is there any possibility in JAXB to marshall all Object of a given ClassZ (e.g. the Date or a CustomClass) depending on some dynamic data (e.g date format, which changes for each object instance)?

    With @XmlAdapter I will have to annotate all properties of type ClassZ with @XmlAdapter and constructing and adapter supposes other 2(or 3) classes.

    ReplyDelete
  33. The following may help:

    1. You can use the @XmlSchemaType at the field/property level to specify the XML representation of data:
    - JAXB and Date/Time Properties

    2. You can register an XmlAdapter for all classes of a particular type at the package level:
    - JAXB and Joda-Time: Dates and Times

    3. You can set initialized instances of XmlAdapter on Marshaller and Unmarshaller. The following answer I gave to a question on Stack Overflow demonstrates this concept in action:
    - http://stackoverflow.com/questions/7278406/serialize-a-jaxb-object-via-its-id/7285517#7285517

    -Blaise

    ReplyDelete
  34. Blaise,

    I have been using JAXB (in a Jersey Restful application) and so far I have been quite happy ! I just have this new requirement come up where I need to convert a List of HashMaps to xml. Each map contains a key value pairs of a database row (so for example the list will have 2 hashmaps for 2 rows {{FNAME=John, LNAME=Smith, AGE=35},{firstName=Mary, lastName=Maria, age=45}}.

    I have written a MapAdapter based on your post http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html but I don't quite like the xml I get. I get this


    JOHN
    35
    SMITH


    MARY
    45
    MARIA


    but I would like this instead


    ALEX
    42
    TRUMP

    ...
    ....

    I haven't been able to do that in JAXB but I have been able to with XStream custom converters!!!! But for just this one case, I don't want to start XSTream as well. Can I achieve the desired result with JAXB ?

    ReplyDelete
    Replies
    1. Hi,

      It appears as though your XML samples did not survive the formatting restrictions of the comment section. Would you mind sending me the details through my contact page?
      - http://blog.bdoughan.com/p/contact_01.html

      -Blaise

      Delete
  35. Hi Blaise,

    Excellent blog!! Your blogs have been quite informative and helpful!!

    Is there a way to suppress certain field names in JAXB or Moxy? Comparable to what XStream's addImplicitCollection achieves?

    Thanks!

    ReplyDelete
    Replies
    1. Hi,

      I'm happy to hear you are enjoying the blog and are finding it useful.

      XStream will include a wrapper element for the collection and then you can use addImplicitCollection to remove it. JAXB (JSR-222) implementations by default do not add a wrapper element unless you use @XmlElementWrapper:
      - JAXB & Collection Properties

      Also if there is a property you want to be excluded from the XML representation you can use @XmlTransient, or you can use @XmlAccessorType(XmlAccessType.NONE) so that only explicitly annotated properties are converted to/from XML:
      - Using JAXB's @XmlAccessorType to Configure Field or Property Access

      -Blaise

      Delete
  36. Hi Blaise,
    This is really good blog with examples.

    I would like save/retrieve some user defined objects into a file.
    I don't know really which one should I use?
    I initially thought of using XMLEncoder and XMLDecoder. I heard that it is not thread safe and it doesn't support some types like Enum etc.

    I am looking at JAXB, Is JAXB heavy for this?
    Are there any less weight solutions for this requirement.

    ReplyDelete
    Replies
    1. JAXB is not a "heavy weight" solution. An implementation is included in the JRE starting with Java SE 6. JAXB is configuration by exception meaning you only need to add annotations to your domain model where you want to override the default mapping behaviour.

      -Blaise

      Delete
  37. Hi Blaise,

    Nice article.

    Any thoughts on using Jibx instead of JAXB?

    My requirement is simple to create the XML from POJO and reverse i.e. POJO from XML.

    What would we your suggestion for this?

    Tahnks
    AC

    ReplyDelete
    Replies
    1. Hi AC,

      I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group, so I won't even pretend to be impartial wrt that question.

      JAXB is the standard for XML binding with multiple open source implementations. Because it is the standard an implementation has been included in Java SE 6. It is the standard binding layer for JAX-WS (SOAP based services) and JAX-RS (RESTful services) meaning JAXB will work in any Java EE application server (WebLogic, GlassFish, WebSphere, JBoss, etc).

      There are risks with using proprietary XML binding solutions in that you don't know when they will disappear. XStream for example didn't have a release between December 2008 and August 2011. And XMLBeans hasn't had a release since December 2009. JAXB is part of Java and will continue to evolve along with it.

      You may want to check out the following question on Quora:
      - What, if any, are the advantages of JiBX over JAXB?

      -Blaise

      Delete
  38. Nice article.

    After reading your article and some other article I am more incline toward the JAXB compare to other XML Binding technology available.

    JAXB can be used for both Marshalling and Unmarshalling, Correct?

    Can we use your approach mentioned above if we directly want to start from POJO to create XML?

    Thanks
    Jha

    ReplyDelete
    Replies
    1. Hi Jha,

      Yes JAXB (JSR-222) can be used for both Marshalling (object-to-XML), and unmarshalling (XML-to-object). You can definitely start with POJO and create XML. You might find the following tutorial helpful:
      - http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted

      -Blaise

      Delete
    2. Hi Blaise,

      Any thoughts on Performance of JAXB? What I mean is, Is it OK to use in J2EE app?
      Any issue with MultiThreading? I read somewhere that JAXBContext class is thread safe and Marshal/Unmarshal classes or not?
      I know there shouldn't be any issue as it's build for keeping WebServices in mind but just wanted to know your opinion.
      What is your thought on this?

      Thanks
      Jha

      Delete
    3. Hi Jha,

      JAXB (JSR-222) is the default binding layer for both JAX-WS (SOAP) and JAX-RS (RESTful) Web Services. This means that a JAXB implementation is included with every Java EE application server and is used by countless Java EE applications.
      - EclipseLink MOXy is the JAXB Provider in WebLogic Server 12c
      - Creating a RESTful Web Service - Part 1/5

      JAXBContext is thread safe and can be shared, Marshaller/Unmarshaller and not thread safe (but are light-weight). When JAXB is used in a JAX-WS or JAX-RS application all this management is done for you.

      -Blaise

      Delete
  39. Hi Blaise,

    Thanks for your reply.

    Depending upon structure of XML, Do I need to create the Classes also?

    Also, Is it possible in JAxb to create the dynamic Element? For example










    Rest all the tag has the name based on what you define in POJO attribute. What about if the tag name it self is dynamic?

    Thanks
    Jha

    ReplyDelete
    Replies
    1. Hi Jha,

      Some content was lost from your comment due to the limitations of the comment section. Feel free to send me a message through my "Contact Me" link at the top of this page.

      -Blaise

      Delete
  40. I like JAXB in that it's mature, well-documented, and fast. It's lack of support for immutable objects (no final, default ctor required) and required getters/setters make it far more verbose than XStream for every case I've run across. I wish it wasn't so, I find XStream very slow. But, XStream lets my code be my code, no need to mutate it to fit a persistence library. Also, I've seen jaxb just silently fail too often when ingesting XML and null fields abound.

    ReplyDelete
    Replies
    1. Hi Jason,

      The ability to support multi-arg constructors would definitely be a welcome addition to JAXB (JSR-222). As a workaround I suggest using XmlAdapters to handle this use case.
      - JAXB and Immutable Objects

      JAXB does not require that you have get/set methods. Simply specify @XmlAccessorType(XmlAccessType.FIELD) and JAXB will use your fields.
      - Using JAXB's @XmlAccessorType to Configure Field or Property Access

      JAXB doesn't really silently fail. By default it is very tolerant of poorly formed XML. If you want to see where the errors occur simply set a ValidationEventHandler on your Unmarshaller.

      XStream requires that your Java model pretty closely resemble the XML structure. If you want true separation check out the path based mapping we have in EclipseLink JAXB (MOXy)
      - XPath Based Mapping - Geocode Example

      -Blaise

      Delete
    2. Thanks for the reply! I've had to switch over to JAXB due to XStream just performing far too slowly (60 seconds vs 500 ms) for my JNLP app (something to do with class loading/scanning I'm sure - no compression on my war/jar though).

      I'll definitely check out MOXy :) I do hope JAXB gets multi(or single!)-arg ctor support. Writing an adapter for all these classes isn't feasible. I've set the ValidationEventHandler up and that works nicely. Thanks!

      Delete
  41. One more question (ha, as if there is ever just one more!). In XStream I was able to, using different instances of XStream, write out the same attributes with a different name. For instance, I have a class called "DistanceProperty" with a "private double distance". In one use case I want the attribute to be labelled "distance" in XML in another I want it to be labelled "height". I googled high and low but it looks like there isn't out-of-the-box support for this with JAXB. I'd like to set the attribute name at runtime somehow. Is this possible?

    ReplyDelete
    Replies
    1. Hi Jason,

      If you are using EclipseLink MOXy as your JAXB provider you can a mapping file to accomplish this use case:
      - Extended JAXB - Representing Metadata as XML
      - Mapping Objects to Multiple XML Schemas - Weather Example

      -Blaise

      Delete
  42. Great article. Nicely compares JAXB and XStream.

    ReplyDelete
  43. Hello.. In JAXB I dont find a way to serialize a dynamic Object. I would choose xstream then.

    ReplyDelete
    Replies
    1. Depends what you mean by a dynamic Object. EclipseLink JAXB (MOXy) offers a lot of useful extensions:

      java.lang.reflect.Proxy Mechanism
      MOXy can map to interfaces where the underlying implementation is handled by Java's reflection APIs:
      - MOXy JAXB - Map Interfaces to XML

      Extensible Objects
      MOXy supports virtual properties on static models. This is very useful when building multi-tenant applications:
      - MOXy Extensible Models - Multi-Tenant Example

      No Domain Classes Whatsoever
      With MOXy's Dynamic JAXB you don't need any domain classes at all. This can be bootstrapped from an XML schema or MOXy's external mapping document. Below is an example.
      - MOXy's Object Graphs & Dynamic JAXB

      Delete
  44. Great Job!! Enjoyed the reading.

    ReplyDelete

Note: Only a member of this blog may post a comment.