Oracle WebLogic 12.1.2 Now With EclipseLink MOXy JSON-Binding
Join the DZone community and get the full member experience.
Join For FreeOracle WebLogic 12.1.2 is now available. WebLogic 12.1.2 contains EclipseLink 2.4.2, this means that for the first time EclipseLink MOXy's
JSON-binding is available in WebLogic out of the box. I will
demonstrate the benefits of using MOXy for JSON-binding with an example.
Java Model
Below is the Java
model we will use for this post. The same metadata will be used to
customize the XML and JSON produced by our JAX-RS service. The get/set methods have been omitted to save space.
Customer
Below is a simple representation of a customer. I have annotated a couple of the fields with MOXy's @XmlPath extension (see: XPath Based Mapping) to demonstrate where MOXy is really being used.
package org.example.model; import java.util.*; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlPath; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlAttribute(name="id") private int identifier; @XmlPath("personalInfo/firstName/text()") private String firstName; @XmlPath("personalInfo/lastName/text()") @XmlElement(nillable=true) private String lastName; @XmlElementWrapper @XmlElement(name="phoneNumber") private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>(); }
PhoneNumber
We will map the PhoneNumber class to a complex type with simple content (see: JAXB and Complex Types with Simple Content) to see the impact on JSON-binding.
package org.example.model; import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) public class PhoneNumber { @XmlAttribute private String type; @XmlValue private String value; }
package-info
We will leverage the package level @XmlSchema annotation to namespace qualify the resulting XML (see: JAXB & Namespaces) so that we can see the impact on the JSON representation.
@XmlSchema( namespace="http://www.example.org/model", elementFormDefault=XmlNsForm.QUALIFIED) package org.example.model; import javax.xml.bind.annotation.*;
RESTful Service
CustomerResource
Normally a real service will be backed by JPA to do persistence operations (see: Creating a RESTful Web Service - Part 4/5). But for this post I will use a "Hello World" style service that returns a Customer based on an ID as XML and JSON to illustrate some points about binding.
package org.example.service; import javax.ejb.*; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import org.example.model.*; @Stateless @LocalBean @Path("/customers") public class CustomerResource { @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("{id}") public Customer read(@PathParam("id") int id) { Customer customer = new Customer(); customer.setId(id); customer.setFirstName("Jane"); customer.setLastName(null); PhoneNumber pn = new PhoneNumber(); pn.setType("work"); pn.setValue("5551111"); customer.getPhoneNumbers().add(pn); return customer; } }
CustomerApplication
MOXy is configured as the JSON-binding provider using the MOXyJsonProvider class via a JAX-RS Application class (see: MOXy as your JAX-RS JSON Provider - MOXyJsonProvider). MOXyJsonProvider offers different settings you can use to customize the JSON representation. In this example we will leverage the wrapperAsArrayName property to clean up the representation of collections (see: Binding to JSON & XML - Handling Collections).
package org.example.service; import java.util.*; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider; @ApplicationPath("rest/*") public class CustomerApplication extends Application { @Override public Set<Class<?>> getClasses() { HashSet<Class<?>> set = new HashSet<Class<?>>(1); set.add(CustomerResource.class); return set; } @Override public Set<Object> getSingletons() { MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider(); moxyJsonProvider.setWrapperAsArrayName(true); HashSet<Object> set = new HashSet<Object>(1); set.add(moxyJsonProvider); return set; } }
Output
We will examine the output we get from calling our service with the following URL using the application/xml and application/json media types.
http://localhost:7001/CustomerResource/rest/customers/1
XML
Below is a sample
of the XML output. It isn't a surprise as it exactly matches the JAXB
and MOXy metadata that we applied to our model.
<?xml version="1.0" encoding="UTF-8"?> <customer xmlns="http://www.example.org/model" id="1"> <personalInfo> <firstName>Jane</firstName> <lastName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/> </personalInfo> <phoneNumbers> <phoneNumber type="work">5551111</phoneNumber> </phoneNumbers> </customer>
Note the following XML specific things about this output.
- There is a root element (line 2).
- The XML is namespace qualified. (line 3).
- There are XML attributes (lines 3 & 10).
- The id attribute contains a int value (line 3).
- The xsi:nil attribute is used to indicate that the lastName element contains a null value. (lines 6 & 7).
- There are a collection of phoneNumber elements with a grouping element called phoneNumbers (lines 9-11).
JSON
Below is the JSON response when MOXy's JSON-binding is used by leveraging MOXyJsonProvider. It was produced using the exact same metadata as the XML representation, but all the XML specific items are gone and JSON specific items are used instead.
{ "id": 1, "personalInfo": { "firstName": "Jane", "lastName": null }, "phoneNumbers": [ { "type": "work", "value": "5551111" } ] }
Now lets compare
the JSON output with what WebLogic would have produced by default. By
default WebLogic uses its JAXB implementation with an intermediate
library to convert XML events to/from JSON. Since MOXy is the default
JAXB implementation in WebLogic the @XmlPath annotation is applied, but we don't get any of the other benefits from MOXy's JSON-binding.
{ "@id": "1", "personalInfo": { "firstName": "Jane", "lastName": { "@nil": "true" } }, "phoneNumbers": { "phoneNumber": { "@type": "work", "$": "5551111" } } }
Below are some of
the problems that we see with the default representation that weren't
present when we used MOXy's JSON-binding. They are all due to the XML
representation leaking into the JSON representation.
- Keys that correspond to properties mapped with @XmlAttribute are prefixed with @ (lines 2 & 11).
- The int value for the id property is incorrectly written as a JSON string (line 2).
- JSON representation of null is not used for the lastName key (lines 5-7).
- Our List of PhoneNumber objects were not marshalled correctly as a JSON array of size 1 (lines 10-13).
- Our phoneNumbers property will map to a JSON key of phoneNumber instead of phoneNumbers (line 10).
Published at DZone with permission of Blaise Doughan, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments