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" ]} |