Tech Lead of the Google Web Toolkit (GWT)
Bruce Johnson is Tech Lead of the Google Web Toolkit (GWT). He joined Google in 2005 as a founding member of Google's engineering office in Atlanta, Georgia. Prior to Google, Bruce was Director of Engineering at AppForge, specializing in cross-platform mobile development tools.Presentations by Bruce Johnson
Google Web Toolkit Performance and Interoperability
GWT lets you build Ajax applications in Java. Beyond the gee-whiz factor (or the "huh?" factor, depending on your perspective) of compiling Java to JavaScript, what kind of results can you expect from GWT? Are GWT apps fast? Are GWT apps small? Can you use GWT with existing JavaScript libraries?Google Web Toolkit Blog
News and note from the Google Web Toolkit Team
Tuesday, August 12, 2008
The second release candidate of GWT 1.5 is available for download now.
Thanks to everyone who started using GWT 1.5 RC1 and shared feedback. With your help, we're very near the end of the big GWT 1.5 development cycle.
If you haven't already, now would be a great time to start upgrading your project to take advantage of all the new features and great performance gains in GWT 1.5.
Enjoy!
Monday, August 11, 2008
Suppose you're happily using JSNI to call bits of handwritten JavaScript from within your GWT module. It works well, but JSNI only works at the level of individual methods. Some integration scenarios require you to more deeply intertwine JavaScript and Java objects — DOM and JSON programming are two good examples — and so what we really want is a way to interact directly with JavaScript objects from our Java source code. In other words, we want JavaScript objects that look like Java objects when we're coding.
GWT 1.5 introduces JavaScript overlay types to make it easy to integrate entire families of JavaScript objects into your GWT project. There are many benefits of this technique, including the ability to use your Java IDE's code completion and refactoring capabilities even as you're working with untyped JavaScript objects.
Example: Easy, efficient JSON
Overlay types are easiest to understand with examples. Suppose we want to access an array of JSON objects representing a set of "customer" entities. The JavaScript structure might look like this:
var jsonData = [
{ "FirstName" : "Jimmy", "LastName" : "Webber" },
{ "FirstName" : "Alan", "LastName" : "Dayal" },
{ "FirstName" : "Keanu", "LastName" : "Spoon" },
{ "FirstName" : "Emily", "LastName" : "Rudnick" }
];
To superimpose a Java type onto the above structure, you start by subclassing JavaScriptObject, a marker type that GWT uses to denote JavaScript objects. Let's go ahead and add some getters, too.
// An overlay type
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();
}
}
GWT will now understand that any instance of Customer is actually a true JavaScript object that comes from outside your GWT module. This has useful implications. For example, notice the this reference inside getFirstName() and getLastName(). That this is truly the identity of the JavaScript object, so you interact with it exactly as it exists in JavaScript. In this example, we can directly access the JSON fields we know exist, this.FirstName and this.LastName.
So, how do you actually get a JavaScript object on which to overlay a Java type? You can't construct it by writing new Customer() because the whole point is to overlay a Java type onto an already existing JavaScript object. Thus, we have to get such an object from the wild using JSNI:
class MyModuleEntryPoint implements EntryPoint {
public void onModuleLoad() {
Customer c = getFirstCustomer();
// Yay! Now I have a JS object that appears to be a Customer
Window.alert("Hello, " + c.getFirstName());
}
// Use JSNI to grab the JSON object we care about
// The JSON object gets its Java type implicitly
// based on the method's return type
private native Customer getFirstCustomer() /*-{
// Get a reference to the first customer in the JSON array from earlier
return $wnd.jsonData[0];
}-*/;
}
Let's clarify what we've done here. We've taken a plain-old-JSON-object (POJSONO, anyone? no?) and created a normal-looking Java type that can be used to interact with it within your GWT code. You get code completion, refactoring, and compile-time checking as you would with any Java code. Yet, you have the flexibility of interacting with arbitrary JavaScript objects, which makes things like accessing JSON services via RequestBuilder a breeze.
A quick digression for compiler geeks. Another neat thing about overlay types is that you can augment the Java type without disturbing the underlying JavaScript object. In the example above, notice that we added the getFullName() method. It's purely Java code — it doesn't exist on the underlying JavaScript object — and yet the method is written in terms of the underlying JavaScript object. In other words, the Java view of the JavaScript object can be richer in functionality than the JavaScript view of the same object but without having to modify the underlying JS object, neither the instance nor its prototype.
(This is still part of the digression.) This cool wackiness of adding new methods to overlay types is possible because the rules for overlay types by design disallow polymorphic calls; all methods must be final and/or private. Consequently, every method on an overlay type is statically resolvable by the compiler, so there is never a need for dynamic dispatch at runtime. That's why we don't have to muck about with an object's function pointers; the compiler can generate a direct call to the method as if it were a global function, external to the object itself. It's easy to see that a direct function call is faster than an indirect one. Better still, since calls to methods on overlay types can be statically resolved, they are all candidates for automatic inlining, which is a Very Good Thing when you're fighting for performance in a scripting language. Below we'll revisit this to show you just how much this regimen pays off.
Example: Lightweight collections
We glossed over something in the example above. The method getFirstCustomer() is pretty unrealistic. You're certainly going to want to be able to access the entire array of customers. Thus, we need an overlay type representing the JavaScript array itself. Fortunately, that's easy:
// w00t! Generics work just fine with overlay types
class JsArray<E extends JavaScriptObject> extends JavaScriptObject {
protected JsArray() { }
public final native int length() /*-{ return this.length; }-*/;
public final native E get(int i) /*-{ return this[i]; }-*/;
}
Now we can write more interesting code:
class MyModuleEntryPoint implements EntryPoint {
public void onModuleLoad() {
JsArray<Customer> cs = getCustomers();
for (int i = 0, n = cs.length(); i < n; ++i) {
Window.alert("Hello, " + cs.get(i).getFullName());
}
}
// Return the whole JSON array, as is
private final native JsArray<Customer> getCustomers() /*-{
return $wnd.jsonData;
}-*/;
}
This is nice clean code, especially considering the flexibility of the plumbing it's built upon. As hinted at earlier, the compiler can do pretty fancy stuff to make this quite efficient. Take a look at the unobfuscated compiled output for the onModuleLoad() method:
function $onModuleLoad(){
var cs, i, n;
cs = $wnd.jsonData;
for (i = 0, n = cs.length; i < n; ++i) {
$wnd.alert('Hello, ' + (cs[i].FirstName + ' ' + cs[i].LastName));
}
}
This is pretty darn optimized. Even the overhead of the getFullName() method went away. In fact, all of the Java method calls went away. When we say that "GWT gives you affordable abstractions," this is the kind of thing we're talking about. Not only does inlined code run significantly faster, we no longer had to include the function definitions themselves, thus shrinking the script a litte, too. (To be fair, though, inlining can also easily increase script size, so we're careful to strike a balance between size and speed.)
It's pretty fun to look back at the original Java source above and try to reason about the sequence of optimizations the compiler had to perform to end up here.
Of course, we can't resist showing you the corresponding obfuscated code:
function B(){var a,b,c;a=$wnd.jsonData;for(b=0,c=a.length;b<c;++b){
$wnd.alert(l+(a[b].FirstName+m+a[b].LastName))}}
Notice in this version that the only bits that aren't obfuscated are the identifiers that originated in JavaScript, such as FirstName, LastName, jsonData, etc. That's why, although GWT strives to make it easy to do lots of JavaScript interop, we try hard to persuade people to write as much of their code as possible as pure Java source instead of mixing with JavaScript. Hopefully now when you hear us say that, you'll understand that we aren't bashing JavaScript — it's just that we can't optimize it as much, which makes us sad.
Putting it all together
Overlay types are a key new feature in GWT 1.5. At its simplest, the technique makes direct interop with JavaScript libraries much easier. Hopefully after this post you could imagine how to almost directly port any JavaScript library into GWT as a set of Java types, thus allowing the use of a Java IDE for productive development and debugging without impacting size or speed due to any sort of GWT overhead. At the same time, overlay types serve as a powerful abstraction tool for delivering more elegant low-level APIs such as the the new GWT DOM package.
For more information...
-
Surprisingly Rockin' JavaScript and DOM Programming
This video (or the associated slides) from Google I/O is the best place to get an end-to-end explanation of overlay types in context. The presentation demonstrates the new GWT DOM classes and explains how we used overlay types to implement everything. It also specifies more detail about constructing your own overlay types. -
GWT and Client-Server Communication
Also from Google I/O, Miguel Mendez explains various ways in which you can access data from the browser, including how to combineRequestBuilderand overlay types for really convenient JSON access. -
Design: Overlay Types
Read at your own risk :-) These are the excruciating technical details. It's fairly interesting but not necessarily instructive.
Saturday, August 2, 2008
Suppose you're happily using JSNI to call bits of handwritten JavaScript from within your GWT module. It works well, but JSNI only works at the level of individual methods. Some integration scenarios require you to more deeply intertwine JavaScript and Java objects — DOM and JSON programming are two good examples — and so what we really want is a way to interact directly with JavaScript objects from our Java source code. In other words, we want JavaScript objects that look like Java objects when we're coding.
GWT 1.5 introduces JavaScript overlay types to make it easy to integrate entire families of JavaScript objects into your GWT project. There are many benefits of this technique, including the ability to use your Java IDE's code completion and refactoring capabilities even as you're working with untyped JavaScript objects.
Example: Easy, efficient JSON
Overlay types are easiest to understand with examples. Suppose we want to access an array of JSON objects representing a set of "customer" entities. The JavaScript structure might look like this:
var jsonData = [
{ "FirstName" : "Jimmy", "LastName" : "Webber" },
{ "FirstName" : "Alan", "LastName" : "Dayal" },
{ "FirstName" : "Keanu", "LastName" : "Spoon" },
{ "FirstName" : "Emily", "LastName" : "Rudnick" }
];
To superimpose a Java type onto the above structure, you start by subclassing JavaScriptObject, a marker type that GWT uses to denote JavaScript objects. Let's go ahead and add some getters, too.
// An overlay type
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();
}
}
GWT will now understand that any instance of Customer is actually a true JavaScript object that comes from outside your GWT module. This has useful implications. For example, notice the this reference inside getFirstName() and getLastName(). That this is truly the identity of the JavaScript object, so you interact with it exactly as it exists in JavaScript. In this example, we can directly access the JSON fields we know exist, this.FirstName and this.LastName.
So, how do you actually get a JavaScript object on which to overlay a Java type? You can't construct it by writing new Customer() because the whole point is to overlay a Java type onto an already existing JavaScript object. Thus, we have to get such an object from the wild using JSNI:
class MyModuleEntryPoint implements EntryPoint {
public void onModuleLoad() {
Customer c = getFirstCustomer();
// Yay! Now I have a JS object that appears to be a Customer
Window.alert("Hello, " + c.getFirstName());
}
// Use JSNI to grab the JSON object we care about
// The JSON object gets its Java type implicitly based on the method's return type
private native Customer getFirstCustomer() {
// Get a reference to the first customer in the JSON array from earlier
return $wnd.jsonData[0];
}
}
Let's clarify what we've done here. We've taken a plain-old-JSON-object (POJSONO, anyone? no?) and created a normal-looking Java type that can be used to interact with it within your GWT code. You get code completion, refactoring, and compile-time checking as you would with any Java code. Yet, you have the flexibility of interacting with arbitrary JavaScript objects, which makes things like accessing JSON services via RequestBuilder a breeze.
A quick digression for compiler geeks. Another neat thing about overlay types is that you can augment the Java type without disturbing the underlying JavaScript object. In the example above, notice that we added the getFullName() method. It's purely Java code — it doesn't exist on the underlying JavaScript object — and yet the method is written in terms of the underlying JavaScript object. In other words, the Java view of the JavaScript object can be richer in functionality than the JavaScript view of the same object but without having to modify the underlying JS object, neither the instance nor its prototype.
(This is still part of the digression.) This cool wackiness of adding new methods to overlay types is possible because the rules for overlay types by design disallow polymorphic calls; all methods must be final and/or private. Consequently, every method on an overlay type is statically resolvable by the compiler, so there is never a need for dynamic dispatch at runtime. That's why we don't have to muck about with an object's function pointers; the compiler can generate a direct call to the method as if it were a global function, external to the object itself. It's easy to see that a direct function call is faster than an indirect one. Better still, since calls to methods on overlay types can be statically resolved, they are all candidates for automatic inlining, which is a Very Good Thing when you're fighting for performance in a scripting language. Below we'll revisit this to show you just how much this regimen pays off.
Example: Lightweight collections
We glossed over something in the example above. The method getFirstCustomer() is pretty unrealistic. You're certainly going to want to be able to access the entire array of customers. Thus, we need an overlay type representing the JavaScript array itself. Fortunately, that's easy:
// w00t! Generics work just fine with overlay types
class JsArray<E extends JavaScriptObject> extends JavaScriptObject {
protected JsArray() { }
public final native int length() /*-{ return this.length; }-*/;
public final native E get(int i) /*-{ return this[i]; }-*/;
}
Now we can write more interesting code:
class MyModuleEntryPoint implements EntryPoint {
public void onModuleLoad() {
JsArray<Customer> cs = getCustomers();
for (int i = 0, n = cs.length(); i < n; ++i) {
Window.alert("Hello, " + cs.get(i).getFullName());
}
}
// Return the whole JSON array, as is
private final native JsArray<Customer> getCustomers() /*-{
return $wnd.jsonData;
}-*/;
}
This is nice clean code, especially considering the flexibility of the plumbing it's built upon. As hinted at earlier, the compiler can do pretty fancy stuff to make this quite efficient. Take a look at the unobfuscated compiled output for the onModuleLoad() method:
function $onModuleLoad(){
var cs, i, n;
cs = $wnd.jsonData;
for (i = 0, n = cs.length; i < n; ++i) {
$wnd.alert('Hello, ' + (cs[i].FirstName + ' ' + cs[i].LastName));
}
}
This is pretty darn optimized. Even the overhead of the getFullName() method went away. In fact, all of the Java method calls went away. When we say that "GWT gives you affordable abstractions," this is the kind of thing we're talking about. Not only does inlined code run significantly faster, we no longer had to include the function definitions themselves, thus shrinking the script a litte, too. (To be fair, though, inlining can also easily increase script size, so we're careful to strike a balance between size and speed.)
It's pretty fun to look back at the original Java source above and try to reason about the sequence of optimizations the compiler had to perform to end up here.
Of course, we can't resist showing you the corresponding obfuscated code:
function B(){var a,b,c;a=$wnd.jsonData;for(b=0,c=a.length;b<c;++b){
$wnd.alert(l+(a[b].FirstName+m+a[b].LastName))}}
Notice in this version that the only bits that aren't obfuscated are the identifiers that originated in JavaScript, such as FirstName, LastName, jsonData, etc. That's why, although GWT strives to make it easy to do lots of JavaScript interop, we try hard to persuade people to write as much of their code as possible as pure Java source instead of mixing with JavaScript. Hopefully now when you hear us say that, you'll understand that we aren't bashing JavaScript — it's just that we can't optimize it as much, which makes us sad.
Putting it all together
Overlay types are a key new feature in GWT 1.5. At its simplest, the technique makes direct interop with JavaScript libraries much easier. Hopefully after this post you could imagine how to almost directly port any JavaScript library into GWT as a set of Java types, thus allowing the use of a Java IDE for productive development and debugging without impacting size or speed due to any sort of GWT overhead. At the same time, overlay types serve as a powerful abstraction tool for delivering more elegant low-level APIs such as the the new GWT DOM package.
For more information...
-
Surprisingly Rockin' JavaScript and DOM Programming
This video (or the associated slides) from Google I/O is the best place to get an end-to-end explanation of overlay types in context. The presentation demonstrates the new GWT DOM classes and explains how we used overlay types to implement everything. It also specifies more detail about constructing your own overlay types. -
GWT and Client-Server Communication
Also from Google I/O, Miguel Mendez explains various ways in which you can access data from the browser, including how to combineRequestBuilderand overlay types for really convenient JSON access. -
Design: Overlay Types
Read at your own risk :-) These are the excruciating technical details. It's fairly interesting but not necessarily instructive.
Friday, August 1, 2008
Google Health started to pick up speed around the time I first joined Google. A few of us had whipped up a prototype in our 20% time. GWT naturally came into the picture as we tried to decide what we would use to build our client infrastructure: hand-written JavaScript with other internal JS libraries, or GWT. We didn't jump right to GWT until we did our homework. We loved the concept, but GWT was fairly new back then. We were cautious about whether it was mature enough for a production-planned project like Google Health.
Since many of you are faced with these same decisions, I thought it might be useful to share a synopsis of that first email thread I wrote to the GWT team titled "GWT, to use or not to use". In it I included a link to our mock as well as 4 key questions:
- Can we use GWT to accomplish all that was in the mock?
- How many browsers does GWT reliably support?
- Is i18n supported?
- How big is the GWT library that needs to be downloaded and how will it perform in the browser client?
Scott Blum from the GWT team responded that "in general anything you can do in HTML, you can do with GWT". Joel Webber, one of the founders of GWT, added "Looking at the your mocks... it appears as though you would want to fetch lots of information from the server during the course of interaction with the user, and to update both the form on the left and the results on the right interactively. I think GWT would be an excellent way to do this". To get a better feel for what GWT development meant, I created a sample project to test the waters. After exploring the widget library, I was able to build a functional prototype quickly. I tried a bunch of different widgets and found that they are easy to use and extend. The RPC calls were straightforward as well, and tied into the Servlet framework nicely. I was very pleased with the result of the prototyping.
Scott also confirmed browser support for "Recent versions of Opera, Safari, and Mozilla/Firefox; IE6+", which was satisfactory for us.
At the time, the i18n support was still in the works, but we were assured that it would arrive very soon. We were a little bit worried about how hard it would be but we were pleasantly surprised to learn that the implementation was really simple. All we had to do is to inherit the i18n package, create the constant and message classes along with their associated property files for all the strings, messages that need to be externalized.
The initial answer I got regarding our fourth question was "your entire application is monolithically compiled into aggressively optimized and obfuscated JavaScript. It's a "pay-as-you-go" model, code you don't call gets pruned", and "GWT uses a trick to allow its script to be reliably compressed, resulting in a 3-5 fold decrease in size". I had vivid memory of working on scripts to prune and obfuscate handwritten JavaScript code in my previous job, and how it required constant tweaks and tune-ups. As painful as it may be, performance tuning is a very important step for any large-scale JavaScript application. The initial download time and execution speed are crucial and greatly affect the user's perception of an application. As a skeptical engineer, I performed my own tests to validate these claims and test performance, initially and prior to launch, to make sure that the code was pruned, optimized and obfuscated. The results of this testing proved to me that GWT could live up to our expectations.
Finally, after receiving convincing arguments and techniques for creating a custom-cut Google Data library, the choice for which technology to use to bring Google Health to production was obvious, and the rest is history. My sample GWT project became the launch pad for the Google Health client infrastructure.
Of course we didn't develop the whole application without running into technical challenges. We grew our application as GWT itself was still growing up. There were times when we realized that some of the little details in JavaScript were not exposed through GWT. In most of these cases, we used JSNI to access lower level JavaScript functionality. At one point, we also noticed that as we continued to build the application the initial download time started growing as well. We analyzed all the requests and realized that there was cumulative latency introduced by each little icon, logo and other images that needed to be requested and loaded during the application loading. We used GWT image bundle to handle all the images and it considerably improved performance. Finally, in cases where we thought a certain widget should be further extended, we took one of a few approaches: first we checked for such a widget in the GWT pipeline; second we checked the developer forum to see if someone has already constructed what we need and contributed it back the open source community; third, we developed our own and contribute it back to GWT for potential inclusion in a future release.
Looking back today at a successful Google Health pilot and public launch after 2 major UI redesigns, numerous UI experiments including proof of concepts and user studies, it's hard for me to imagine accomplishing so much in last two years without GWT. We were able to do all the fancy JavaScript stuff in half of the effort it would have taken with handwritten JavaScript. We were able to write truly object-oriented UI code, refactoring and reuse were much easier, and leveraging IDEs like IntelliJ or Eclipse made UI redesigns much easier to absorb. GWT's compile-time elimination of dead code also meant we didn't have to worry about unused code that was still hanging around the codebase (of course it's best to do code cleanups every now and then), and we were also able to easily create unit tests for our UI code with GWT's integration with JUnit, which saved us lots of debugging time as our engineering team grew. It's been an amazing experience.
Friday, July 18, 2008
The next and hopefully last release candidate for GWT 1.5 is almost upon us. In anticipation, we'd like to really crank up the excitement level and, well, the sheer geek factor of this here blog.
If you are new to GWT, you may be wondering what all the excitement is about. Why is GWT different from other framework-style solutions? GWT is more of a tool chain and a baseline technology rather than a particular application framework. So, although GWT has lots of libraries, you can use as many or as few as you find useful. Don't like GWT's UI? You can build your own using the DOM classes. Want to use JSON instead of RPC? It's easy. In fact, it is completely possible to start from scratch and build your own framework using GWT and benefit just as much from GWT's overall approach to debugging and compilation.
So, high-level, why should you consider using GWT for your next big web app?
- Ajax applications, when designed well, can by their nature provide a much better user experience than server-centric approaches for many important kinds of applications. Since you are reading this blog, you probably already know this.
- The GWT compiler frequently produces smaller, faster JavaScript than you would write by hand.
- You can be more productive developing with GWT and, simultaneously, the JavaScript you deploy to users will be more reliable.
- You get the opportunity to say "Gwit" a lot.
We doubt you are someone who is easily influenced by mere assertions or marketing pitches, so we've put together the next few blog posts to take a look at exactly how GWT achieves these performance gains, and how it makes working with JavaScript easier.
Before we dive into the technical details, one last note. We sometimes get asked two questions about the very nature of GWT:
- Why does GWT center on the Java language and tools?
- Isn't GWT heavyweight and limiting compared to handwritten JavaScript?
In answer to the first, understand that our goal and our passion is to radically improve the end user experience of the web, which means that GWT must produce JavaScript that is maximally performant and reliable. In order to do that, we naturally want to apply a lot of optimizations to source code and catch bugs as early as possible. Both of these goals are directly facilitated by Java's static type system and the existence of great Java IDEs. That is why we, dispassionately, chose to center GWT on Java technologies. That's it — no fodder for language wars here.
In answer to the second, it is perfectly reasonable that some developers, upon first hearing about GWT, assume that it is a sort of "walled garden of abstraction" that forever locks you into Java development and prevents you from using or integrating with handwritten JavaScript. Nothing could be further from the truth, which is a great segue...
GWT's JavaScript Native Interface (JSNI)
You can easily combine handwritten JavaScript directly into GWT code. It's all JavaScript in the end, of course, so why not allow GWT developers to mix-and-match in any way that's useful? That's what JSNI is all about. It's named similarly to the Java Native Interface (JNI) because it uses the same basic idea: declare a Java method "native" and then use another language to implement it. In the case of JSNI, that other language is JavaScript.
Writing Java methods with JavaScript
JSNI is useful to create a reusable abstraction on top of functionality that is most naturally expressed using JavaScript syntax rather than Java syntax. For example, regular expressions are pleasantly concise in JavaScript, so you can use JSNI to make them directly available in your GWT code. Suppose you wanted a method to flip someone's name around such that their last name comes first, for example turning "Freeland Abbott" into "Abbott, Freeland". (Admittedly, this example is an I18N nightmare.) You can create a short JSNI method to do this:
// Java method declaration...
native String flipName(String name) /*-{
// ...implemented with JavaScript
var re = /(\w+)\s(\w+)/;
return name.replace(re, '$2, $1');
}-*/;
Notice that the method body is really just a glorified Java comment, enclosed by the special tokens /*-{ and }-*/.
Calling Java methods from JSNI
You can go the other direction, too, calling a Java method from JavaScript. Suppose we modified the example above to invoke a callback instead:
package org.example.foo;
public class Flipper {
public native void flipName(String name) /*-{
var re = /(\w+)\s(\w+)/;
var s = name.replace(re, '$2, $1');
this.@org.example.foo.Flipper::onFlip(Ljava/lang/String;)(s);
}-*/;
private void onFlip(String flippedName) {
// do something useful with the flipped name
}
}
Using JSNI to access external JavaScript code
Naturally, you can access any sort of external JavaScript code from within a GWT module. For example, if your HTML page looks like this:
<html>
<head>
<script>
function sayHello(name) {
alert("Hello from JavaScript, " + name);
}
</script>
<-- Include the GWT module called "Spiffy" -->
<script src="org.example.yourcode.Spiffy.nocache.js"></script>
</head>
...
Within your Java source, you can access the sayHello() JS function through JSNI:
// A Java method using JSNI
native void sayHelloInJava(String name) /*-{
$wnd.sayHello(name); // $wnd is a JSNI synonym for 'window'
}-*/;
The GWT compiler inlines the extra method call away, so calling the sayHelloInJava() method in your Java source is no more expensive than calling sayHello() directly from handwritten JavaScript.
Creating JavaScript libraries with GWT
You can even create JavaScript-callable libraries from your GWT code. This is a pretty neat trick:
package org.example.yourcode.format.client;
public class DateFormatterLib implements EntryPoint {
// Expose the following method into JavaScript.
private static String formatAsCurrency(double x) {
return NumberFormat.getCurrencyFormat().format(x);
}
// Set up the JS-callable signature as a global JS function.
private native void publish() /*-{
$wnd.formatAsCurrency =
@org.example.yourcode.format.client.DateFormatterLib::formatAsCurrency(D);
}-*/;
// Auto-publish the method into JS when the GWT module loads.
public void onModuleLoad() {
publish();
}
}
You can then access this GWT-created functionality from within any HTML page or another JavaScript library:
<html>
<head>
<-- Include the GWT module that publishes the JS API -->
<script src="org.example.yourcode.FormatLib.nocache.js"></script>
<-- Write some JS that uses that GWT code -->
<script>
function doStuff() {
alert(formatAsCurrency(1530281));
}
</script>
</head>
...
Ray Cromwell (of GWT Extreme! fame, among other things) has taken the above JavaScript publishing technique to the extreme with his GWT Exporter project. It creates all the publishing code automagically using GWT's compile-time code generation facility. (Does "compile-time code generation" sound cool? If so, stay tuned for the upcoming posts in this series.)
Putting it all together
Using JSNI, you can freely mix handwritten JavaScript, external JavaScript libraries, and Java source code in any way that you need to. That's what we mean we say GWT isn't a walled garden of abstraction and that you can adopt GWT incrementally into existing web apps. And, best of all, you can debug all the Java code using the Java debugger of your choice.
To learn more, check out JavaScript Native Interface in the GWT Developer Guide. Better yet, let GWT compiler architect Scott Blum explain it to you himself.