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 .