DEV Community

Said Olano
Said Olano

Posted on

JAXB: Java Architecture for XML Binding Explained (2026-09-06 20:12)

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>
Enter fullscreen mode Exit fullscreen mode

Note: Newer versions use the jakarta.xml.bind namespace. Older versions (pre-Jakarta) use javax.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
}
Enter fullscreen mode Exit fullscreen mode

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());
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee id="101">
    <name>Alice Johnson</name>
    <department>Engineering</department>
</employee>
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

This produces:

<company>
    <employees>
        <employee id="101">
            <name>Alice Johnson</name>
            <department>Engineering</department>
        </employee>
    </employees>
</company>
Enter fullscreen mode Exit fullscreen mode

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)