Jarfiller.com

JAXB Guide

Read, modify and write XML documents with JAXB 2.1 or 2.2

Overview

JAXB allows you to access XML documents like regular Java classes. It only works for documents that follow a fixed structure that can be described by a schema, a DTD or by a tree of Java classes.
The easiest way to use JAXB is with a XML Schema (XSD file). You can then just compile the schema using xjc. xjc generates annotated Java classes that you use to read and write the XML. Alternatively, you write your data structures as Java classes yourself and use annotations to map them onto the XML structure. An XML schema is not needed for this approach, but you can generate one from your code using the schemagen tool.
Once you have the annotated classes, JAXB can read XML documents and create object trees that represents them (this is called unmarshalling) and write them back into an XML document (marshalling). The object tree itself can be created, read and modified like any other Java object.

Mapping Classes

In case you don't already have a schema, you need to ask yourself whether you want to write the XML Schema first and generate classes for it using xjc, or whether you want to write the Java classes with JAXB annotations, and optionally generate the XML Schema later using schemagen.

  • If you just want to serialize some data in XML, and don't really care too much what the XML looks like, write the definitions in Java. It's usually more convenient and the resulting Java classes are simpler and easier to use. This is called bottom-up design.
  • If you care about the XML Schema (e.g. you want to publish it), write the Schema first and use xjc. This makes it a lot easier to have a good XML schema. This is called top-down design

If you have a schema, you can use xjc on the command line to get the classes that you need. xjc is included with both JDK6 and the JAXB reference implementation. Usage:

> xjc -d target-directory -p your.package.name path-to-schema
package com.jarfiller.example;
import java.util.*;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class MovieLibrary {                      // root element
  private List<Movie> collection;

  public MovieLibrary() {                        // no-arg constructor required (more)
  }

  public MovieLibrary(List<Movie> collection) {  // convenience constructor
    this.collection = collection;
  }

  public void setCollection(List<Movie> collection) {
    this.collection = collection;
  }
  public List<Movie> getCollection() {
    return collection;
  }
}

public class Movie {                             // normal element - annotations are optional
  private String title;
  private int releaseYear;

  public Movie() {                               // no-arg constructor required (more)
  }

  public Movie(String title, int releaseYear) {
    this.title = title;
    this.releaseYear = releaseYear;
  }

  public String getTitle() {
    return title;
  }
  public void setTitle(String title) {
    this.title = title;
  }

  public int getReleaseYear() {
    return releaseYear;
  }
  public void setReleaseYear(int releaseYear) {
    this.releaseYear = releaseYear;
  }
}

Shorter alternative: just use public fields. The following classes would create exactly the same XML as the property-based bean above:

@XmlRootElement
public class MovieLibrary {
  public List<Movie> collection;
}

public class Movie {
  public String title;
  public int releaseYear;
}

This is the XML Schema that the schemagen tool will create, given the MovieLibrary class:

<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:complexType name="movieLibrary">
    <xs:sequence>
      <xs:element name="collection" type="movie" nillable="true"
                     minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="movie">
    <xs:sequence>
      <xs:element name="title" type="xs:string" minOccurs="0"/>
      <xs:element name="releaseYear" type="xs:int"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

Be careful with schemagen-generated schemas though: as in this example, they do not declare a top-level element. You may need to add it yourself:

<xs:element name="movieLibrary" type="movieLibrary"/>

Reading and Writing XML

List<Movie> movies = new java.util.ArrayList<Movie>();
movies.add(new Movie("Casablanca", 1942));
movies.add(new Movie("Dr Zhivago", 1965));
movies.add(new Movie("Out of Africa", 1985));
MovieLibrary library = new MovieLibrary(movies);

JAXB.marshal(library, new File("/tmp/library.xml"));  // write XML (more)

Result of the previous code snippet:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<movieLibrary>
    <collection>
        <name>Casablanca</name>
        <releaseYear>1942</releaseYear>
    </collection>
    <collection>
        <name>Dr Zhivago</name>
        <releaseYear>1965</releaseYear>
    </collection>
    <collection>
        <name>Out of Africa</name>
        <releaseYear>1985</releaseYear>
    </collection>
</movieLibrary>
MovieLibrary library = JAXB.unmarshal(new File("/tmp/library.xml"), 
                               MovieLibrary.class);  // read XML (more)

assert library.getCollection().size() == 3;
assert library.getCollection().get(0).getTitle().equals("Casablanca");
assert library.getCollection().get(2).getReleaseYear() == 1985;

Beside beans, JAXB supports the following types natively. Each of them can also be used either as element content or for XML attributes:

Java typeXML Simple Schema type
java.lang.Stringxs:string
intxs:int
longxs:long
booleanxs:boolean
bytexs:byte
shortxs:short
floatxs:float
doublexs:double
byte[]xs:base64Binary
java.math.BigIntegerxs:integer
java.math.BigDecimalxs:decimal
java.util.Datexs:dateTime
javax.xml.namespace.QNamexs:QName
javax.xml.datatype.Durationxs:duration

Collections are also supported by JAXB and can be used as element content:

Java typeXML Mapping
Arrays, single dimensionRepeats the element several times, sets maxOccurs in the schema to unbounded (except byte[], see above).
Arrays, multi dimensionFor the first dimension, the item is repeated (maxOccurs in the schema set to unbounded). For additional dimensions, there is a repeating element item defined that will be nested.
java.util.Collection (includes List and Set)Repeats the element several times, sets maxOccurs in the schema to unbounded (like one-dimensional arrays).
java.util.MapThe element contains an entry element for each Map entry (maxOccurs in the schema set to unbounded), each entry containing a key and a value element.

How to... Mapping

How to... Serialization

JAXB uses plain Java beans to represent the XML document. Data can be either stored in properties, as shown in this section, or in public fields.
In order to map the bean onto a specific XML schema, it supports a large number of annotations to give you full control over the XML that will be generated. However, if the exact XML layout is a concern for you (e.g. whether a field will be stored as an attribute or as an element), you are usually better off writing the XML Schema first and use xjc.
Every serializable element needs a public constructor without arguments that JAXB can use to create new instances. You are free to add additional constructors, of course.
In JAXB, you can either use bean properties or public fields for you data. You can also mix both of them. The created XML will always be the same.
You can override the automatic creation of elements for both types of members using the @XmlAccessorType annotation.
Since JAXB 2.1, serializing your Java class tree into a XML document is really simple. Just call the static marshal method and you're done.
Only in more complicated scenarios you will need to create JAXBContext and Marshaller separately. This will be shown in the How-To sections below.
The marshal method writes the XML structure represented by the first argument into the given file or stream. It is a short cut added in JAXB 2.1 that replaces the complicated setup mechanism of older versions.
Since JAXB 2.1, reading the XML document is as simple as writing. Just call the static marshal method and you're done.
Only in more complicated scenarios you will need to create JAXBContext and Unmarshaller separately. This will be shown in the How-To sections below.
The unmarshal method reads the XML structure represented by the first argument will and creates an object tree using the class specified in the second argument. It is a short cut added since JAXB 2.1 that replaces the complicated setup mechanism of older versions.
The Java types in this section's tables can be translated directly into corresponding XML types. You do not need to convert them manually. All other types are treated as beans by default. Alternatively you could also write an @XmlAdapter to map a type and declare it with a @XmlJavaTypeAdapter annotation.
Built-in types (int, boolean, long, float...) are always required, as they can not be null. If you want to make the XML elements optional you must use the corresponding wrapper type (Integer, Boolean, Long, Float...).
Well, that's not entirely true. But creating the context by package works only if you either have an ObjectFactory class, which is a helper class generated by , or a file called jaxb.index containing all class names. See the JavaDocs for details.
If you create the Java classes by hand, you usually don't have neither ObjectFactory nor jaxb.index, and it does not make much sense to create those files manually instead of just listing the classes in the code. So, effectively, creating the context by package is only a good option for xjc-generated code.
The JAXBContext represents the mapping between Java classes and XML. You can either specify one or more root classes (it supports varargs) or the name of the package containing the mapping classes. JAXBContext is multi-thread safe and can be shared among threads (note that you can not share Marshaller and Unmarshaller).
xjc does not set it if the root element is defined using a stand-alone complex type instead of an inline type. Then xjc can not be sure whether all uses of the complex type are really as root type, and thus it can not write the @XmlRootElement annotation.
xjc is a compiler that takes a XML schema and generates annotated Java classes that represent this schema. You can find xjc in your JDK's bin directory since JDK6.
schemagen takes Java classes with JAXB's annotations and generates an XML schema for them. This is useful if you want to use the XML document in other applications. You can find schemagen in your JDK's bin directory (since JDK6).
The path of the directory to store the generated source in.
The package name for the Java code to generate. If you don't specify the -p option, xjc will try to derive a package name from the XML Schema's namespace URI.
The path to the XML schema you want to compile. You can specify more than one schema. If this is a directory, all schemas in the directory will be compiled.
The prolog is the optional first line of a XML file, and looks like "<?xml bla bla bla?>". Most importantly, it defines the XML version ("version") and the character encoding ("encoding") of the file.
If a document has no prolog, the character encoding is either UTF-8 or UTF-16. The processor will detect the encoding by inspecting the document's first four bytes.
XML Schema
An XML Schema is used to describe the structure of a XML document. The schema itself is a also XML document, called XML Schema Definition (XSD).
Specification: Part 0, Part 1, Part 2
XPath
XPath is a query language for XML documents.
Wikipedia: XPath
Specification: XPath 1.0, XPath 2.0
XSLT
XSLT is a language for transforming XML documents into other XML documents, HTML or plain text.
Homepage: XSL Family (W3C)
Wikipedia: XSLT
Specification: XSLT 1.0, XSLT 2.0
close
close