Introduction to JAXB

Introduction

This tutorial gives an in-depth introduction to JAXB (Java Architecture for XML Binding). The purpose of this tutorial is to show to how to quickly convert Java objects to XML and vice versa. Later tutorials will explore more advanced concepts of JAXB, such as validation, XSLT or schema generation.

What is JAXB?

JAXB defines a standard to bind Java classes to XML and vice versa. Marshalling is the process to convert Java objects into XML. Unmarshalling is the process to convert XML documents to Java. JAXB provides a binding framework that maps XML elements and attributes to Java fields and properties. It also has Java annotations that provide the capability to configure this binding.

XML Schema definitions describe the structure of XML documents in a similar manner how Java classes describe Java objects. The JAXB binding framework provides a schema compiler that converts XML schemas to Java classes (xjc tool). It also provides a schema generator that converts Java classes into XML schemas (schemagen tool).

The picture below summarises the main JAXB concepts:

JAXB Overview
JAXB Overview

The JAXB Hello World

Let’s start our journey through JAXB land with a traditional Hello World example. The Java class below is a simple class with several properties and no dependencies.

The @XmlRootElement annotation indicates that this class is mapped to a root XML element. When the @XmlAccessorType annotation is set to XmlAccessType.FIELD, all private fields are mapped to XML elements.  Annotating them with @XmlElement is optional. The @XmlAttribute defines that the id field is mapped as an attribute instead of an element. The @XmlTransient attribute is used when you don’t want to bind a field.

The following code shows how to marshal and unmarshal using JAXB.

The JAXBContext provides the entry point to the JAXB API (line 11). The JAXBContext contains all the binding information needed to marshal and unmarshal Java to XML. To create a JAXBContext instance, we pass in the Java root classes annotated with @XmlRootElement. The JAXBContext will create bindings for all classes directly or indirectly available from the root class.

Creating a new JAXBContext instance is a heavy operation.  The JAXB specification encourages applications to re-use them. JAXBContext instances are guaranteed to be thread-safe.

Then we create a Marshaller and configure it to pretty print the XML (lines 14 and 15).  In line 19 we marshal our Java class to generate the XML.

This is the XML generated:

We finally create an Unmarshaller to parse the XML and convert it to a new Java instance (line 24).

Using the JAXB schemagen tool we can create the XML Schema from the Java class (for details check this). The schemagen tool automatically maps primitive Java types to their XML Schema type counterparts. The Sector enum is mapped to a restricted simpleType.

Changing default mappings: name and propOrder attributes

JAXB does good job at defaulting bindings between Java and XML. For example, Java names are translated to XML standard names. Java primitive types are mapped to XML Schema types. The class below makes use of the name and propOrder attributes to configure the XML mapping:

The name attribute in the @XmlRootElement, @XmlAttribute and @XmlElement annotations sets the name of the XML Schema element. So for example, the above example will use the tag name “super-company” instead of the JAXB default “company“:

The @XmlType annotation maps a Java class to an XML Schema type. The propOrder attribute defines the order in which XML elements will appear in the XML file. Most JAXB implementations use the same order used in the Java class. This however is not guaranteed across different JAXB vendors. The only way to guarantee the order is either to use the @XmlOrderType annotation or set the propOrder.

Below the XML Schema generated.

Mapping Collections

There are three ways to map a Java collection to XML:

  • Unwrapped collections (default)
  • Wrapped collections (using @XmlElementWrapper)
  • Space-separated list (using @XmlList)

Unwrapped collections

The Java class below illustrates the default behaviour: unwrapped mode. The employees collection is only annotated with @XmlElement.

This is the XML generated. Note that each item in the collection is a direct child of the root node. This is to say, the collections items are unwrapped.

Wrapped collections

The @XmlElementWrapper maps a Java collection to an XML wrapped collection. Below an example Java class.

This is the XML generated. As you can see, the items in the collection are wrapped by the employees element, and they are no longer direct descendants from the root node.

Space-Separated List

The @XmlList annotation maps a collection to a list of values separated by space. The only limitation is that the items in the collection must map to simple XML Schema types. This is to say, @XmlList does not support complex types.

The Java class below shows an example how to use the @XmlList annotation (the @XmlElement is optional):

When adding three items to the names list, it generates the following XML:

Maps

The default mapping for java.util.Map makes use of entry, key and value XML elements.  This default mapping can be changed with the @XmlJavaTypeAdapter annotation.

Let’s look at an example. The Java class below has a java.util.Map collection.

This is the XML that will be generated:

Adapters

The @XmlJavaTypeAdapter is the workhorse of JAXB type mapping. JAXB does a good job at mapping Java classes to XML Schema types out of the box. JAXB however cannot map some classes, such as those without an empty constructor. Other times, we might want to change the default mapping.  The @XmlJavaTypeAdapter annotation defines an adapter that customises the Java to XML mapping.

The following example illustrates how to use adapters. The Company class has three elements that map to non-standard XML Schema types: CompanyId, and Joda’s DateTime and LocalDate.

We will create three adapters later, one for each type: CompanyIdAdapter, DateTimeAdapter and LocalDateAdapter. First, let’s see how to register the adapters in the package-info.java file so that the JAXB engine can use them:

If you have never heard of package-info.java before, check this blog.

XmlAdapter for Joda’s DateTime

This is the implementation of the @XmlJavaTypeAdapter to map Joda DateTimes to XML. The adapter extends from javax.xml.bind.annotation.adapters.XmlAdapter and must implement the marshal and umarshal methods.

Since Joda-Time and XML Schema both represent date and time using the standard ISO 8601, the implementation of the XmlAdapter is trivial.

XmlAdapter for Joda’s LocalTime

This is the implementation of the @XmlJavaTypeAdapter to map Joda’s LocalDates to XML.

XmlAdapter for Immutable objects or classes with no default constructor

The CompanyId class does not have a default constructor, and thus JAXB cannot use it out of the box. This is its implementation:

And this is the XmlAdapter that maps CompanyId to XML:

Namespaces

XML namespaces are used to group XML elements and attributes. XML namespaces allow mixing elements from different vocabularies into the same XML document, so that two tags with the same name but different semantics can be used together.

The best way to declare a namespace in JAXB is with the @XmlSchema annotation in the package-info.java file. This sets the default namespace for all Java classes in the package.

The @XmlSchema configuration below sets the default namespace and elementFormDefault attributes:

This generates an XML Schema like the below:

and an XML document as per below:

The namespace attribute in @XmlSchema maps to the targetNamespace attribute in xs:schema. The targetNamespace attribute has the namespace of the domain that the XML Schema defines.

The elementFormDefault controls whether the elements must be namespace-qualified. Most XML Schema declarations set this to “qualified“. A qualified element means that it is part of an XML Schema vocabulary. It must either have a namespace prefix or be part of the default namespace. There is also a counterpart attributeFormDefault, but is usually left as unqualified. For a good explanation of elementFormDefault and attributeFormDefault you can read Introduction to XML Schema.

Another usage of @XmlSchema is to declare multiple namespaces.

This declaration defines two namespaces, a default http://actimem.com/xsd/company.xsd and a prefixed http://actimem.com/xsd/employee.xsd. An example XML looks like this:

Bibliography

The following two tabs change content below.

Eduard Manas

Eduard is a senior IT consultant with over 15 years in the financial sector. He is an experienced developer in Java, C#, Python, Wordpress, Tibco EMS/RV, Oracle, Sybase and MySQL.Outside of work, he likes spending time with family, friends, and watching football.

Latest posts by Eduard Manas (see all)

Leave a Reply