Статьи

Графические объекты MOXy и динамический JAXB

JAXB (JSR-222) упрощает преобразование экземпляров классов вашего домена в / из XML. Реализация EclipseLink MOXy предлагает расширение, называемое Dynamic JAXB, где вместо реальных классов у вас есть экземпляры карты типа класса с именем DynamicEntity . Вы можете получить доступ к данным на вашем DynamicEntity, используя методы get и set, которые принимают имя свойства (то есть customer.get («адрес») и customer.set («имя», «Джейн Доу») . В этом посте мы сначала рассмотрим загружает динамический JAXBContext, основанный на внешнем файле сопоставления, затем мы демаршируем XML-документ в динамические сущности и, наконец, применим граф объектов, чтобы охватить результирующий вывод JSON.

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

Динамическая модель Java

В статической модели метаданные получаются из классов Java и дополняются любыми предоставленными метаданными (см .: JAXB — аннотации не требуются ). Поскольку в динамическом JAXB MOXy отсутствуют доменные классы, типы должны быть полностью определены метаданными. Это может быть сделано из схемы XML или как в этом примере с использованием внешнего документа сопоставления MOXy.

oxm.xml

Поскольку реальных классов Java нет, во внешнем документе отображения нам нужно указать каждое отображение и для каждого отображения тип свойства Java.

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version="1.0"?>
    package-name="blog.objectgraphs.dynamic">
    <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" type="java.lang.Integer"/>
                <xml-element java-attribute="name" type="java.lang.String"/>
                <xml-element java-attribute="billingAddress"
                    type="blog.objectgraphs.dynamic.Address"/>
                <xml-element java-attribute="shippingAddress"
                    type="blog.objectgraphs.dynamic.Address"/>
                <xml-element
                    java-attribute="phoneNumbers"
                    name="phoneNumber"
                    type="blog.objectgraphs.dynamic.PhoneNumber"
                    container-type="java.util.List">
                    <xml-element-wrapper/>
                </xml-element>
            </java-attributes>
        </java-type>
        <java-type name="Address">
            <java-attributes>
                <xml-element java-attribute="street" type="java.lang.String"/>
                <xml-element java-attribute="city" type="java.lang.String"/>
                <xml-element java-attribute="province" type="java.lang.String"/>
                <xml-element java-attribute="postalCode" type="java.lang.String"/>
            </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" type="java.lang.String"/>
                <xml-value java-attribute="value" type="java.lang.String"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

jaxb.properties

Файл jaxb.properties используется для указания провайдера JAXB. Для динамического JAXB содержимое этого файла немного отличается от обычного при использовании MOXy (сравните с Заданием EclipseLink MOXy в качестве вашего JAXB-провайдера ). Этот файл входит в тот же пакет, что и модель домена, так как здесь у нас есть модель виртуального домена, файл jaxb.properties будет единственным реальным элементом в пакете blog.objectgraphs.dynamic .

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

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

Ниже мы рассмотрим два разных подхода к использованию графов объектов.

Демонстрация — граф объектов, заданный метаданными

В демонстрационном коде ниже мы будем использовать граф объектов, который был определен во внешнем документе сопоставления. Граф объектов был определен для динамической модели точно так же, как и для соответствующей статической модели (см. Графы объектов MOXy — Частичные модели ввода / вывода в XML и JSON ). Единственное, что отличается тем, что объект, который мы получаем из вызова unmarshal, является экземпляром DynamicEntity, а не Customer .

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
package blog.objectgraphs.dynamic;
 
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.jaxb.MarshallerProperties;
 
public class DemoMetadata {
 
    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>(1);
        properties.put(JAXBContextProperties.OXM_METADATA_SOURCE,
            "blog/objectgraphs/dynamic/oxm.xml");
        JAXBContext jc = JAXBContext.newInstance("blog.objectgraphs.dynamic",
            DemoMetadata.class.getClassLoader(), properties);
 
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/blog/objectgraphs/dynamic/input.xml");
        DynamicEntity customer = (DynamicEntity) 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);
    }
 
}

Демо — Граф объектов, созданный программно

В демонстрационном коде ниже мы создадим граф объектов программно. Граф объектов был создан для динамической модели точно так же, как это было для соответствующей статической модели (см .: Объектные Gaphs MOXy — Частичные модели на лету в / из XML и JSON ). Отличие состоит в том, что мы использовали имя динамического объекта для создания графа объекта вместо класса, и мы получаем экземпляр DynamicEntity, а не Customer из вызова unmarshal.

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
42
43
44
45
46
47
48
49
50
51
package blog.objectgraphs.dynamic;
 
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.jaxb.JAXBHelper;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.ObjectGraph;
import org.eclipse.persistence.jaxb.Subgraph;
 
public class DemoRuntime {
 
    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>(1);
        properties.put(JAXBContextProperties.OXM_METADATA_SOURCE,
            "blog/objectgraphs/dynamic/oxm.xml");
        JAXBContext jc = JAXBContext.newInstance("blog.objectgraphs.dynamic",
            DemoMetadata.class.getClassLoader(), properties);
 
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/blog/objectgraphs/dynamic/input.xml");
        DynamicEntity customer = (DynamicEntity) unmarshaller.unmarshal(xml);
 
        // Output XML
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
 
        // Create the Object Graph
        ObjectGraph contactInfo = JAXBHelper.getJAXBContext(jc)
            .createObjectGraph("blog.objectgraphs.dynamic.Customer");
        contactInfo.addAttributeNodes("name");
        Subgraph location = contactInfo.addSubgraph("billingAddress");
        location.addAttributeNodes("city", "province");
        Subgraph simple = contactInfo.addSubgraph("phoneNumbers");
        simple.addAttributeNodes("value");
 
        // Output XML - Based on Object Graph
        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, contactInfo);
        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 и динамический JAXB от нашего партнера JCG Блейза Дафана в блоге Java XML & JSON Binding .