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

** 1. Вступление

**

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

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

2. Обзор

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

Плагин JAXB-2 Maven делегирует большую часть своей работы любому из двух предоставляемых JDK инструментов: XJC и http ://docs.oracle.com/javase/7/docs/technotes/tools/share/schemagen.html[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
}

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

  • имя корневого элемента XML получено из имени класса, и мы

также можно указать имя корневого элемента XML, используя его имя атрибут @ XmlType ** : определить порядок, в котором поля записываются в

XML-файл @ XmlElement ** : определить фактическое имя элемента XML, которое будет использоваться

  • определить поле идентификатора отображается как атрибут вместо элемента

  • аннотировать поля, которые мы не хотим включать в XML

Для получения более подробной информации о аннотации JAXB вы можете проверить следующую link .

4. Маршаллинг

Marshalling предоставляет клиентскому приложению возможность преобразовывать производное JAXB дерево объектов Java в данные 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. Un-сортировочных

Un-marshalling предоставляет клиентскому приложению возможность конвертировать данные 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__ для пользовательского маршалинга.

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

[source,java,gutter:,true]

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__ к нашей __Book__:

[source,java,gutter:,true]

@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, используя новый формат даты «гггг-мм-дд чч: мм: сс__»

[source,xml,gutter:,true]

<?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 Плагин +

**

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

Обратите внимание, что существует два фундаментальных подхода к созданию веб-сервисов: __Contract Last__ и __Contract First__. Для получения более подробной информации об этих подходах вы можете проверить следующие http://docs.spring.io/spring-ws/site/reference/html/why-contract-first.html[link].

====  **  7.1. Генерация Java-класса из XSD **

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

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

[source,xml,gutter:,true]

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

[source,xml,gutter:,true]

<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/generate-resources/jaxb__. Мы можем изменить каталог вывода, добавив элемент __outputDirectory__ в конфигурацию плагина. Мы также можем добавить элемент __clearOutputDir__ со значением false, чтобы предотвратить удаление файлов в этом каталоге.

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

[source,xml,gutter:,true]

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

В этом же плагине используется JSK-инструмент __Schemagen__. Это инструмент компиляции JAXB Binding, который может генерировать схему XSD из классов Java.

Чтобы Java-класс мог претендовать на кандидата в схему XSD, этот класс должен иметь аннотацию __ @ XmlType__.

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

[source,xml,gutter:,true]

<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. Мы можем указать другую папку __source__ для наших аннотированных классов JAXB, добавив элемент __source__ в конфигурацию плагина.

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

Когда мы собираем проект, он генерирует файл __user-gen.xsd__ в каталоге __src/main/resources__.

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

В этой статье мы рассмотрели вводные концепции JAXB. Для получения подробной информации, мы можем взглянуть на http://www.oracle.com/technetwork/articles/javase/index-140168.html[JAXB домашнюю страницу].

Мы можем найти исходный код этой статьи на https://github.com/eugenp/tutorials/tree/master/jaxb[GitHub].