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