W3docs

Java JAXB

Отображение XML на объекты Java и обратно с помощью аннотаций JAXB и Marshaller/Unmarshaller.

JAXB (Jakarta XML Binding, ранее Java Architecture for XML Binding) отображает объекты Java на XML и обратно без необходимости писать код разбора вручную. Вы аннотируете обычный класс, после чего передаёте его в Marshaller для получения XML или в Unmarshaller для чтения XML в объекты. JAXB входил в состав JDK (javax.xml.bind) вплоть до Java 8, был удалён в Java 11 и теперь поставляется как отдельная зависимость в пространстве имён jakarta.xml.bind. Аннотации и модель маршалинга/анмаршалинга одинаковы в обоих вариантах.

Эта глава охватывает что такое привязка JAXB, основные аннотации, как маршалировать объект в XML и анмаршалировать XML обратно, как отображаются коллекции, а также смену пространства имён между Java 8 и современной Java. JAXB — это binding API: в отличие от низкоуровневых парсеров DOM и SAX, рассмотренных ранее в этой части, вы никогда не работаете с деревом XML напрямую — вы работаете с обычными объектами Java.

Когда стоит использовать JAXB

Используйте JAXB, когда ваши данные уже имеют (или заслуживают) класс, а XML — лишь формат передачи или хранения:

  • Чтение и запись конфигурационных или документных файлов, где структура стабильна и известна заранее.
  • SOAP / устаревшие веб-сервисы, где контракт — это XML-схема, а классы генерируются автоматически.
  • Двустороннее преобразование — загрузка XML, изменение объекта и запись обратно без ручного разбора.

Используйте DOM или SAX, когда структура нерегулярна, вам нужны лишь несколько полей из большого документа или нет естественного класса для привязки. А если вы контролируете оба конца и вам нужен компактный формат данных, JSON с Jackson обычно легче, чем XML.

Главная идея: аннотации описывают отображение

Вы не пишете код, обходящий дерево XML. Вместо этого вы описываете с помощью аннотаций на классе, как его поля соответствуют элементам и атрибутам XML. JAXB читает эти аннотации во время выполнения и генерирует преобразование в обоих направлениях. POJO становится самодокументирующейся схемой.

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() {}
}

Основные аннотации

Небольшой набор аннотаций охватывает почти любое отображение. Они находятся в пакете jakarta.xml.bind.annotation (или javax.xml.bind.annotation в Java 8).

АннотацияНазначение
@XmlRootElementОтмечает класс как корень документа; задаёт имя внешнего элемента
@XmlElementОтображает поле/свойство на вложенный элемент
@XmlAttributeОтображает поле/свойство на атрибут его элемента
@XmlElementWrapperОборачивает коллекцию в содержащий элемент
@XmlTransientПолностью исключает поле из XML
@XmlAccessorTypeУправляет тем, что JAXB привязывает по умолчанию — поля или геттеры

Маршалинг: объект в XML

JAXBContext — это точка входа: создайте его для ваших корневых классов, затем запросите Marshaller. Маршаллер превращает граф объектов в XML. Установка JAXB_FORMATTED_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>

Анмаршалинг: XML в объект

Обратная операция симметрична: запросите у того же JAXBContext Unmarshaller и укажите ему источник — File, InputStream, Reader или StringReader. JAXB создаёт объект с помощью конструктора без аргументов и заполняет его из элементов и атрибутов.

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());  // 2018

JAXB недоступен в этой среде выполнения (это внешняя зависимость в современной Java), поэтому приведённый ниже рабочий пример демонстрирует тот же цикл маршалинга/анмаршалинга с использованием только встроенного в JDK DOM API. Концепция идентична: атрибут на корневом элементе, дочерние элементы для полей и обратный цикл к равному объекту.

java— editable, runs on the server

Что следует вынести из запуска:

  • Маршалированный XML помещает year как атрибут в <book>, а title и author — как дочерние элементы — именно такое разделение управляется @XmlAttribute и @XmlElement в реальном JAXB. Выбор аннотации определяет, что будет элементом, а что — атрибутом.
  • Корневой тег — book, о чём сообщает el.getTagName(). В JAXB это имя задаётся через @XmlRootElement(name = "book"); здесь — строка, переданная в createElement. В любом случае внешний элемент идентифицирует тип документа.
  • Маршалинг и анмаршалинг — зеркальные операции над одной и той же структурой: программа строит XML из Book, затем восстанавливает Book из этого XML. Marshaller и Unmarshaller JAXB — это именно такая пара, опирающаяся на один JAXBContext.
  • round-trip equal : true доказывает, что данные пережили преобразование без потерь — title, author и year вернулись без изменений. Корректная привязка не теряет данные — это именно то свойство, на которое вы рассчитываете, когда XML является форматом передачи данных.
  • Для чтения year обратно потребовался Integer.parseInt, потому что XML — это всё текст. JAXB скрывает это, автоматически преобразуя текст атрибутов и элементов в объявленный тип Java (int, LocalDate, BigDecimal); без него каждое поле — это строка, которую нужно разбирать вручную.

Отображение коллекций

List отображается на повторяющиеся элементы. По умолчанию каждый элемент называется по имени поля, что может дать плоский, трудночитаемый документ. @XmlElementWrapper добавляет содержащий элемент, чтобы элементы были сгруппированы — это распространённый, читаемый паттерн.

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

@XmlRootElement(name = "library")
public class Library {
    private List<Book> books;

    @XmlElementWrapper(name = "books") // outer <books> element
    @XmlElement(name = "book")         // each item is a <book>
    public List<Book> getBooks() { return books; }
    public void setBooks(List<Book> books) { this.books = books; }

    public Library() {}
}

С оберткой вывод получается аккуратно вложенным:

<library>
  <books>
    <book year="2018"><title>Effective Java</title>...</book>
    <book year="2008"><title>Clean Code</title>...</book>
  </books>
</library>

Уберите @XmlElementWrapper, и элементы <book> окажутся непосредственно под <library> без группирующего элемента — допустимо, но более плоско. Выбор между этими двумя вариантами — наиболее распространённое решение при отображении коллекций в JAXB.

Java 8 vs. современная Java: смена пространства имён

Главная ловушка — переименование пакета. В Java 8 API входит в поставку и находится в javax.xml.bind. Начиная с Java 11 он вынесен и находится в jakarta.xml.bind, подключаемом как зависимость.

Java 8Java 11+
Пакетjavax.xml.bindjakarta.xml.bind
В classpath?ВстроенДобавьте зависимость
Артефакт времени выполненияJDKorg.glassfish.jaxb:jaxb-runtime

Для сборки Maven на современной Java добавьте API и реализацию времени выполнения:

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

Практика

Практика
В JAXB в чём разница между аннотированием свойства с помощью @XmlElement и @XmlAttribute?
В JAXB в чём разница между аннотированием свойства с помощью @XmlElement и @XmlAttribute?

Смотрите также

  • Работа с XML в Java — обзор XML API и применимость каждого из них.
  • DOM-парсер и SAX-парсер — низкоуровневые альтернативы привязке.
  • Jackson — та же идея аннотирования и привязки, применённая к JSON.
Was this page helpful?