CodeGym /Courses /JAVA 25 SELF /Working with XML via JAXB: basics and annotations

Working with XML via JAXB: basics and annotations

JAVA 25 SELF
Level 47 , Lesson 3
Available

1. Introduction to JAXB

JAXB (Java Architecture for XML Binding) — a standard Java technology for converting (binding) Java objects to XML and back. With JAXB, you can easily serialize objects to XML files and then reconstruct them from those files.

JAXB was part of the Java standard library up to and including version 11. Starting with Java 11, JAXB was moved to a separate module that you need to add via Maven/Gradle or download manually. For modern Java versions add the dependencies:

<!-- Example for Maven -->
<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.3</version>
</dependency>

Why use XML at all?

  • XML is a universal, human-readable format widely used for data exchange between systems, configuration, and data storage.
  • Unlike binary serialization, XML is easy to read with your eyes, validate against a schema, and open in a browser.

2. Core JAXB classes and annotations

JAXB relies on annotations applied to classes and their fields to control the serialization/deserialization process.

Key annotations

Annotation Purpose
@XmlRootElement
Marks the root XML element (the class itself)
@XmlElement
Marks a field/property as an XML element
@XmlAttribute
Marks a field/property as an XML attribute
@XmlType
Controls element order, type name, etc.
@XmlTransient
Excludes a field from serialization

Key classes

  • JAXBContext — the entry point; creates a context for serializing/deserializing specific classes.
  • Marshaller — converts an object to XML (marshalling, marshal()).
  • Unmarshaller — converts XML to an object (unmarshalling, unmarshal()).

3. Example: serializing an object to XML

Let’s create a class to serialize. Let it be a character for our game:

import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlAttribute;

@XmlRootElement(name = "player")
public class Player {
    private String name;
    private int level;
    private int health;

    public Player() {} // Required no-arg constructor!

    public Player(String name, int level, int health) {
        this.name = name;
        this.level = level;
        this.health = health;
    }

    @XmlElement
    public String getName() {
        return name;
    }

    public void setName(String name) { this.name = name; }

    @XmlElement
    public int getLevel() {
        return level;
    }

    public void setLevel(int level) { this.level = level; }

    @XmlAttribute
    public int getHealth() {
        return health;
    }

    public void setHealth(int health) { this.health = health; }
}
  • @XmlRootElement(name = "player") — the class becomes the root element <player>.
  • @XmlElement — the field will be a separate XML element (<name>, <level>).
  • @XmlAttribute — the field will be an attribute of the root element (health="100").
  • Don’t forget the no-arg constructor! JAXB requires it for deserialization.

Serializing an object to XML

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Marshaller;

public class Main {
    public static void main(String[] args) throws Exception {
        Player player = new Player("Aragorn", 5, 100);

        JAXBContext context = JAXBContext.newInstance(Player.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // Pretty output

        marshaller.marshal(player, System.out); // Write XML to the console
        // marshaller.marshal(player, new File("player.xml")); // Or to a file
    }
}

Result:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<player health="100">
    <name>Aragorn</name>
    <level>5</level>
</player>

Deserializing an object from XML

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Unmarshaller;
import java.io.File;

public class Main {
    public static void main(String[] args) throws Exception {
        JAXBContext context = JAXBContext.newInstance(Player.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();

        Player player = (Player) unmarshaller.unmarshal(new File("player.xml"));
        System.out.println(player.getName() + ", level: " + player.getLevel() + ", health: " + player.getHealth());
    }
}

4. Features and limitations of JAXB

Class requirements

  • Public no-arg constructor — required.
  • Use getters and setters for correct operation.
  • All serializable fields must be accessible (via the public API).
  • Nested objects and collections must also be serializable (annotate them and add a no-arg constructor).

Working with collections and nested objects

Suppose the player has an inventory (a list of items). How do you serialize a collection?

import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import java.util.List;

@XmlRootElement(name = "player")
public class Player {
    // ... other fields

    private List<String> inventory;

    public Player() {}

    // ... other getters/setters

    @XmlElementWrapper(name = "inventory")
    @XmlElement(name = "item")
    public List<String> getInventory() {
        return inventory;
    }

    public void setInventory(List<String> inventory) {
        this.inventory = inventory;
    }
}

Serialization result:

<player health="100">
    <name>Aragorn</name>
    <level>5</level>
    <inventory>
        <item>Sword</item>
        <item>Shield</item>
    </inventory>
</player>
  • @XmlElementWrapper — creates a “wrapper” around the collection (the <inventory> element).
  • @XmlElement(name = "item") — each list element is serialized as <item>.

If you have nested objects (for example, Position), you also need to annotate them and add a no-arg constructor.

5. Practice: serializing and deserializing an object to XML

import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import jakarta.xml.bind.annotation.XmlAttribute;
import java.util.List;

@XmlRootElement(name = "player")
public class Player {
    private String name;
    private int level;
    private int health;
    private List<String> inventory;
    private Position position;

    public Player() {}

    public Player(String name, int level, int health, List<String> inventory, Position position) {
        this.name = name;
        this.level = level;
        this.health = health;
        this.inventory = inventory;
        this.position = position;
    }

    @XmlElement
    public String getName() { return name; }

    @XmlElement
    public int getLevel() { return level; }

    @XmlAttribute
    public int getHealth() { return health; }

    @XmlElementWrapper(name = "inventory")
    @XmlElement(name = "item")
    public List<String> getInventory() { return inventory; }

    @XmlElement
    public Position getPosition() { return position; }

    // setters omitted for brevity
}

@XmlRootElement(name = "position")
class Position {
    private int x;
    private int y;

    public Position() {}

    public Position(int x, int y) { this.x = x; this.y = y; }

    @XmlAttribute
    public int getX() { return x; }

    @XmlAttribute
    public int getY() { return y; }

    // setters omitted
}

Serialization:

Player player = new Player(
    "Aragorn",
    5,
    100,
    List.of("Sword", "Shield", "Potion"),
    new Position(10, 20)
);

JAXBContext context = JAXBContext.newInstance(Player.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(player, System.out);

XML result:

<player health="100">
    <name>Aragorn</name>
    <level>5</level>
    <inventory>
        <item>Sword</item>
        <item>Shield</item>
        <item>Potion</item>
    </inventory>
    <position x="10" y="20"/>
</player>

Deserialization works similarly: JAXB will handle nested objects and collections automatically if the classes are defined correctly.

6. Table: core JAXB annotations and their effect

Annotation Where to use What it does in XML
@XmlRootElement
Class Root element
@XmlElement
Getter/field Element inside XML
@XmlAttribute
Getter/field Attribute on an element
@XmlElementWrapper
Collection getter Collection “wrapper” (e.g., <list>)
@XmlTransient
Field/getter Excludes a field from serialization
@XmlType
Class Controls element order and type name

7. Features and limitations of JAXB

Element order

By default, JAXB may output elements in alphabetical order. To explicitly define the order, use @XmlType and the propOrder property:

@XmlType(propOrder = {"name", "level", "inventory", "position"})

Excluding fields

To avoid serializing a field/getter, use @XmlTransient:

@XmlTransient
public String getSecretCode() { ... }

Collection issues

  • Don’t use raw collections without generics: write List<Type> rather than List.
  • If a collection stores objects, their classes must also be annotated and have a no-arg constructor.

Errors

  • Missing no-arg constructor — you will get a JAXBException during unmarshalling.
  • Non-annotated nested class — JAXB will not be able to serialize/deserialize it.
  • Non-standard types (for example, LocalDate) require an adapter (@XmlJavaTypeAdapter).

8. Common mistakes when working with JAXB

Error #1: Missing no-arg constructor. JAXB requires the serializable class to have a public no-argument constructor. If it’s missing — an exception JAXBException will be thrown during unmarshalling.

Error #2: Non-annotated nested objects. If you have a field that is an object but its class is not annotated with @XmlRootElement or at least @XmlType, JAXB will not be able to serialize/deserialize it correctly.

Error #3: Problems with collections. JAXB does not understand raw collections without specifying the element type. Use generics and annotate collections correctly (@XmlElementWrapper + @XmlElement).

Error #4: Implicit control of element order. If element order in XML matters for integration, use @XmlType with propOrder; otherwise, JAXB may output elements in a different order (e.g., alphabetical).

Error #5: Using non-standard types without an adapter. JAXB cannot serialize certain types (for example, LocalDate) without an adapter. Apply @XmlJavaTypeAdapter or serialize the value as a string.

1
Task
JAVA 25 SELF, level 47, lesson 3
Locked
Designing a Book Record for a Digital Library 📖
Designing a Book Record for a Digital Library 📖
1
Task
JAVA 25 SELF, level 47, lesson 3
Locked
Loading a Book from XML into the Application 📥
Loading a Book from XML into the Application 📥
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION