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/Release/2.4.0/JSONBinding"

Line 321: Line 321:
 
</source>
 
</source>
 
</div>
 
</div>
 +
 +
The namespaces will be given the prefix from the Map separated by a dot:
  
 
<div style="width:850px">
 
<div style="width:850px">
<source lang="java">
+
<source lang="xml">
 
{
 
{
 
   "ns1.employee : {
 
   "ns1.employee : {

Revision as of 15:03, 14 June 2012

Object-to-JSON Binding Layer

Overview

New in EclipseLink 2.4 is support for converting objects to and from JSON. This can be useful when creating RESTful services, as JAX-RS services often accept both XML (application/xml) and JSON (application/json) messages.


Same Flexibility as Object-to-XML Mapping

JSON binding is compatible with most existing MOXy extensions. This includes:

  • External bindings file
  • Dynamic JAXB
  • Extensible models


XML and JSON Messages with One Set of Mappings

Both an XML message such as:

<foo id="123">
   <bar>Hello World</bar>
</foo>

and a JSON message such as:

{
   "foo" : {
      "id" : 123,
      "bar : "Hello World"
   }
}

can be supported by a single object model:

@XmlRootElement
public class Foo {
 
   @XmlAttribute
   private int id;
 
   @XmlElement
   private String bar;
 
}


No Additional Compile-Time Dependencies

JSON binding does not require any additional compile-time dependencies above and beyond what is required for normal JAXB usage.


Easy to Use with JAX-RS

EclipseLink JSON support makes it easy to implement MessageBodyReader and MessageBodyWriter classes for use with RESTful web services.


Marshalling and Unmarshalling with JSON

Adapting your application to produce and consume JSON is as easy as setting a property on your JAXB Marshaller or Unmarshaller:

import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.oxm.MediaType;
 
...
 
Marshaller m = jaxbContext.createMarshaller();
m.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
 
Unmarshaller u = jaxbContext.createUnmarshaller();
u.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
 
...

The MEDIA_TYPE property can also be specified in the Map of properties used during creation of the JAXBContext. In this case, Marshallers and Unmarshallers created from that context will automatically use the specified media type:

Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
 
JAXBContext ctx = JAXBContext.newInstance(new Class[] { Employee.class }, properties);
Marshaller jsonMarshaller = ctx.createMarshaller();
Unmarshaller jsonUnmarshaller = ctx.createUnmarshaller();


JSON Data Types

XML has one datatype, text, whereas JSON differentiates between strings, numbers, and booleans. MOXy supports these datatypes automatically:

@XmlRootElement
public class Address {
 
   @XmlElement
   private int id;
   @XmlElement
   private String city;
   @XmlElement
   private boolean isMailingAddress;
 
}
{
   "address": {
      "id" : 1,
      "city" : "Ottawa",
      "isMailingAddress" : true
   }
}


Attributes

JSON doesn't have the concept of attributes, so by default anything mapped as an @XmlAttribute will be marshalled as an element. During unmarshal, elements will trigger both the attribute and element events, to allow either the mapped attribute or element to handle the value. If there is an element and attribute with the same name, this will cause problems.

Users will be able to override the default behavior by providing an attribute prefix, which will be prepended to the attribute name during marshal, and recognized during unmarshal. In the example below the number field is mapped as an attribute.

jsonUnmarshaller.setProperty(UnmarshallerProperties.JSON_ATTRIBUTE_PREFIX, "@");
jsonMarshaller.setProperty(MarshallerProperties.JSON_ATTRIBUTE_PREFIX, "@") ;
{
   "phone" : {
      "area-code" : "613",
      "@number" : "1234567"
   }
}

The JSON_ATTRIBUTE_PREFIX property can also be specified in the Map of properties used during creation of the JAXBContext. In this case, Marshallers and Unmarshallers created from that context will automatically use the specified prefix:

Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.JSON_ATTRIBUTE_PREFIX, "@");
 
JAXBContext ctx = JAXBContext.newInstance(new Class[] { Phone.class }, properties);


Support for No "Root Element"

JSON supports documents with no root element:

{
   "area-code" : "613",
   "number" : "1234567"
}

As opposed to the corresponding JSON with a root element "phone":

{
   "phone": {
      "area-code" : "613",
      "number" : "1234567"
   }
}

Marshal

During marshal, if no @XmlRootElement annotation is present, then the marshalled JSON document will not have a root element. If @XmlRootElement is specified, the root element can be omitted from the JSON output by setting the following property on the JAXB Marshaller:

marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);

Unmarshal

By default it will be assumed that the document has a root element. If your documents do not contain root elements, you should set the following property on your Unmarshaller. Also note that if there is no root element, you must specify the Class being unmarshalled to.

unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
JAXBElement<SearchResults> jaxbElement = unmarshaller.unmarshal(source, SearchResults.class);


Collections

By default, when marshalling to JSON, empty collections are marshalled as [ ]:

{
   "phone" : {
      "myList" : [ ]
   }
}

The JSON_MARSHAL_EMPTY_COLLECTIONS Marshaller property can be set to false to change this behavior so that empty collections are not marshalled at all:

 jsonMarshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, Boolean.FALSE) ;
{
   "phone" : {
   }
}

Root-Level Collections

JSON documents can have root level lists. If a class Root has an @XmlRootElement(name="root")' specified, we could marshal as follows:

marshaller.marshal(myListOfRoots, System.out);
[ {
   "root" : {
      "name" : "aaa"
   }
}, {
   "root" : {
      "name" : "bbb"
   }
} ]

Since the root element is present in the document, we can unmarshal using:

unmarshaller.unmarshal(json);

If Root does not have an @XmlRootElement, or if JSON_INCLUDE_ROOT has been set to false, the marshal would give this output:

[ {
   "name":"aaa"
}, {
   "name":"bbb"
} ]

Since the root element is not present, we would need to provide the class to unmarshal to:

unmarshaller.unmarshal(json, Root.class);


Namespaces

JSON doesn't have the concept of namespaces, and by default namespaces/prefixes will be ignored during marshal and unmarshal operations. This default behavior could be a problem if there are multiple mappings with the same local name in different namespaces as there would be no way to distinguish between those mappings.

In this case, the user can supply Map of namespace->prefix (or an instance of NamespacePrefixMapper) to the Marshaller and Unmarshaller, and namespace prefixes will appear in the marshalled document, prepended to the element name. This prefix will be recognized during unmarshal, and the resulting Java objects will be placed in the proper namespaces.

Map<String, String> namespaces = new HashMap<String, String>();
namespaces.put("namespace1", "ns1");
namespaces.put("namespace2", "ns2");
jsonMarshaller.setProperty(MarshallerProperties.JSON_NAMESPACE_PREFIX_MAPPER, namespaces);
jsonUnmarshaller.setProperty(UnmarshallerProperties.JSON_NAMESPACE_PREFIX_MAPPER, namespaces);

The namespaces will be given the prefix from the Map separated by a dot:

{
   "ns1.employee : {
      "ns2.id" : 123
   }
}

Note that NAMESPACE_PREFIX_MAPPER only comes into play during unmarshal if the media type is set to JSON; XML unmarshalling can obtain the namespace information from the document itself.


Unsupported MOXy/JAXB Annotations

The following annotations are not applicable to JSON:

XmlAttributeRef XmlMimeType XmlMixed XmlNs
XmlNsForm XmlSchema XmlProperties XmlProperty
XmlVirtualAccessMethods XmlVirtualAccessMethodsSchema XmlIsSetNullPolicy XmlJoinNodes
XmlMarshalNullRepresentation XmlNullPolicy XmlParameter XmlPath
XmlPaths XmlCDATA

Back to the top