About Blaise Doughan

Team lead for the TopLink/EclipseLink JAXB & SDO implementations, and the Oracle representative on those specifications.

MOXy’s Object Graphs – Input/Output Partial Models to XML & JSON

Suppose you have a domain model that you want to expose as a RESTful service. The problem is you only want to input/output part of your data. Previously you would have created a separate model representing the subset and then have code to move data between the models. In EclipseLink 2.5.0 we have a new feature called Object Graphs that enables you to easily define partial views on your model.

You can try this out today by downloading an EclipseLink 2.5.0 nightly download starting on March 24, 2013 from:

 

Java Model

Below is the Java model that we will use for this example. The model represents customer data. We will use an object graph to output just enough information so that someone could contact the customer by phone.

Customer

The @XmlNamedObjectGraph extension is used to specify subsets of the model we wish to marshal/unmarshal. This is done by specifying one or more @XmlNamedAttributeNode annotations. If you want an object graph applied to a property you can specify a subgraph for it. The subgraph can either be defined as a @XmlNamedSubgraph or as a @XmlNamedObjectGraph on the target class.

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

Because we defined the object graph for the Address class as a subgraph on the Customer class there is nothing we need to do here.

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;

}

PhoneNumber

For the phoneNumbers property on the Customer class we specified that an object graph called simple should be used to scope the data. We will define this object graph on the PhoneNumber class. An advantage of this approach is that it makes the object graphs easier to be reused.

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;

}

Demo Code

Demo

In the demo code below we will read in an XML document to fully populate our Java model. After marshalling it out to prove that everything was fully mapped we will specify an object graph on the marshaler (line 22), and output a subset to both XML and JSON.

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/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 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 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>
   <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 Output Based on Object Graph

Below is the same subset as the previous XML document represented as JSON. We have used the new
JSON_WRAPPER_AS_ARRAY_NAME property (see Binding to JSON & XML – Handling Collections) to improve the representation of collection values.

{
   'name' : 'Jane Doe',
   'billingAddress' : {
      'city' : 'Any Town',
      'province' : 'Ontario'
   },
   'phoneNumbers' : [ '555-1111', '555-2222' ]
}

External Metadata

MOXy also offers an external binding document which allows you to provide metadata for third party objects or apply alternate mappings for your model (see: Mapping Object to Multiple XML Schemas – Weather Example). Below is the mapping document for this example.

<?xml version='1.0'?>
<xml-bindings xmlns='http://www.eclipse.org/eclipselink/xsds/persistence/oxm'
    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>

 

Reference: MOXy’s Object Graphs – Input/Output Partial Models to XML & JSON from our JCG partner Blaise Doughan at the Java XML & JSON Binding blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


+ 2 = nine



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close