JAXB: Java Architecture for XML Binding
Working with XML in Java can be tedious if you rely on low-level parsers like SAX or DOM. JAXB (Java Architecture for XML Binding) offers a higher-level, annotation-driven approach that maps Java objects to XML documents and back again with minimal boilerplate.
In this post, we'll explore what JAXB is, how it works, and how to use it effectively.
What is JAXB?
JAXB provides a convenient way to bind an XML schema to a representation of Java objects. It handles two core operations:
- Marshalling: Converting Java objects into XML.
- Unmarshalling: Converting XML back into Java objects.
This lets developers work with familiar POJOs (Plain Old Java Objects) instead of manually traversing XML nodes.
A Note on Availability
JAXB was bundled with the JDK from Java 6 through Java 8. Starting with Java 11, it was removed from the JDK and must be added as an external dependency.
For Maven projects, add the following:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.0</version>
</dependency>
Note: Newer versions use the
jakarta.xml.bindnamespace. Older versions (pre-Jakarta) usejavax.xml.bind.
Core Annotations
JAXB relies on annotations to control how Java classes map to XML. The most common ones are:
| Annotation | Purpose |
|---|---|
@XmlRootElement |
Marks the root element of the XML document |
@XmlElement |
Maps a field or property to an XML element |
@XmlAttribute |
Maps a field to an XML attribute |
@XmlType |
Defines the order of elements |
@XmlAccessorType |
Controls field/property access |
@XmlTransient |
Excludes a field from binding |
A Practical Example
Let's model a simple Employee object.
import jakarta.xml.bind.annotation.*;
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
@XmlAttribute
private int id;
@XmlElement(name = "name")
private String name;
@XmlElement(name = "department")
private String department;
@XmlTransient
private String internalNotes;
// Required no-arg constructor
public Employee() {}
public Employee(int id, String name, String department) {
this.id = id;
this.name = name;
this.department = department;
}
// Getters and setters omitted for brevity
}
Marshalling: Java to XML
import jakarta.xml.bind.*;
import java.io.StringWriter;
public class MarshalExample {
public static void main(String[] args) throws JAXBException {
Employee employee = new Employee(101, "Alice Johnson", "Engineering");
JAXBContext context = JAXBContext.newInstance(Employee.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter writer = new StringWriter();
marshaller.marshal(employee, writer);
System.out.println(writer.toString());
}
}
Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee id="101">
<name>Alice Johnson</name>
<department>Engineering</department>
</employee>
Notice the internalNotes field is excluded thanks to @XmlTransient.
Unmarshalling: XML to Java
import jakarta.xml.bind.*;
import java.io.StringReader;
public class UnmarshalExample {
public static void main(String[] args) throws JAXBException {
String xml = """
<employee id="101">
<name>Alice Johnson</name>
<department>Engineering</department>
</employee>
""";
JAXBContext context = JAXBContext.newInstance(Employee.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Employee employee = (Employee) unmarshaller.unmarshal(new StringReader(xml));
System.out.println(employee.getName()); // Alice Johnson
}
}
Handling Collections
To map a list of objects, wrap them in a container class using @XmlElementWrapper.
@XmlRootElement(name = "company")
@XmlAccessorType(XmlAccessType.FIELD)
public class Company {
@XmlElementWrapper(name = "employees")
@XmlElement(name = "employee")
private List<Employee> employees = new ArrayList<>();
// Constructors, getters, setters
}
This produces:
<company>
<employees>
<employee id="101">
<name>Alice Johnson</name>
<department>Engineering</department>
</employee>
</employees>
</company>
Performance Considerations
Creating a JAXBContext is expensive because it uses reflection to analyze your classes. Always cache and reuse JAXBContext instances — they are thread-safe. In contrast, Marshaller and Unmarshaller are not thread-safe and should be created
Top comments (0)