Java JAXB
Map XML to Java objects and back in Java with JAXB annotations and Marshaller/Unmarshaller.
Java JAXB
JAXB (Jakarta XML Binding, formerly Java Architecture for XML Binding) maps Java objects to XML and back without you writing parsing code by hand. You annotate a plain class, then hand it to a Marshaller to produce XML or an Unmarshaller to read XML into objects. JAXB lived in the JDK (javax.xml.bind) through Java 8, was removed in Java 11, and now ships as a separate dependency under the jakarta.xml.bind namespace. The annotations and the marshal/unmarshal model are the same in both.
The big idea: annotations describe the mapping
You do not write code that walks the XML tree. Instead you describe, with annotations on a class, how its fields correspond to XML elements and attributes. JAXB reads those annotations at runtime and generates the conversion for you in both directions. A POJO becomes a self-documenting schema.
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlAttribute;
@XmlRootElement(name = "book")
public class Book {
private String title;
private String author;
private int year;
@XmlElement public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
@XmlElement public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
@XmlAttribute public int getYear() { return year; }
public void setYear(int year) { this.year = year; }
// JAXB requires a public no-arg constructor for unmarshalling
public Book() {}
}The core annotations
A handful of annotations cover almost every mapping. They live in the jakarta.xml.bind.annotation package (or javax.xml.bind.annotation on Java 8).
| Annotation | Effect |
|---|---|
@XmlRootElement | Marks a class as a document root; names the outermost element |
@XmlElement | Maps a field/property to a nested element |
@XmlAttribute | Maps a field/property to an attribute on its element |
@XmlElementWrapper | Wraps a collection in a containing element |
@XmlTransient | Excludes a field from the XML entirely |
@XmlAccessorType | Controls whether JAXB binds fields or getters by default |
Marshalling: object to XML
A JAXBContext is the entry point — create one for your root classes, then ask it for a Marshaller. The marshaller turns an object graph into XML. Setting JAXB_FORMATTED_OUTPUT gives human-readable, indented output.
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Marshaller;
Book book = new Book();
book.setTitle("Effective Java");
book.setAuthor("Joshua Bloch");
book.setYear(2018);
JAXBContext context = JAXBContext.newInstance(Book.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(book, System.out);
// <book year="2018"><title>Effective Java</title><author>Joshua Bloch</author></book>Unmarshalling: XML to object
The reverse is symmetric: ask the same JAXBContext for an Unmarshaller and point it at a source — a File, InputStream, Reader, or StringReader. JAXB constructs the object using the no-arg constructor and populates it from the elements and attributes.
import jakarta.xml.bind.Unmarshaller;
import java.io.StringReader;
String xml = "<book year=\"2018\">"
+ "<title>Effective Java</title>"
+ "<author>Joshua Bloch</author></book>";
Unmarshaller unmarshaller = context.createUnmarshaller();
Book book = (Book) unmarshaller.unmarshal(new StringReader(xml));
System.out.println(book.getTitle()); // Effective Java
System.out.println(book.getYear()); // 2018JAXB is not on this code runner's classpath (it is an external dependency on modern Java), so the worked example below demonstrates the same marshal/unmarshal round trip using only the JDK's built-in DOM API. The concept is identical: an attribute on the root, child elements for the fields, and a round trip back to an equal object.
What to take from the run:
- The marshalled XML puts
yearas an attribute on<book>buttitleandauthoras child elements — exactly the split that@XmlAttributeversus@XmlElementcontrols in real JAXB. The annotation choice is what decides element-vs-attribute. - The root tag is
book, reported byel.getTagName(). In JAXB that name comes from@XmlRootElement(name = "book"); here it is the string passed tocreateElement. Either way, the outermost element identifies the document's type. - Marshalling and unmarshalling are mirror operations on the same shape: the program builds XML from a
Book, then reconstructs aBookfrom that XML. JAXB'sMarshallerandUnmarshallerare this exact pair backed by oneJAXBContext. round-trip equal : trueproves the data survived the trip intact — title, author, and year all came back. A correct binding is loss-free, which is the property you rely on when XML is your wire format.- Reading
yearback requiredInteger.parseIntbecause XML is all text. JAXB hides this by converting attribute and element text to the declared Java type (int,LocalDate,BigDecimal) automatically; without it, every field is a string you must parse yourself.
Java 8 vs. modern Java: the namespace move
The single biggest gotcha is the package rename. On Java 8 the API is bundled and lives under javax.xml.bind. From Java 11 onward it is unbundled and lives under jakarta.xml.bind, pulled in as a dependency.
| Java 8 | Java 11+ | |
|---|---|---|
| Package | javax.xml.bind | jakarta.xml.bind |
| On the classpath? | Built in | Add a dependency |
| Runtime artifact | JDK | org.glassfish.jaxb:jaxb-runtime |
For a Maven build on modern Java, you add the API plus a runtime implementation:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.5</version>
</dependency>Practice
In JAXB, what is the difference between annotating a property with @XmlElement versus @XmlAttribute?