Making Jersey-based web-services be JSONP friendly

It's pretty easy to make web-services answer with JSONP callbacks if you're using Jersey. Adding single filter you can make all web-services' resources add callbacks to their response.

Here is the code of such filter. Note that it's Jersey-based.

package net.sukharevd.ws.rs;

import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.sun.jersey.api.json.JSONWithPadding;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;

/**
 * Filter that optionally wraps a JSON response in a JSONP callback.
 * <p/>
 * For this wrapping to happen two things need to be true:
 * <ul>
 * <li>The Media type of the response must be set to JSON or application/javascript</li>
 * <li>The request must have a query parameter called {@code callback}</li>
 * </ul>
 * <p/>
 *
 * @see <a href="http://weblogs.java.net/blog/felipegaucho/archive/2010/02/25/jersey-feat-jquery-jsonp">JSONP with
 *      Jersey and jQuery</a>
 */
public class JsonpResponseFilter implements ContainerResponseFilter {

    @Override
    public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
        if (response.getMediaType() == null || !response.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)
                && !response.getMediaType().equals(new MediaType("application", "javascript"))
                && !response.getMediaType().equals(new MediaType("application", "x-javascript"))) {
            return response;
        }

        String callback = request.getQueryParameters().getFirst("callback");
        if (callback == null || callback.isEmpty()) {
            return response;
        }

        if (response.getEntity() != null && response.getEntity().getClass() != GenericEntity.class
                && response.getEntity().getClass() != JSONWithPadding.class) {
            @SuppressWarnings("unchecked")
            final GenericEntity<?> genericEntity = new GenericEntity(response.getEntity(), response.getEntityType());
            JSONWithPadding jsonp = new JSONWithPadding(genericEntity, callback);
            response.setEntity(jsonp);
            response.setResponse(Response.fromResponse(response.getResponse())
                    .type("application/javascript")
                    .entity(jsonp).build());
            return response;
        }

        return response;
    }
}

You can add this filter to web.xml as easy as adding parameter

<init-param>
  <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
  <param-value>net.sukharevd.ws.rs.JsonpResponseFilter</param-value>
</init-param>

or if you use GrizzlyServerFactory

ResourceConfig rc = new PackagesResourceConfig("net.sukharevd.ws.rs");
rc.getContainerResponseFilters().add(new JsonpResponseFilter());
HttpServer httpServer = GrizzlyServerFactory.createHttpServer(BASE_URI, rc);

Here you can find GitHub repository with web-services and GWT-client sample projects.

Tagged as : Java

Comments