About Blaise Doughan

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

MOXy is the New Default JSON-Binding Provider in GlassFish 4

GlassFish 4 is now available offering the complete Java EE 7 (JSR-342) platform.  EclipseLink made some major contributions to this release.  The first is providing the JPA 2.1 (JSR-338) implementation.  The second which I’ll cover in this post is EclipseLink MOXy is now the default JSON-binding provider for JAX-RS applications.

RESTful Service 

CustomerService

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 CustomerService {

    @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.setName("Jane Doe");

        PhoneNumber pn = new PhoneNumber();
        pn.setType("work");
        pn.setValue("5551111");
        customer.getPhoneNumbers().add(pn);

        return customer;
     }

}

CustomerApplication 

I have used an Application class to specify the path for the service.

package org.example.service;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("rest/*")
public class CustomerApplication  extends Application {

}

Java Model

Below is the Java model we will use for this example.  The goal is to produce good XML and JSON representations using a single set of metadata.

Customer

There are a couple of interesting things to note about the Customer class.

  1. The id property is an int.  Since JSON has a different representation for numbers and text we will look at how this value gets represented in the JSON output.
  2. The phoneNumbers property is of type List<PhoneNumber>.  It has been annotated with @XmlElementWrapper to produce good XML output.  We will examine the impact of doing this on the JSON output.
package org.example.model;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Customer {

    private int id;
    private String name;
    private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlElementWrapper
    @XmlElement(name="phoneNumber")
    public List<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

}

PhoneNumber 

In XML the PhoneNumber class maps to a complex type with simple content (see: JAXB and Complex Types with Simple Content).  This means it maps to an XML element with attributes and text.  These XML concepts do not correspond directly to JSON concepts so we will examine the JSON representation.

package org.example.model;

import javax.xml.bind.annotation.*;

public class PhoneNumber {

    private String type;
    private String value;

    @XmlAttribute
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @XmlValue
    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

Using the Service

Request – GET

Below is the URL we will use to access our service:

http://localhost:8080/CustomerResource/rest/customers/1

Response (application/xml)

Since we mapped our domain model with
JAXB (JSR-222) metadata the XML representation below isn’t much of a surprise.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer id="1">
    <name>Jane Doe</name>
    <phoneNumbers>
        <phoneNumber type="work">5551111</phoneNumber>
    </phoneNumbers>
</customer>

Response (application/json) – GlassFish 3.1.2

Lets take a look at what the JSON representation looked like back in GlassFish 3.1.2 before MOXy was the default JSON-binding provider.  There are several things to take note of:

  1. The int value for the id property is represented as JSON text.
  2. The phoneNumbers property of type List<PhoneNumber>
    since it had a single item was represented as a JSON object instead of a JSON array.  Also even when this key contains a collection it is still called phoneNumber.
  3. The JSON key corresponding to the type property since it was annotated with @XmlAttribute is prefixed with @.
  4. The JSON key corresponding to the value property since it was annotated with @XmlValue is called $.
{
    "id": "1",
    "name": "Jane Doe",
    "phoneNumbers": {
        "phoneNumber": {
            "@type": "work",
            "$": "5551111"
        }
    }
}

Response (application/json) – GlassFish 4

Using the default configuration you will see that upgrading to GlassFish 4 eliminates the two biggest problems:

  1. Numeric Values – Now the id property is correctly marshalled to JSON as a numeric value.  This isn’t a trick, MOXy bases the JSON representation on the Java type of the property.  The value property of type String on the instance of PhoneNumber contained only digits and it is correctly marshalled to JSON as text.
  2. Collections of Size 1 – The phoneNumber key is now a JSON array, unfortunately it is still called phoneNumber (I’m demonstrate how to fix this next).
{
    "id": 1,
    "name": "Jane Doe",
    "phoneNumbers": {
        "phoneNumber": [
            "@type": "work",
            "$": "5551111"
        ]
    }
}

Customizing the JSON-Binding

MOXy can now be configured by leveraging the JAX-RS ContextResolver mechanism.  You simply need to return an instance of MOXyJsonConfig.  We will use it to do the following:

  1. Specify that we don’t want to prefix the JSON keys that correspond to properties mapped with @XmlAttribute.
  2. Use the JSON key value instead of $ for properties mapped with @XmlValue.
  3. MOXyJsonConfig can also be used to pass properties down to the Marshaller/Unmarshaller.  We will do this to clean up the JSON key for collection properties (see: Binding to JSON & XML – Handling Collections).
package org.example.service;

import javax.ws.rs.ext.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.glassfish.jersey.moxy.json.MoxyJsonConfig;

@Provider
public class MOXyJsonContextResolver implements ContextResolver<MoxyJsonConfig> {

    private final MoxyJsonConfig config;

    public MOXyJsonContextResolver() {
        config = new MoxyJsonConfig()
            .setAttributePrefix("")
            .setValueWrapper("value")
            .property(JAXBContextProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
    }

    @Override
    public MoxyJsonConfig getContext(Class<?> objectType) {
        return config;
    }

}

New Response

Finally we have a JSON representation that we can be happy with.  It does not contain any XML related artifacts, even though it was produced with the same metadata as the XML representation (which hasn’t changed).  All it took was a little MOXy.

{
    "id": 1,
    "name": "Jane Doe",
    "phoneNumbers": [
        {
            "type": "work",
            "value": "5551111"
        }
    ]
}

 

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


6 + = seven



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