JavaRush /Курсы /JAVA 25 SELF /Работа с XML через JAXB: основы, аннотации

Работа с XML через JAXB: основы, аннотации

JAVA 25 SELF
47 уровень , 3 лекция
Открыта

1. Знакомство с JAXB

JAXB (Java Architecture for XML Binding) — это стандартная технология Java для преобразования (binding) Java-объектов в XML и обратно. С помощью JAXB можно легко сериализовать объекты в XML-файлы, а затем воссоздавать их из этих файлов.

JAXB входил в стандартную библиотеку Java до версии 11 включительно. Начиная с Java 11, JAXB вынесен в отдельный модуль, который нужно подключать через Maven/Gradle или скачивать вручную. Для современных версий Java добавьте зависимости:

<!-- Пример для 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>

Зачем вообще нужен XML?

  • XML — это универсальный, человекочитаемый формат, который широко используется для обмена данными между системами, конфигурирования и хранения информации.
  • В отличие от бинарной сериализации, XML легко прочитать глазами, проверить валидность по схеме и открыть в браузере.

2. Основные классы и аннотации JAXB

JAXB работает на основе аннотаций, которыми помечаются классы и их поля, чтобы управлять процессом сериализации/десериализации.

Главные аннотации

Аннотация Для чего нужна
@XmlRootElement
Обозначает корневой элемент XML (сам класс)
@XmlElement
Помечает поле/свойство как XML-элемент
@XmlAttribute
Помечает поле/свойство как XML-атрибут
@XmlType
Управляет порядком элементов, именем типа и др.
@XmlTransient
Исключает поле из сериализации

Главные классы

  • JAXBContext — точка входа, создаёт контекст для сериализации/десериализации конкретных классов.
  • Marshaller — превращает объект в XML (маршалинг, marshal()).
  • Unmarshaller — превращает XML в объект (анмаршалинг, unmarshal()).

3. Пример: сериализация объекта в XML

Создадим класс, который будем сериализовать. Пусть это будет персонаж для нашей игры:

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() {} // Обязательный пустой конструктор!

    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") — класс превращается в корневой элемент <player>.
  • @XmlElement — поле будет отдельным XML-элементом (<name>, <level>).
  • @XmlAttribute — поле будет атрибутом корневого элемента (health="100").
  • Не забудьте пустой конструктор! JAXB требует его для десериализации.

Сериализация объекта в 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); // Красивый вывод

        marshaller.marshal(player, System.out); // Пишем XML в консоль
        // marshaller.marshal(player, new File("player.xml")); // Или в файл
    }
}

Результат:

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

Десериализация объекта из 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() + ", уровень: " + player.getLevel() + ", здоровье: " + player.getHealth());
    }
}

4. Особенности и ограничения JAXB

Требования к классам

  • Публичный конструктор без параметров — обязателен.
  • Для корректной работы используйте геттеры и сеттеры.
  • Все сериализуемые поля должны быть доступны (через public API).
  • Вложенные объекты и коллекции тоже должны быть сериализуемыми (аннотируйте и добавьте пустой конструктор).

Работа с коллекциями и вложенными объектами

Допустим, у игрока есть инвентарь (список предметов). Как сериализовать коллекцию?

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

@XmlRootElement(name = "player")
public class Player {
    // ... остальные поля

    private List<String> inventory;

    public Player() {}

    // ... остальные геттеры/сеттеры

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

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

Результат сериализации:

<player health="100">
    <name>Aragorn</name>
    <level>5</level>
    <inventory>
        <item>Sword</item>
        <item>Shield</item>
    </inventory>
</player>
  • @XmlElementWrapper — создаёт «обёртку» вокруг коллекции (элемент <inventory>).
  • @XmlElement(name = "item") — каждый элемент списка сериализуется как <item>.

Если у вас есть вложенные объекты (например, Position), их тоже нужно аннотировать и добавить пустой конструктор.

5. Практика: сериализация и десериализация объекта в 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; }

    // сеттеры опущены для краткости
}

@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; }

    // сеттеры опущены
}

Сериализация:

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-результат:

<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>

Десериализация работает аналогично: JAXB сам разберёт вложенные объекты и коллекции, если классы описаны корректно.

6. Таблица: основные аннотации JAXB и их эффект

Аннотация Где использовать Что делает в XML
@XmlRootElement
Класс Корневой элемент
@XmlElement
Геттер/поле Элемент внутри XML
@XmlAttribute
Геттер/поле Атрибут у элемента
@XmlElementWrapper
Геттер коллекции «Обёртка» коллекции (например, <list>)
@XmlTransient
Поле/геттер Исключает поле из сериализации
@XmlType
Класс Управляет порядком элементов, именем типа

7. Особенности и ограничения JAXB

Порядок элементов

По умолчанию JAXB может выводить элементы в алфавитном порядке. Чтобы явно задать порядок, используйте @XmlType и свойство propOrder:

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

Исключение полей

Чтобы не сериализовать поле/геттер, используйте @XmlTransient:

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

Проблемы с коллекциями

  • Не используйте «сырые» коллекции без дженериков: пишите List<Type>, а не List.
  • Если коллекция хранит объекты, их классы тоже должны быть аннотированы и иметь пустой конструктор.

Ошибки

  • Отсутствует пустой конструктор — получите JAXBException при анмаршалинге.
  • Неаннотированный вложенный класс — JAXB не сможет его сериализовать/десериализовать.
  • Нестандартные типы (например, LocalDate) требуют адаптера (@XmlJavaTypeAdapter).

8. Типичные ошибки при работе с JAXB

Ошибка №1: Отсутствует пустой конструктор. JAXB требует, чтобы у сериализуемого класса был публичный конструктор без параметров. Если его нет — при анмаршалинге возникнет исключение JAXBException.

Ошибка №2: Неаннотированные вложенные объекты. Если у вас есть поле-объект, но его класс не аннотирован @XmlRootElement или хотя бы @XmlType, JAXB не сможет корректно его сериализовать/десериализовать.

Ошибка №3: Проблемы с коллекциями. JAXB не понимает «сырые» коллекции без указания типа элементов. Используйте дженерики и корректно аннотируйте коллекции (@XmlElementWrapper + @XmlElement).

Ошибка №4: Неявное управление порядком элементов. Если порядок элементов в XML важен для интеграции, используйте @XmlType с propOrder; иначе JAXB может вывести элементы в ином порядке (например, по алфавиту).

Ошибка №5: Использование нестандартных типов без адаптера. JAXB не умеет сериализовать некоторые типы (например, LocalDate) без адаптера. Применяйте @XmlJavaTypeAdapter или сериализуйте значение как строку.

1
Задача
JAVA 25 SELF, 47 уровень, 3 лекция
Недоступна
Проектирование Книжной Записи для Цифровой Библиотеки 📖
Проектирование Книжной Записи для Цифровой Библиотеки 📖
1
Задача
JAVA 25 SELF, 47 уровень, 3 лекция
Недоступна
Загрузка Книги из XML в Приложение 📥
Загрузка Книги из XML в Приложение 📥
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
I'll kick them all Уровень 5
11 октября 2025

XML — это универсальный, человекочитаемый формат, который до сих пор широко используется 
для обмена данными между системами, конфигурирования и хранения информации.
среднестатистический pom.xml поспорит с человекочитаемым форматом =)