Bruce Johnson has posted a new entry on the Google Web Toolkit blog entitled Getting to really know GWT, Part 2: JavaScript Overlay Types. In the article, Bruce shows us how to use the new GWT 1.5 JavaScript overlay types to easily parse JSON into Java objects.
I previously wrote about Testing JSON Parsing with GWTTestCase using the original GWT JSON parsing libraries, so I'm posting a new example of testing JSON parsing using the new JavaScript Overlay Types.
Bruce's example parses some customer data into a Java Customer object. Here's the source from the article, with an additional "parse" factory method that parses a Customer object from a String containing JSON.
class Customer extends JavaScriptObject {
// Overlay types always have protected, zero-arg ctors
protected Customer() { }
// Typically, methods on overlay types are JSNI
public final native String getFirstName() /*-{ return this.FirstName; }-*/;
public final native String getLastName() /*-{ return this.LastName; }-*/;
// Note, though, that methods aren't required to be JSNI
public final String getFullName() {
return getFirstName() + " " + getLastName();
}
// Parse from JSON, based upon code from
// http://sites.google.com/site/io/gwt-and-client-server-communication
public static final native Customer fromJson(String input) /*-{
return eval('(' + input + ')')
}-*/;
}
Here's a simple test case demonstrating using an existing JavaScript object as well as parsing from JSON:
public class CustomerTest extends GWTTestCase {
// Required by all GWTTestCases
public String getModuleName() {
return "JsniOverlays";
}
public void testUsesUnderlyingJavaScriptObject() {
Customer customer = testCustomer();
assertEquals("Jimmy", customer.getFirstName());
assertEquals("Webber", customer.getLastName());
assertEquals("Jimmy Webber", customer.getFullName());
}
// Sample test fixture
private native Customer testCustomer() /*-{
return { "FirstName" : "Jimmy", "LastName" : "Webber" }
}-*/;
public void testParsesFromJson() {
Customer customer = Customer.fromJson("{ FirstName: \"Murphy\", LastName: \"Plankton\" }");
assertEquals("Murphy", customer.getFirstName());
assertEquals("Plankton", customer.getLastName());
}
}
Notice that testUsesUnderlyingJavaScriptObject refers to a test fixture creation method written in JavaScript using JSNI. This test is similar to Bruce's example which coerces a JavaScript object into a Java object.
testParsesFromJson passes in a String containing JSON, which is what a remote service might do after receiving a response from a server. Notice how I'm not testing getFullName again in this test; it's already been verified in another test.
Testing Considerations
One challenge with using overlay types is that your objects contain JSNI -- which means that they fail to run in a plain JUnit TestCase. Instead, they must be run in a GWTTestCase, and that means a much slower test.
To solve this problem, I'm tempted to create an interface for the methods I need on my Customer object, then create a Test Double to use in my tests. This would encourage referring to the object by it's interface, which is a good thing.
Still, it seems a little annoying that I need to jump through some hoops so that my core domain object (Customer) doesn't accidentally call JavaScript in my tests. I'm not sure if this would be a real problem or not; experience will tell.
Congratulations to the GWT team on their hard work in making some great improvements to GWT 1.5!