Статьи

Графы объектов MOXy — частичные модели ввода / вывода в XML и JSON

Предположим, у вас есть модель домена, которую вы хотите предоставить в качестве службы RESTful. Проблема в том, что вы хотите вводить / выводить только часть ваших данных. Ранее вы бы создали отдельную модель, представляющую подмножество, а затем имели бы код для перемещения данных между моделями. В EclipseLink 2.5.0 у нас есть новая функция, которая называется Object Graphs, которая позволяет вам легко определять частичные виды вашей модели.

Вы можете попробовать это сегодня, загрузив ночную загрузку EclipseLink 2.5.0, начиная с 24 марта 2013 года, из:

Модель Java

Ниже приведена модель Java, которую мы будем использовать для этого примера. Модель представляет данные клиента. Мы будем использовать граф объектов для вывода достаточно информации, чтобы кто-то мог связаться с клиентом по телефону.

Клиент

Расширение @XmlNamedObjectGraph используется для указания подмножеств модели, которую мы хотим маршалировать / демаршалировать. Это делается путем указания одной или нескольких аннотаций @XmlNamedAttributeNode . Если вы хотите, чтобы к объекту применялся граф объектов, вы можете указать для него подграф. Подграф может быть определен как @XmlNamedSubgraph или как @XmlNamedObjectGraph в целевом классе.

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
package blog.objectgraphs.metadata;
 
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
 
@XmlNamedObjectGraph(
    name='contact info',
    attributeNodes={
        @XmlNamedAttributeNode('name'),
        @XmlNamedAttributeNode(value='billingAddress', subgraph='location'),
        @XmlNamedAttributeNode(value='phoneNumbers', subgraph='simple')
    },
    subgraphs={
        @XmlNamedSubgraph(
            name='location',
            attributeNodes = {
                @XmlNamedAttributeNode('city'),
                @XmlNamedAttributeNode('province')
            }
        )
    }
)
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
 
    @XmlAttribute
    private int id;
 
    private String name;
 
    private Address billingAddress;
 
    private Address shippingAddress;
 
    @XmlElementWrapper
    @XmlElement(name='phoneNumber')
    private List<PhoneNumber> phoneNumbers;
 
}

Адрес

Поскольку мы определили граф объектов для класса Address как подграф класса Customer, нам здесь ничего не нужно делать.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
package blog.objectgraphs.metadata;
 
import javax.xml.bind.annotation.*;
 
@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
 
    private String street;
 
    private String city;
 
    private String province;
 
    private String postalCode;
 
}

Номер телефона

Для свойства phoneNumbers в классе Customer мы указали, что для охвата данных должен использоваться граф объектов с именем simple . Мы определим этот граф объектов в классе PhoneNumber . Преимущество этого подхода состоит в том, что он облегчает повторное использование графов объектов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package blog.objectgraphs.metadata;
 
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
 
@XmlNamedObjectGraph(
    name='simple',
    attributeNodes={
        @XmlNamedAttributeNode('value'),
    }
)
@XmlAccessorType(XmlAccessType.FIELD)
public class PhoneNumber {
 
    @XmlAttribute
    private String type;
 
    @XmlValue
    private String value;
 
}

Демонстрационный код

демонстрация

В демонстрационном коде ниже мы будем читать документ XML, чтобы полностью заполнить нашу модель Java. После того, как вы раскроете его, чтобы доказать, что все полностью отображено, мы определим граф объектов на маршалере (строка 22) и выведем подмножество в XML и JSON.

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
package blog.objectgraphs.metadata;
 
import java.io.File;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
 
public class Demo {
 
    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);
 
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File('src/blog/objectgraphs/metadata/input.xml');
        Customer customer = (Customer) unmarshaller.unmarshal(xml);
 
        // Output XML
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
 
        // Output XML - Based on Object Graph
        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, 'contact info');
        marshaller.marshal(customer, System.out);
 
        // Output JSON - Based on Object Graph
        marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, 'application/json');
        marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
        marshaller.setProperty(MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
        marshaller.marshal(customer, System.out);
    }
 
}

Input.xml / выход

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<?xml version='1.0' encoding='UTF-8'?>
<customer id='123'>
   <name>Jane Doe</name>
   <billingAddress>
      <street>1 A Street</street>
      <city>Any Town</city>
      <province>Ontario</province>
      <postalCode>A1B 2C3</postalCode>
   </billingAddress>
   <shippingAddress>
      <street>2 B Road</street>
      <city>Another Place</city>
      <province>Quebec</province>
      <postalCode>X7Y 8Z9</postalCode>
   </shippingAddress>
   <phoneNumbers>
      <phoneNumber type='work'>555-1111</phoneNumber>
      <phoneNumber type='home'>555-2222</phoneNumber>
   </phoneNumbers>
</customer>

Вывод XML на основе графов объектов

Приведенный ниже XML был создан точно такой же моделью, что и предыдущий документ XML. Разница в том, что мы использовали граф именованных объектов, чтобы выбрать подмножество отображаемого содержимого.

01
02
03
04
05
06
07
08
09
10
11
12
<?xml version='1.0' encoding='UTF-8'?>
<customer>
   <name>Jane Doe</name>
   <billingAddress>
      <city>Any Town</city>
      <province>Ontario</province>
   </billingAddress>
   <phoneNumbers>
      <phoneNumber>555-1111</phoneNumber>
      <phoneNumber>555-2222</phoneNumber>
   </phoneNumbers>
</customer>

Вывод JSON на основе графов объектов

Ниже приведено то же подмножество, что и в предыдущем документе XML, представленном как JSON. Мы использовали новый
Свойство JSON_WRAPPER_AS_ARRAY_NAME (см.
Привязка к JSON и XML — Обработка коллекций ) для улучшения представления значений коллекций.

1
2
3
4
5
6
7
8
{
   'name' : 'Jane Doe',
   'billingAddress' : {
      'city' : 'Any Town',
      'province' : 'Ontario'
   },
   'phoneNumbers' : [ '555-1111', '555-2222' ]
}

Внешние метаданные

MOXy также предлагает внешний документ связывания, который позволяет вам предоставлять метаданные для сторонних объектов или применять альтернативные сопоставления для вашей модели (см .: Отображение объекта на несколько схем XML — Пример погоды ). Ниже приведен документ сопоставления для этого примера.

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
<?xml version='1.0'?>
    package-name='blog.objectgraphs.metadata'
    xml-accessor-type='FIELD'>
    <java-types>
        <java-type name='Customer'>
            <xml-named-object-graphs>
                <xml-named-object-graph name='contact info'>
                    <xml-named-attribute-node name='name'/>
                    <xml-named-attribute-node name='billingAddress' subgraph='location'/>
                    <xml-named-attribute-node name='phoneNumbers' subgraph='simple'/>
                    <xml-named-subgraph name='location'>
                        <xml-named-attribute-node name='city'/>
                        <xml-named-attribute-node name='province'/>
                    </xml-named-subgraph>
                </xml-named-object-graph>
            </xml-named-object-graphs>
            <xml-root-element/>
            <java-attributes>
                <xml-attribute java-attribute='id'/>
                <xml-element java-attribute='phoneNumbers' name='phoneNumber'>
                    <xml-element-wrapper/>
                </xml-element>
            </java-attributes>
        </java-type>
        <java-type name='PhoneNumber'>
            <xml-named-object-graphs>
                <xml-named-object-graph name='simple'>
                    <xml-named-attribute-node name='value'/>
                </xml-named-object-graph>
            </xml-named-object-graphs>
            <java-attributes>
                <xml-attribute java-attribute='type'/>
                <xml-value java-attribute='value'/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

Ссылка: объектные графики MOXy — частичные модели ввода / вывода в XML и JSON от нашего партнера по JCG Блэза Дафана из блога Java XML & JSON Binding .