In previous posts we have explored how object graphs can be defined through metadata and programatically. In this post I'll demonstrate the impact of inheritance in your domain model on how you define object graphs.
You can try this out today by downloading an EclipseLink 2.5.0 nightly download starting on March 24, 2013 from:
Java Model
The following domain model will be used for this example.
Customer
package blog.objectgraphs.inheritance; import java.util.*; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlNamedAttributeNode; import org.eclipse.persistence.oxm.annotations.XmlNamedObjectGraph; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) @XmlNamedObjectGraph( name = "simple", attributeNodes = { @XmlNamedAttributeNode(value="contactInfo", subgraph="simple") } ) public class Customer { private List<ContactInfo> contactInfo = new ArrayList<ContactInfo>(); }
ContactInfo
The @XmlNamedObjectGraph annotation is used to define the object graph for the root class, and @XmlNamedSubGraph is used to define the object graphs for the subclasses. We have indicated that we do not want to include any of the properties from the super class.
package blog.objectgraphs.inheritance; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.*; @XmlSeeAlso({Address.class, PhoneNumber.class}) @XmlAccessorType(XmlAccessType.FIELD) @XmlNamedObjectGraph( name = "simple", attributeNodes = { }, subclassSubgraphs = { @XmlNamedSubgraph( name = "simple", type = Address.class, attributeNodes = { @XmlNamedAttributeNode("city") } ), @XmlNamedSubgraph( name = "simple", type = PhoneNumber.class, attributeNodes = { @XmlNamedAttributeNode("number") } ) } ) public abstract class ContactInfo { private int id; }
Address
Address is a subclass of ContactInfo.
package blog.objectgraphs.inheritance; public class Address extends ContactInfo { private String street; private String city; }
PhoneNumber
PhoneNumber is also a subclass of ContactInfo.
package blog.objectgraphs.inheritance; public class PhoneNumber extends ContactInfo { private String number; private String extension; }
Demo Code
Below we will explore two different approaches for using object graphs.
Demo - Object Graph Specified through Metadata
In the demo code below we will leverage the object graphs that we defined via annotations to output a subset of the data to XML and JSON.
package blog.objectgraphs.inheritance; import java.io.File; import javax.xml.bind.*; import org.eclipse.persistence.jaxb.MarshallerProperties; public class DemoMetadata { 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/inheritance/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, "simple"); 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.marshal(customer, System.out); } }
Demo - Object Graph Created Programatically
package blog.objectgraphs.inheritance; import java.io.File; import javax.xml.bind.*; 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 { JAXBContext jc = JAXBContext.newInstance(Customer.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File("src/blog/objectgraphs/inheritance/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); // Create the Object Graph ObjectGraph simple = JAXBHelper.getJAXBContext(jc).createObjectGraph(Customer.class); Subgraph contactInfoSG = simple.addSubgraph("contactInfo", ContactInfo.class); Subgraph addressSG = simple.addSubgraph("contactInfo", Address.class); addressSG.addAttributeNodes("city"); Subgraph phoneNumberSG = simple.addSubgraph("contactInfo", PhoneNumber.class); phoneNumberSG.addAttributeNodes("number"); // Output XML - Based on Object Graph marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, simple); 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.marshal(customer, System.out); } }
Input/Output
The following input and output are the same for both the metadata driven and programmatic demos.
input.xml/Output
We will use the following document to populate our domain model. We will also marshal it back out to demonstrate that all of the content is actually mapped.
<?xml version="1.0" encoding="UTF-8"?> <customer> <contactInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="address"> <id>1</id> <street>1 A Street</street> <city>Any Town</city> </contactInfo> <contactInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="phoneNumber"> <id>2</id> <number>555-1111</number> <extension>123</extension> </contactInfo> </customer>
XML Output Based on Object Graph
The XML below was produced by the exact same model as the previous XML document. The difference is that we leveraged a named object graph to select a subset of the mapped content.
<?xml version="1.0" encoding="UTF-8"?> <customer> <contactInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="address"> <city>Any Town</city> </contactInfo> <contactInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="phoneNumber"> <number>555-1111</number> </contactInfo> </customer>
JSON Output Based on Object Graph
Below is the same subset as the previous XML document represented as JSON.
{ "contactInfo" : [ { "type" : "address", "city" : "Any Town" }, { "type" : "phoneNumber", "number" : "555-1111" } ] }
Further Reading
If you enjoyed this post then you may also be interested in:
- MOXy's Object Graphs - Input/Output Partial Models to XML & JSON
- MOXy's Object Graphs - Partial Models on the Fly to XML & JSON
- MOXy's Object Graphs & Dynamic JAXB
- Specifying EclipseLink MOXy as Your JAXB Provider
- JSON Binding with EclipseLink MOXy - Twitter Example
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.