Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/MOXy/ObjectGraphs/Metadata"

(New page: 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...)
 
(Demo Code)
 
(4 intermediate revisions by one other user not shown)
Line 13: Line 13:
  
 
<source lang="java">
 
<source lang="java">
package blog.objectgraphs.metadata;
+
package example.moxy.objectgraphs.metadata;
 
   
 
   
 
import java.util.List;
 
import java.util.List;
Line 62: Line 62:
  
 
<source lang="java">
 
<source lang="java">
package blog.objectgraphs.metadata;
+
package example.moxy.objectgraphs.metadata;
 
   
 
   
 
import javax.xml.bind.annotation.*;
 
import javax.xml.bind.annotation.*;
Line 85: Line 85:
  
 
<source lang="java">
 
<source lang="java">
package blog.objectgraphs.metadata;
+
package example.moxy.objectgraphs.metadata;
 
   
 
   
 
import javax.xml.bind.annotation.*;
 
import javax.xml.bind.annotation.*;
Line 106: Line 106:
 
   
 
   
 
}</source>
 
}</source>
 
 
  
 
== Demo Code ==
 
== Demo Code ==
Line 116: Line 114:
  
 
<source lang="java">
 
<source lang="java">
package blog.objectgraphs.metadata;
+
package example.moxy.objectgraphs.metadata;
 
   
 
   
 
import java.io.File;
 
import java.io.File;
Line 128: Line 126:
 
          
 
          
 
         Unmarshaller unmarshaller = jc.createUnmarshaller();
 
         Unmarshaller unmarshaller = jc.createUnmarshaller();
         File xml = new File("src/blog/objectgraphs/metadata/input.xml");
+
         File xml = new File("src/example/moxy/objectgraphs/metadata/input.xml");
 
         Customer customer = (Customer) unmarshaller.unmarshal(xml);
 
         Customer customer = (Customer) unmarshaller.unmarshal(xml);
 
          
 
          
Line 201: Line 199:
 
'''JSON Output Based on Object Graph'''
 
'''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.
+
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 [[EclipseLink/Examples/MOXy/JSON_CollectionProperties| MOXy/JSON Collection Properties]]) to improve the representation of collection values.
  
 
<source lang="java">
 
<source lang="java">
Line 212: Line 210:
 
   "phoneNumbers" : [ "555-1111", "555-2222" ]
 
   "phoneNumbers" : [ "555-1111", "555-2222" ]
 
}</source>
 
}</source>
 
 
  
 
== External Metadata ==
 
== External Metadata ==
Line 222: Line 218:
 
<?xml version="1.0"?>
 
<?xml version="1.0"?>
 
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
 
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
     package-name="blog.objectgraphs.metadata"
+
     package-name="example.moxy.objectgraphs.metadata"
 
     xml-accessor-type="FIELD">
 
     xml-accessor-type="FIELD">
 
     <java-types>
 
     <java-types>

Latest revision as of 16:48, 8 April 2013

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.


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 example.moxy.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 example.moxy.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 example.moxy.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 example.moxy.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/example/moxy/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 MOXy/JSON Collection Properties) 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="example.moxy.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>

Back to the top