Статьи

Сделайте свой JAXB чище с помощью реализации MOXy

Принципиальным преимуществом использования JAXB при маршалинге и демаршаллинге XML является модель программирования. Просто аннотируйте несколько POJO и используйте JAXB API, и вы сможете легко сериализовать в XML и десериализовать из XML. Вам не нужно беспокоиться о специфике относительно того, как XML распределяется / разбирается. Все намного проще, чем альтернативы, такие как DOM и SAX.

Теперь данные в файлах XML имеют тенденцию быть иерархическими по своей природе. Например, рассмотрим этот XML-файл:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<person>
    <firstname>Barok</firstname>
    <lastname>Obama</lastname>
    <age>52</age>
    <car>
        <model>Green Ford Focus 1.4L</model>
    </car>
</person>

В этом случае у человека Барока Обамы есть автомобиль, который является Зеленым Фордом Фокусом. Здесь мы видим иерархические характеристики XML. Автомобиль под Лицом. В более изощренном примере у Человека может быть Автомобиль, у которого есть Автомобильное радио, с Усилителем, у которого есть Транзисторы и т. Д. Но давайте сейчас остановимся на нашем более простом случае. Предположим, мы хотим удалить этот XML-файл с помощью JAXB. Нам нужны все данные человека (имя, фамилия и т. Д.) И модель автомобиля, принадлежащего этому человеку. Мы создаем POJO Person и Car POJO и комментируем соответствующим образом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder={"name", "firstname", "lastname"})
public class Person {
    private String firstname;
    private String lastname;
    private int age;
    private Car car;
   
    public String getLastname() {
        return lastname;
    }
  
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
  
    public int getAge() {
        return age;
    }
  
    public void setAge(int age) {
        this.age = age;
    }
  
    public String getFirstname() {
        return firstname;
    }
   
    public void setFirstname(String name) {
        this.firstname = name;
    }
   
    public Car getCar() {
        return car;
    }
   
    public void setCar(Car car){
        this.car= car;
    }
}
01
02
03
04
05
06
07
08
09
10
11
public class Car {
    private String model;
      
    public String getModel() {
        return model;
    }
   
    public void setModel(String model){
        this.model = model;
    }
}

Чтобы разобраться в этом, мы просто делаем

1
2
3
4
5
6
public static void unmarshall() throws Exception {
    JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    Person person = (Person)unmarshaller.unmarshal(new File("Person.xml"));
    System.out.println("Perosn is=" +person.toString());
}

Все это кажется очень простым — особенно если учесть, что сущность Car даже не нуждается в каких-либо аннотациях! Однако, у Car есть только один атрибут, и может показаться излишним иметь класс POJO для чего-то, от чего мы хотим только один атрибут! Помните, что это простой пример, представьте, если иерархическая структура была намного глубже. Что-то вроде внешней сущности, содержащей сущность, которая содержала другую сущность, которая содержала даже другую сущность, и все, что мы хотели, — это внешняя сущность и один атрибут от самой глубокой вложенной сущности. По сути, это та же проблема, но просто еще более излишняя. Мы должны были бы обеспечить наличие класса POJO для всего в иерархии — даже для сущностей, от которых мы ничего не хотели. Никто не любит раздувать код. Так что мы можем сделать?

Ну, первое, что мы должны помнить, это то, что JAXB — это спецификация, для которой есть много реализаций (например, JaxMeAPI, MOXy, Metro). Если бы мы использовали эталонную реализацию JAXB (поставляется с JDK, мы мало что можем сделать). У нас должен быть автомобиль и человек POJO. Однако, если мы используем реализацию MOXy из EclipseLink, мы можем использовать некоторые из ее расширений, чтобы помочь нам. Более конкретно, мы можем использовать расширение MOXy @XmlPath, которое вдохновлено XPath.

Давайте посмотрим на это в действии. Вот обновленный человек POJO.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder={"name", "firstname", "lastname"})
public class Person {
    private String firstname;
    private String lastname;
    private int age;
   
    public String getLastname() {
        return lastname;
    }
  
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
  
    public int getAge() {
        return age;
    }
  
    public void setAge(int age) {
        this.age = age;
    }
  
    public String getFirstname() {
        return firstname;
    }
   
    public void setFirstname(String name) {
        this.firstname = name;
    }
   
    @XmlPath("car/model/text()")
    private String model;
  
    public String getModel() {
        return model;
    }
}

Так куда же девался автомобиль POJO? Ну, это удалено. Нам это больше не нужно. Пока-пока.
Используя аннотацию MOXy @XmlPath, нам не нужен автомобильный POJO. Эта аннотация находится в пакете org.eclipse.persistence.oxm.annotations, и получить ее в вашем classpath действительно просто. Если вы пользователь maven, просто добавьте:

1
2
3
4
5
<dependency>
    <groupid>org.eclipse.persistence</groupId>
    <artifactid>eclipselink</artifactId>
    <version>2.3.2</version>
</dependency>

Чтобы указать вашему JDK использовать MOXy для реализации JAXB во время выполнения, вы помещаете файл с именем
jaxb.properties в том же каталоге, что и ваши JAXB POJO. Он содержит одну строку:

1
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Чтобы убедиться, что вы используете реализацию MOXy, просто проверьте контекст JAXB:

1
2
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
System.out.println("jaxbContext is=" +jaxbContext.toString());

Вы должны увидеть что-то вроде:

1
jaxbContext is=org.eclipse.persistence.jaxb.JAXBContext@5e3974

После этого нет никаких изменений. Можно использовать точно такой же код демаршаллинга.
Одна из причин, почему мне действительно нравится это расширение, заключается в том, что оно означает меньше кода. Обычно это означает более чистый код и более понятный код. Это становится еще более очевидным в более сложных сценариях, где сущности намного глубже в иерархической структуре, чем этот простой пример. Неважно, если вы используете что-то вроде XJC для генерации ваших POJO, у вас все еще есть раздувание кода.

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

MOXy возвращает борьбу за чистоту обратно в JAXB, предоставляя возможность использовать выражения XPath для чего угодно в нашем XML-файле.

Примечание: MOXy только что был включен в качестве реализации JAXB для WebLogic 12c .

Рекомендации:

  1. МОКСИ страница проекта
  2. Блог Блеза Дафана
  3. Сделайте свой JAXB чище с помощью MOXy от нашего партнера JCG Алекса Стейвли в техническом блоге Дублина

Статьи по Теме :