April 5, 2013

MOXy and JSON with Padding

JSON with padding is a communication mechanism used in JavaScript to overcome restrictions due to the same origin policy (for more information see: http://en.wikipedia.org/wiki/JSONP).  In this post I will demonstrate how to leverage JSON with padding when using MOXy as your JSON provider.

This functionality is new in EclipseLink 2.5.0 (and 2.4.2), you can try it out today using a nightly build available from:

Web Application (foo.html)

The data that we are requesting (to populate the div with id="message") via HTTP comes from a different server than the one hosting our application.  We will utilize JSON with padding to get the data.  The response from the URL will be a call to our foo function.  We will supply the function name via the callback query parameter.
<html>
    <body>
        <div id="message"></div>
        <script>
        function foo(dataWeGotViaJsonp){
            document.getElementById('message').innerHTML = dataWeGotViaJsonp.bar;
        }
        </script>
        <script type="text/javascript" 
            src="http://www.example.com/foo?callback=foo"></script>
    </body>
</html>

Response (from http://www.example.com/foo?callback=foo)

Below is the response from making the HTTP call.  See how the JSON data is wrapped in a call to our foo function.
foo({
   "bar" : "Hello World"
});

RESTful Service (FooResource)

Below is the RESTful service implemented with JAX-RS.  Our GET method returns an instance of the MOXy class JSONWithPadding parameterized with the domain class Foo.  When instantiating this class we give it the callback function name (default is callback) and an instance of the domain class.  We will use the callback function name from the query parameters if one was provided.
package org.example.padding;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import org.eclipse.persistence.oxm.JSONWithPadding;

@Path("/foo")
public class FooResource {

    @GET
    @Produces("application/x-javascript")
    public JSONWithPadding<Foo> getFoo(@Context UriInfo uriInfo) {
        Foo foo = new Foo();
        foo.setBar("Hello World");
        MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters();
        String callbackName = queryParameters.getFirst("callback");
        if(null == callbackName) {
            return new JSONWithPadding<Foo>(foo);
        } else {
            return new JSONWithPadding<Foo>(foo, callbackName);
        }
    }

}

Java Model (Foo) 

Below is the Java model that we will use for this example.
package org.example.padding;

public class Foo {

    private String bar;

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

}

Handling the application/x-javascript Media Type  (MyProvider)

Due to a bug (see:  http://bugs.eclipse.org/404927) that we will fix in EclipseLink 2.5.1 you will need to subclass MOXyJsonProvider to override @Produces and the isWritable method in order to utilize JSON with padding.
package org.example.padding;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;
import org.eclipse.persistence.oxm.JSONWithPadding;

@Provider
@Produces({
    MediaType.APPLICATION_JSON, 
    "application/x-javascript"
})
@Consumes(MediaType.APPLICATION_JSON)
public class MyProvider extends MOXyJsonProvider {

    public MyProvider() {
        setFormattedOutput(true);
    }

    @Override
    public boolean isWriteable(Class type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        if(type == JSONWithPadding.class && 
            "application/x-javascript".equals(mediaType.toString())) {
            return true;
        }
        return super.isWriteable(type, genericType, annotations, mediaType);
    }

}

Further Reading 

If you enjoyed this post then you may also be interested in:

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.