«1. Введение
Это вводная статья о JAXB (Java Architecture for XML Binding).
Сначала мы покажем, как преобразовывать объекты Java в XML и наоборот, а затем сосредоточимся на создании классов Java из схемы XML и наоборот с помощью подключаемого модуля JAXB-2 Maven.
2. Обзор
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, используя его атрибут имени @XmlType: определить порядок, в котором поля записываются в файле XML @XmlElement: определить фактическое имя элемента XML, которое будет использоваться @ XmlAttribute: определите, что поле id отображается как атрибут вместо элемента @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. Де-сортировка — преобразование XML в Java Object
Un-marshalling предоставляет клиентскому приложению возможность преобразовывать XML-данные в производные JAXB-объекты Java.
Давайте воспользуемся 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, как управлять конкретным типом.
Используя JAXB XmlAdapter, мы можем определить собственный код для преобразования неотображаемого класса в то, что может обрабатывать 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);
}
}
Мы используем формат даты «гггг-ММ-дд ЧЧ:мм:сс» для преобразования даты в строку при маршалинге и 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, используя новую дату формат «гггг-ММ-дд ЧЧ: мм: сс»:
<?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.baeldung.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/baeldung/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.