Issue 10164

Investigate how to support JSONP

10164
Reporter: omeyn
Type: Feedback
Summary: Investigate how to support JSONP
Priority: Major
Resolution: Fixed
Status: Closed
Created: 2011-11-08 09:42:00.298
Updated: 2013-08-29 14:46:02.771
Resolved: 2011-11-08 09:42:40.146


Author: omeyn@gbif.org
Created: 2011-11-08 09:42:32.888
Updated: 2011-11-08 09:42:32.888
        
Markus Döring Fri, 16 Sep at 3:24am
of course it can. Wrapping the data object with the JSONWithPadding class does the trick:
http://weblogs.java.net/blog/felipegaucho/archive/2010/02/25/jersey-feat-jquery-jsonp
Setting up test project in clb-ws using a jquery cross domain call to test its working fine as the client should send the correct request headers asking for a javascript content type and not text json:
http://code.google.com/p/gbif-ecat/source/browse/trunk/checklistbank-ws/src/main/java/org/gbif/checklistbank/ws/resources/UsageResource.java

Markus Döring Fri, 16 Sep at 3:52am
 The drawback of using JSONWithPadding is that application/x-javascript becomes the default mime type of a jersey resource, even if no callback parameter is given in the request. This is required as jquery
 sends out an accept all request header: Accept:*/*

  So consumers of pure json MUST make sure to request the right mime type, otherwise it will be
  JSONP instead.

  A simple alternative solution is to use a servlet filter that checks for the presence of
  a callback parameter and sets the content-type accordingly.

Markus Döring Fri, 16 Sep at 4:22am
current rev: http://code.google.com/p/gbif-ecat/source/browse/trunk/checklistbank-ws/src/main/java/org/gbif/checklistbank/ws/resources/UsageResource.java?r=4038

Markus Döring Fri, 16 Sep at 5:57am
Potenital working pure jersey solution found that plays nice with jQuery.
It uses the return media type found by jersey by default, but when a callback parameter is found it forces it to be application/javascript.
Please review  http://code.google.com/p/gbif-ecat/source/browse/trunk/checklistbank-ws/src/main/java/org/gbif/checklistbank/ws/resources/UsageResource.java?r=4041
If you start the server via maven behavior with jQuery can be tested by opening this static html file in your browser (from your local checkout!):
http://code.google.com/p/gbif-ecat/source/browse/trunk/checklistbank-ws/src/test/resources/jsonp.html

Lars Francke Tue, 20 Sep at 5:25am
Thank you for the implementation. It's unfortunate that we have to do it this complicated. What about the other solutions using one of those Providers or whatever they are called in JAX-RS to process the response?

Markus Döring Tue, 20 Sep at 5:34am
I thought providers are only for injecting things into resource methods, but Ill look at that. The simplest as I said initially is to use a servlet filter that potentially wraps json into jsonp and sets the new content type. But it seemed noone likes filters these days anymore...

Markus Döring Tue, 20 Sep at 6:05am
There is a com.sun.jersey.spi.container.ContainerResponseFilter which we can probably use that does very much what a servlet filter would do. Or I can try to subclass JSONWithPadding to also check if the callback parameter was set at all.

Markus Döring Tue, 20 Sep at 10:31am
Ok, rethought this one. For JSONP all we want is that if there is a callback parameter provided that the returned content type is javascript. We can therefore use a request filter and set the Accept header appropriately in case we find a callback query param.
We can use the same approach for updating the accept language header in case a language query param was given. This allows clean programming on the resource side where we only have to check the headers. In case of JSONP this is then done out of the box with the JSONWithPadding class and for the language Ive written a locale provider (couldnt figure out how to access the query params, but headers are simple!) that can be injected into any resource method, so we keep the logic in one place.
Also for potential future method overloading I found that there is already a jersey request filter, so it makes sense to follow that way:
http://jersey.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/container/filter/PostReplaceFilter.html

Markus Döring Tue, 20 Sep at 11:11am
Implemented the proposed request filter approach in rev 4060: http://code.google.com/p/gbif-ecat/source/browse/trunk/checklistbank-ws/src/main/java/org/gbif/checklistbank/ws/resources/UsageResource.java?r=4060

Markus Döring Tue, 20 Sep at 11:12am
also see
http://code.google.com/p/gbif-ecat/source/browse/trunk/checklistbank-ws/src/main/java/org/gbif/checklistbank/ws/util/RequestHeaderParamUpdate.java?r=4060
http://code.google.com/p/gbif-ecat/source/browse/trunk/checklistbank-ws/src/main/java/org/gbif/checklistbank/ws/provider/LocaleProvider.java?r=4060