JAXB (Java Architecture for XML Binding) enables the mapping of Java object into XML documents back and forth. This post is an introduction, tutorial and summary of JAXB annotations. It proceeds with operational code examples to describe each feature.
The code examples are available from
Github in the JAXB-JSON-XML-Marshalling directory. Most examples rely on the following piece of code to create XML files from annotated Java objects:
public static void createXML(Object o) throws JAXBException {
// Creating a Marshaller
JAXBContext jaxbContext = JAXBContext.newInstance(o.getClass());
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter result = new StringWriter();
jaxbMarshaller.marshal(o, result);
// Printing XML
String xml = result.toString();
System.out.println(xml);
}
In order to generate such XML documents, a JAXB context must be created. More details on this in part
II.
@XmlRootElement
Defines the root element of the XML document. If not name is specified (like this for example:
@XmlRootElement(name = "MyRootName"), the name of the element is taken from the class name.
This annotation can be used on a
Class or on an
enum. A
Class does need a no parameter constructor or a factory method (more details in the
@XmlType section).
For example:
@XmlRootElement(name="MyRootName")
public class A {
private int a1 = 0;
@XmlElement
public int getA1() {
return a1;
}
public void setA1(int a1) {
this.a1 = a1;
}
}
generates the following XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<MyRootName>
<a1>28</a1>
</MyRootName>
One can also specify a
namespace name for the XML element or a
local name for the XML element.
Inheritance
When a class inherits of another annotated class, the root name is taken from the inheriting class:
@XmlRootElement
public class InheritsA extends A {
private int b1 = 0;
@XmlElement
public int getB1() {
return b1;
}
public void setB1(int b1) {
this.b1 = b1;
}
}
The generated XML is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<inheritsA>
<a1>33</a1>
<b1>66</b1>
</inheritsA>
@XmlElement / @XmlTransient
The
@XmlElement indicates which element should be included in the XML conversion. If you want to annotate fields instead of getter methods, use the
@XmlAccessorType(XmlAccessType.FIELD).
If you need to exclude a field from the generated XML, use the
@XmlTransient annotation.
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class FieldAnnotation {
@XmlElement
private int a1 = 45;
@XmlTransient
private long a2 = 0;
@XmlElement(nillable=true)
private String xxx = null;
@XmlElement(required=true)
private String req;
public int getA1() {
return a1;
}
public void setA1(int a1) {
this.a1 = a1;
}
public long getA2() {
return a2;
}
public void setA2(long a2) {
this.a2 = a2;
}
public String getXxx() {
return xxx;
}
public void setXxx(String xxx) {
this.xxx = xxx;
}
public String getReq() {
return req;
}
public void setReq(String req) {
this.req = req;
}
}
Assuming the following class creation:
FieldAnnotation fa = new FieldAnnotation();
fa.setA2(28);
fa.setReq("Some value");
generates:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<fieldAnnotation>
<a1>45</a1>
<xxx xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<req>Some value</req>
</fieldAnnotation>
One can also set a
default string value, or set the
XML Schema element name and the
target namespace of the XML element via the
@XmlElement annotation.
@XmlType
This annotation allows one to specify the order of items in the generated XML document. It can also be used to specify a factory class and/or a factory method (with no arguments) to create instances of the annotated class:
@XmlRootElement
@XmlType(propOrder={"a2", "a1"},
factoryClass=OrderFactory.class,
factoryMethod="myConstructor")
public class Order {
private int a1 = 0;
private int a2 = 0;
@XmlElement
public int getA1() {
return a1;
}
public void setA1(int a1) {
this.a1 = a1;
}
@XmlElement
public int getA2() {
return a2;
}
public void setA2(int a2) {
this.a2 = a2;
}
}
The factory class:
public class OrderFactory {
public static Order myConstructor() {
return new Order();
}
}
The generated XML:
<order>
<a2>99</a2>
<a1>28</a1>
</order>
One can also set the
XML Schema type and the
target namespace of the XML Schema type with the
@XmlType annotation.
@XmlSeeAlso
This annotation allows one to refer to other classes to include in the XML generation. In other words, if a referred class is not in the
JAXB context, it will be taken into account anyway and won't trigger a runtime error. This annotation can be used as a safeguard when marshalling and unmarshalling.
This is best described with an example:
@XmlRootElement
public class Document {
private String content = "";
@XmlElement
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
@XmlRootElement
public class Image {
private String name = "";
@XmlElement
public String getName() {
return name;
}
public void setName(String content) {
this.name = content;
}
}
@XmlRootElement
@XmlSeeAlso({Document.class,Image.class})
public class Folder {
private Document document = null;
private Image image = null;
@XmlElement
public Document getDocument() {
return document;
}
public void setDocument(Document document) {
this.document = document;
}
@XmlElement
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
}
The generated output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<folder>
<document>
<content>My content</content>
</document>
<image>
<name>My image</name>
</image>
</folder>
Next
JAXB to XML •
JAXB to JSON •
JAXB Annotations Tutorial Table Of Content