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 type | XML Simple Schema type |
---|---|
java.lang.String | xs:string |
int | xs:int |
long | xs:long |
boolean | xs:boolean |
byte | xs:byte |
short | xs:short |
float | xs:float |
double | xs:double |
byte[] | xs:base64Binary |
java.math.BigInteger | xs:integer |
java.math.BigDecimal | xs:decimal |
java.util.Date | xs:dateTime |
javax.xml.namespace.QName | xs:QName |
javax.xml.datatype.Duration | xs:duration |
Collections are also supported by JAXB and can be used as element content:
Java type | XML Mapping |
---|---|
Arrays, single dimension | Repeats the element several times, sets maxOccurs in the schema to unbounded (except byte[], see above). |
Arrays, multi dimension | For 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.Map | The 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. |