Перейти к основному содержимому

Руководство по JAXB

· 7 мин. чтения

1. Обзор

Это вводное руководство по JAXB (архитектура Java для привязки XML).

Сначала мы покажем, как преобразовывать объекты Java в XML и наоборот.

Затем мы сосредоточимся на создании классов Java из схемы XML и наоборот с помощью подключаемого модуля JAXB-2 Maven.

2. Введение в JAXB

JAXB обеспечивает быстрый и удобный способ маршалирования (записи) объектов Java в XML и демаршалирования (чтения) XML в объекты. Он поддерживает структуру привязки, которая сопоставляет элементы и атрибуты XML с полями и свойствами Java с помощью аннотаций Java.

Плагин JAXB-2 Maven делегирует большую часть своей работы одному из двух инструментов, поставляемых JDK, XJC и Schemagen .

3. Аннотации JAXB

JAXB использует аннотации Java для дополнения сгенерированных классов дополнительной информацией. Добавление таких аннотаций к существующим классам Java подготавливает их к среде выполнения JAXB.

Давайте сначала создадим простой объект Java, чтобы проиллюстрировать маршалинг и демаршаллинг:

@XmlRootElement(name = "book")
@XmlType(propOrder = { "id", "name", "date" })
public class Book {
private Long id;
private String name;
private String author;
private Date date;

@XmlAttribute
public void setId(Long id) {
this.id = id;
}

@XmlElement(name = "title")
public void setName(String name) {
this.name = name;
}

@XmlTransient
public void setAuthor(String author) {
this.author = author;
}

// constructor, getters and setters
}

Приведенный выше класс содержит следующие аннотации:

  • @XmlRootElement : имя корневого элемента XML происходит от имени класса, и мы также можем указать имя корневого элемента XML, используя его атрибут name.
  • @XmlType : определите порядок, в котором поля записываются в файле XML.
  • @XmlElement : определите фактическое имя элемента XML, которое будет использоваться.
  • @XmlAttribute : определите, что поле идентификатора отображается как атрибут, а не как элемент.
  • @XmlTransient : аннотировать поля, которые мы не хотим включать в XML

Подробнее об аннотации JAXB можно узнать по этой ссылке .

4. Маршаллинг — преобразование объекта Java в XML

Маршаллинг дает клиентскому приложению возможность преобразовывать дерево объектов Java, полученное из JAXB, в данные XML. По умолчанию Marshaller использует кодировку UTF-8 при создании XML-данных. Далее мы создадим файлы XML из объектов Java.

Давайте создадим простую программу, используя JAXBContext , которая обеспечивает абстракцию для управления информацией о привязке XML/Java, необходимой для реализации операций структуры привязки JAXB:

public void marshal() throws JAXBException, IOException {
Book book = new Book();
book.setId(1L);
book.setName("Book1");
book.setAuthor("Author1");
book.setDate(new Date());

JAXBContext context = JAXBContext.newInstance(Book.class);
Marshaller mar= context.createMarshaller();
mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
mar.marshal(book, new File("./book.xml"));
}

Класс javax.xml.bind.JAXBContext обеспечивает точку входа клиента в JAXB API. По умолчанию JAXB не форматирует XML-документ. Это экономит место и предотвращает случайную интерпретацию любого пробела как значимого.

Чтобы JAXB форматировал выходные данные, мы просто устанавливаем для свойства Marshaller.JAXB_FORMATTED_OUTPUT значение true в Marshaller . Метод маршала использует объект и выходной файл для хранения сгенерированного XML в качестве параметров.

Когда мы запускаем приведенный выше код, мы можем проверить результат в book.xml , чтобы убедиться, что мы успешно преобразовали объект Java в данные XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<book id="1">
<title>Book1</title>
<date>2016-11-12T11:25:12.227+07:00</date>
</book>

5. Unmarshalling — преобразование XML в объект Java

Разупорядочение дает клиентскому приложению возможность преобразовывать данные XML в объекты Java, производные от JAXB.

Давайте воспользуемся JAXB Unmarshaller , чтобы преобразовать наш book.xml обратно в объект Java:

public Book unmarshall() throws JAXBException, IOException {
JAXBContext context = JAXBContext.newInstance(Book.class);
return (Book) context.createUnmarshaller()
.unmarshal(new FileReader("./book.xml"));
}

Когда мы запускаем приведенный выше код, мы можем проверить вывод консоли, чтобы убедиться, что мы успешно преобразовали данные XML в объект Java:

Book [id=1, name=Book1, author=null, date=Sat Nov 12 11:38:18 ICT 2016]

6. Сложные типы данных

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

Для этого мы будем использовать XmlAdapter JAXB для определения пользовательского кода для преобразования неотображаемого класса во что-то, что JAXB может обработать. В аннотации @XmlJavaTypeAdapter используется адаптер, который расширяет класс XmlAdapter для пользовательской сортировки.

Давайте создадим адаптер для указания формата даты при маршаллинге:

public class DateAdapter extends XmlAdapter<String, Date> {

private static final ThreadLocal<DateFormat> dateFormat
= new ThreadLocal<DateFormat>() {

@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};

@Override
public Date unmarshal(String v) throws Exception {
return dateFormat.get().parse(v);
}

@Override
public String marshal(Date v) throws Exception {
return dateFormat.get().format(v);
}
}

Мы используем формат даты yyyy-MM-dd HH:mm:ss для преобразования Date в String при сортировке и ThreadLocal , чтобы сделать наш DateFormat потокобезопасным.

Давайте применим DateAdapter к нашей книге :

@XmlRootElement(name = "book")
@XmlType(propOrder = { "id", "name", "date" })
public class Book {
private Long id;
private String name;
private String author;
private Date date;

@XmlAttribute
public void setId(Long id) {
this.id = id;
}

@XmlTransient
public void setAuthor(String author) {
this.author = author;
}

@XmlElement(name = "title")
public void setName(String name) {
this.name = name;
}

@XmlJavaTypeAdapter(DateAdapter.class)
public void setDate(Date date) {
this.date = date;
}
}

Когда мы запускаем приведенный выше код, мы можем проверить результат в book.xml , чтобы убедиться, что мы успешно преобразовали наш объект Java в XML, используя новый формат даты yyyy-MM-dd HH:mm:ss :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<book id="1">
<title>Book1</title>
<date>2016-11-10 23:44:18</date>final
</book>

7. Плагин JAXB-2 Maven

Этот подключаемый модуль использует API Java для привязки XML (JAXB), версия 2+, для создания классов Java из схем XML (и, возможно, файлов привязки) или для создания схемы XML из аннотированного класса Java.

Обратите внимание, что существует два основных подхода к созданию веб-сервисов: Contract Last и Contract First . Подробнее об этих подходах читайте по этой ссылке .

7.1. Создание класса Java из XSD

Подключаемый модуль JAXB-2 Maven использует предоставленный JDK инструмент XJC, инструмент компилятора привязки JAXB, который генерирует классы Java из XSD (определение схемы XML).

Давайте создадим простой файл user.xsd и воспользуемся подключаемым модулем JAXB-2 Maven для создания классов Java из этой схемы XSD:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="/jaxb/gen"
xmlns:userns="/jaxb/gen"
elementFormDefault="qualified">

<element name="userRequest" type="userns:UserRequest"></element>
<element name="userResponse" type="userns:UserResponse"></element>

<complexType name="UserRequest">
<sequence>
<element name="id" type="int" />
<element name="name" type="string" />
</sequence>
</complexType>

<complexType name="UserResponse">
<sequence>
<element name="id" type="int" />
<element name="name" type="string" />
<element name="gender" type="string" />
<element name="created" type="dateTime" />
</sequence>
</complexType>
</schema>

Давайте настроим плагин JAXB-2 Maven:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<xjbSources>
<xjbSource>src/main/resources/global.xjb</xjbSource>
</xjbSources>
<sources>
<source>src/main/resources/user.xsd</source>
</sources>
<outputDirectory>${basedir}/src/main/java</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>

По умолчанию этот плагин находит файлы XSD в src/main/xsd . Мы можем настроить поиск XSD, соответствующим образом изменив раздел конфигурации этого плагина в pom.xml .

Также по умолчанию эти классы Java генерируются в папке target/generated-resources/jaxb . Мы можем изменить выходной каталог, добавив элемент outputDirectory в конфигурацию плагина. Мы также можем добавить элемент clearOutputDir со значением false, чтобы предотвратить стирание файлов в этом каталоге.

Кроме того, мы можем настроить глобальную привязку JAXB, которая переопределяет правила привязки по умолчанию:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
jaxb:extensionBindingPrefixes="xjc">

<jaxb:globalBindings>
<xjc:simple />
<xjc:serializable uid="-1" />
<jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
parse="javax.xml.bind.DatatypeConverter.parseDateTime"
print="javax.xml.bind.DatatypeConverter.printDateTime" />
</jaxb:globalBindings>
</jaxb:bindings>

Приведенный выше файл global.xjb переопределяет тип dateTime на тип java.util.Calendar .

Когда мы собираем проект, он создает файлы классов в папке src/main/java и пакет com.foreach.jaxb.gen .

7.2. Создание схемы XSD из Java

Этот же плагин использует инструмент Schemagen из JDK . Это инструмент компилятора JAXB Binding, который может генерировать схему XSD из классов Java. Чтобы класс Java соответствовал требованиям кандидата схемы XSD, класс должен быть снабжен аннотацией @XmlType .

Мы будем повторно использовать файлы классов Java из предыдущего примера для настройки плагина:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>schemagen</id>
<goals>
<goal>schemagen</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<source>src/main/java/com/foreach/jaxb/gen</source>
</sources>
<outputDirectory>src/main/resources</outputDirectory>
<clearOutputDir>false</clearOutputDir>
<transformSchemas>
<transformSchema>
<uri>/jaxb/gen</uri>
<toPrefix>user</toPrefix>
<toFile>user-gen.xsd</toFile>
</transformSchema>
</transformSchemas>
</configuration>
</plugin>

По умолчанию JAXB рекурсивно сканирует все папки в папке src/main/java на наличие аннотированных классов JAXB. Мы можем указать другую исходную папку для наших JAXB-аннотированных классов, добавив исходный элемент в конфигурацию плагина.

Мы также можем зарегистрировать transformSchemas , постпроцессор, отвечающий за присвоение имени XSD-схеме. Он работает, сопоставляя пространство имен с пространством имен @XmlType нашего класса Java.

Когда мы собираем проект, он создает файл user-gen.xsd в каталоге src/main/resources .

8. Заключение

В этой статье мы рассмотрели вводные концепции JAXB. Для получения более подробной информации посетите домашнюю страницу JAXB .

Мы можем найти исходный код этой статьи на GitHub .