GWT 2, JSONP and Javascript Overlays with JsonpRequestBuilder
In one of my earlier posts I discussed the topic of making cross site requests with Google Web toolkit.
Since that post Google have updated Web toolkit, currently version 2.0.3 and has now made it easier to make cross site requests through the use of their new JsonpRequestBuilder object and the Javascript object overlay types for result encapsulation.
This is a quick tutorial update on how to make use of the object overlay types. The application contacts the Geonames webservice. For the example I shall use the ‘Placename lookup with postalcode (JSON)’ function by making the following call:
http://ws.geonames.org/postalCodeLookupJSON?postalcode=M1&country=GB&maxRows=4
This returns location details for places matching the M1 post code so central Manchester in the United Kingdom.
The results this request return are as follows:
{"postalcodes":[ {"adminCode3":"BN","adminName3":"Manchester District (B)","adminCode2":"00","postalcode":"M1 1AD","adminCode1":"ENG","countryCode":"GB","lng":-2.24521599415295,"placeName":"City Centre Ward","lat":53.4838491117407,"adminName1":"England"}, {"adminCode3":"BN","adminName3":"Manchester District (B)","adminCode2":"00","postalcode":"M1 1AE","adminCode1":"ENG","countryCode":"GB","lng":-2.23116928236428,"placeName":"Ancoats and Clayton Ward","lat":53.4834816441844,"adminName1":"England"} ]}
If you look at the previous JSON data it seems we have a list of ‘postalcodes‘ and each postal code has various fields such as adminName3, placeName etc.
Using GWT Javascript object overlays we can represent this structure. Within your GWT client directory create a new class called PostcodeEntry and add the following:
import com.google.gwt.core.client.JavaScriptObject; public class PostcodeEntry extends JavaScriptObject { protected PostcodeEntry() {} public final native String getAdminCode3() /*-{ return this.adminCode3; }-*/; public final native void setNumberPlaceHolderId(String adminCode3) /*-{ this.adminCode3 = adminCode3; }-*/; public final native String getAdminName3() /*-{ return this.adminName3; }-*/; public final native void setAdminName3(String adminName3) /*-{ this.adminName3 = adminName3; }-*/; public final native String getPostalcode() /*-{ return this.postalcode; }-*/; public final native void setPostalcode(String postalcode) /*-{ this.postalcode = postalcode; }-*/; public final native String getPlaceName() /*-{ return this.placeName; }-*/; public final native void setPlaceName(String placeName) /*-{ this.placeName = placeName; }-*/; }
Each PostcodeEntry represents one postalcode as you can see we have the functions for the various properties of a postalcode. Also note we extend the GWT JavascriptObject. In the above example you’ll notice I haven’t implemented every property. This is by choice I have only implemented a few of the properties.
Now we need to build an object that maintains the collection of PostcodeEntry object. Essentially the object that represents the postalcodes array. Create a new Java object called ‘PostalCodes‘. Add the following content:
import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; public class PostalCodes extends JavaScriptObject { protected PostalCodes() {} public final native JsArray<PostcodeEntry> getPostalCodes() /*-{ return this.postalcodes; }-*/; }
The object quite simply has one method called getPostalCodes which you’ll notice is a collection of PostcodeEntry objects and the native method simply called this.postalcodes which if you remember was the name of the array in the JSON response.
Those two objects wrap up the Geonames JSON response.
Finally we just need to write the code that invokes the service using the JsonpRequestBuilder object.
Locate your GWT entry point and add the following code.
import com.google.gwt.core.client.EntryPoint; import com.google.gwt.jsonp.client.JsonpRequestBuilder; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.VerticalPanel; /** * Entry point classes define <code>onModuleLoad()</code>. */ public class JsonpExample implements EntryPoint { /** * This is the entry point method. */ public void onModuleLoad() { // // http://ws.geonames.org/postalCodeLookupJSON?postalcode=M1&country=GB&maxRows=4 // JsonpRequestBuilder jsonp = new JsonpRequestBuilder(); String url = "http://ws.geonames.org/postalCodeLookupJSON?postalcode=M1&country=GB&maxRows=4"; jsonp.requestObject(url, new AsyncCallback<PostalCodes>() { @Override public void onFailure(Throwable caught) { Window.alert("Failure:" + caught.getMessage()); } @Override public void onSuccess(PostalCodes result) { VerticalPanel vp = new VerticalPanel(); if(result.getPostalCodes() != null ) { for( int count = 0; count < result.getPostalCodes().length(); count++) { PostcodeEntry entry = result.getPostalCodes().get(count); HorizontalPanel hp = new HorizontalPanel(); hp.setSpacing(10); hp.add(new Label(entry.getPostalcode())); hp.add(new Label(entry.getPlaceName())); vp.add(hp); } } RootPanel.get().add(vp); } }); } }
There are few important areas of this code to take note.
First of all note the use of the JsonpRequestBuilder object. We simply give this a Url which in this case is the Geoname service url. Those who are familiar with cross site requests will notice that the URL I specified doesn’t contain the ‘callback’ parameter. The JsonpRequestBuilder automatically appends this to the end of the URL for us so we have &callback=gwt_IOSucess appended to the request. It defaults the parameter name to ‘callback’ but if the service requires a different parameter name you can change this by calling setCallbackParam.
Next we simply call requestObject that takes an Async callback which is of our Postalcodes type. This clears up why we use object overlays.
Finally the onSuccess method takes in the Postalcodes as an argument and we are then free to pick away at the response and the various postalcode entries in the result.
I hope this has helped people to start making use of the new GWT JSONP functions and object overlays.
You can also download the source code for this example.
Please any comments welcome…..