My favorites | English | Sign in

Google Web Toolkit

Coding Basics

  1. Client-side code
  2. Compatibility with the Java Language and Libraries
  3. History
  4. Number and Date Formatting
  5. Programming Delayed Logic
  6. Working with JSON
  7. Working with XML
  8. JavaScript Native Interface (JSNI)
  9. JavaScript Overlay Types
  10. Deferred Binding

Client-side code

Your application is sent across a network to a user, where it runs as JavaScript inside his or her web browser. Everything that happens within the user's web browser is referred to as client-side processing. When you write client-side code that is intended to run in the web browser, remember that it ultimately becomes JavaScript. Thus, it is important to use only libraries and Java language constructs that can be translated into JavaScript.

Creating an EntryPoint Class

To begin writing a GWT module, subclass the EntryPoint class.

Tip: GWT applicationCreator creates a starter application for you with a sample EntryPoint subclass defined.

package com.example.foo.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;

/**
 * Entry point classes define onModuleLoad().
 */
public class Foo implements EntryPoint {

  /**
   * This is the entry point method. Initialize you GWT module here.
   */
  public void onModuleLoad() { 

    // Writes Hello World to the Hosted Browser log window.
    GWT.log("Hello World!", null);
  }
}

Writing the entry point method

The entry point method is onModuleLoad(). It contains the code that executes when you launch the application. Typically, the types of things you do in the onModuleLoad() method are:

  • create new user interface components
  • set up handlers for events
  • modify the browser DOM in some way

The example above logs a message to the Hosted Browser console. If you try to run this example application in web mode, you won't see anything because the GWT.log() method is compiled away when the client-side code is translated into JavaScript.

Hello World Example

Included with the GWT distribution is a sample "Hello World" program that looks like this when run in hosted mode:

package com.google.gwt.sample.hello.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * Hello World application.
 */
public class Hello implements EntryPoint {

  public void onModuleLoad() {
    Button b = new Button("Click me", new ClickHandler() {
      public void onClick(ClickEvent event) {
        Window.alert("Hello, AJAX");
      }
    });

    RootPanel.get().add(b);
  }
}

In the entry point method for the Hello World application, the following actions were taken:

  • a new Button widget was created with the text "Click me"
  • a handler was created to respond to the user clicking the button
  • the handler pops up an Alert dialog
  • the button is added to the Root panel

Compatibility with the Java Language and Libraries

Language support

GWT supports most of the core Java language syntax and semantics, but there are a few differences you will want to be aware of.

Note: As of GWT 1.5, GWT compiles the Java language syntax that is compatible with J2SE 1.5 or earlier. Versions of GWT prior to GWT 1.5 are limited to Java 1.4 source compatibility. For example, GWT 1.6 supports generics, whereas GWT 1.4 does not.

It is important to remember that the target language of your GWT application is ultimately JavaScript, so there are some differences between running your application in hosted mode and web mode:

  • Intrinsic types: Primitive types (boolean, byte, char, short, int, long, float, and double), Object, String, arrays, user-defined classes, etc. are all supported, with a couple of caveats.
    • Arithmetic: In JavaScript, the only available numeric type is a 64-bit floating point value. All Java primitive numeric types (except for long, see below), are therefore implemented in web mode as if on doubles. Primarily, that means overflowing an integral data type (byte, char, short, int) will not wrap the underlying value as Java specifies. Instead, the resulting value will outside of the legal range for that data type. Operations on float are performed as double and will result in more-than-expected precision. Integer division is implemented to explicitly round to the correct value.
    • long: JavaScript has no 64-bit integral type, so long needs special consideration. Prior to GWT 1.5, the long type was was simply mapped to the integral range of a 64-bit JavaScript floating-point value, giving long variables an actual range less than the full 64 bits. As of GWT 1.5, long primitives are emulated as a pair of 32-bit integers, and work reliably over the entire 64-bit range. Overflow is emulated to match the expected behavior. There are a couple of caveats. Heavy use of long operations will have a performance impact due to the underlying emulation. Additionally, long primitives cannot be used in JSNI code because they are not a native JavaScript numeric type.
  • Exceptions: try, catch, finally and user-defined exceptions are supported as normal, although Throwable.getStackTrace() is not meaningfully supported in web mode.
Note: Several fundamental exceptions implicitly produced by the Java VM, most notably NullPointerException, StackOverflowError, and OutOfMemoryError, do not occur in web mode as such. Instead, a JavaScriptException is produced for any implicitly generated exceptions. This is because the nature of the underlying JavaScript exception cannot be reliably mapped onto the appropriate Java exception type.

  • Assertions: assert statements are always active in hosted mode because it's a great way for GWT libraries to provide lots of helpful error checking while you're debugging. The GWT compiler removes and ignores all assertions by default, but you can enable them in web mode by specifying the -ea flag to GWTCompiler.
  • Multithreading and Synchronization: JavaScript interpreters are single-threaded, so while GWT silently accepts the synchronized keyword, it has no real effect. Synchronization-related library methods are not available, including Object.wait(), Object.notify(), and Object.notifyAll(). The compiler will ignore the synchronized keyword but will refuse to compile your code if the Object's related synchronization methods are invoked.
  • Reflection: For maximum efficiency, GWT compiles your Java source into a monolithic script, and does not support subsequent dynamic loading of classes. This and other optimizations preclude general support for reflection. However, it is possible to query an object for its class name using Object.getClass().getName().
  • Finalization: JavaScript does not support object finalization during garbage collection, so GWT is not able to be honor Java finalizers in web mode.
  • Strict Floating-Point: The Java language specification precisely defines floating-point support, including single-precision and double-precision numbers as well as the strictfp keyword. GWT does not support the strictfp keyword and can not ensure any particular degree of floating-point precision in translated code, so you may want to avoid calculations in client-side code that require a guaranteed level of floating-point precision.

Runtime library support

GWT supports only a small subset of the classes available in the Java 2 Standard and Enterprise Edition libraries, as these libraries are quite large and rely on functionality that is unavailable within web browsers. To find out exactly which classes and methods are supported for core Java runtime packages, see the GWT JRE Emulation Reference.

Tip: You will save yourself a lot of frustration if you make sure that you use only translatable classes in your client-side code from the very beginning. To help you identify problems early, your code is checked against the JRE emulation library whenever you run in hosted mode. As a result, most uses of unsupported libraries will be caught the first time you attempt to run your application. So, run early and often.

Differences between JRE and emulated classes

Some specific areas in which GWT emulation differs from the standard Java runtime:

  • Serialization: Java serialization relies on a few mechanisms that are not available in compiled JavaScript, such as dynamic class loading and reflection. As a result, GWT does not support standard Java serialization. Instead, GWT has an RPC facility that provides automatic object serialization to and from the server for the purpose of invoking remote methods.
Note: For a list of JRE classes that GWT can translate out of the box, see the GWT JRE Emulation Reference.

Classes that provide similar functionality

In some classes, the functionality of the class is too expensive to be emulated entirely, so a similar routine in another package is provided instead. Here are some commonly used routines that provide a subset of the native JRE functionality:

History

Ajax applications sometimes fail to meet user's expectations because they do not interact with the browser in the same way as static web pages. This is often apparent -- and frustrating for users -- when an Ajax application does not integrate with browser history. For example, users expect browsers to be able to navigate back to previous pages visited using back and forward actions. Because an Ajax application is a usually single page running JavaScript logic and not a series of pages, the browser history needs help from the application to support this use case. Thankfully, GWT's history mechanism makes history support fairly straightforward.

The GWT History Mechanism

GWT's History mechanism has a lot in common with other Ajax history implementations, such as RSH (Really Simple History). The basic premise is to keep track of the application's "internal state" in the url fragment identifier. This works because updating the fragment doesn't typically cause the page to be reloaded.

This approach has several benefits:

  • It's about the only way to control the browser's history reliably.
  • It provides good feedback to the user.
  • It's "bookmarkable". I.e., the user can create a bookmark to the current state and save it, email it, et cetera.

History Tokens

GWT includes a mechanism to help Ajax developers activate browser history. For each page that is to be navigable in the history, the application should generate a unique history token. A token is simply a string that the application can parse to return to a particular state. This token will be saved in browser history as a URL fragment (in the location bar, after the "#"), and this fragment is passed back to the application when the user goes back or forward in history, or follows a link.

For example, a history token named "page1" would be added to a URL as follows:

http://www.example.com/com.example.gwt.HistoryExample/HistoryExample.html#page1

When the application wants to push a placeholder onto the browser's history stack, it simply invokes History.newItem(token). When the user uses the back button, a call will be made to any object that was added as a handler with History.addValueChangeHandler(). It is up to the application to restore the state according to the value of the new token.

Example

To use GWT History support, you must first embed an iframe into your host HTML page.

  <iframe src="javascript:''" 
          id="__gwt_historyFrame" 
          style="width:0;height:0;border:0"></iframe>

Then, in your GWT application, perform the following steps:

  • Add a history token to the history stack when you want to enable a history event.
  • Create an object that implements the ValueChangeHandler interface, parses the new token (available by calling ValueChangeEvent.getValue()) and changes the application state to match.

The following short example shows how to add a history event each time the user selects a new tab in a TabPanel.

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TabPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class BrowserHistoryExample implements EntryPoint {

  TabPanel tabPanel;
  /**
   * This is the entry point method.
   */
  public void onModuleLoad() {
    tabPanel = new TabPanel();

    tabPanel.add(new HTML("<h1>Page 0 Content: Llamas</h1>"), " Page 0 ");
    tabPanel.add(new HTML("<h1>Page 1 Content: Alpacas</h1>"), " Page 1 ");
    tabPanel.add(new HTML("<h1>Page 2 Content: Camels</h1>"), " Page 2 ");

    tabPanel.addSelectionHandler(new SelectionHandler<Integer>(){
      public void onSelection(SelectionEvent<Integer> event) {
        // TODO Auto-generated method stub
        History.newItem("page" + event.getSelectedItem());
      }});

    History.addValueChangeHandler(new ValueChangeHandler<String>() {
      public void onValueChange(ValueChangeEvent<String> event) {
        String historyToken = event.getValue();

        // Parse the history token
        try {
          if (historyToken.substring(0, 4).equals("page")) {
            String tabIndexToken = historyToken.substring(4, 5);
            int tabIndex = Integer.parseInt(tabIndexToken);
            // Select the specified tab panel
            tabPanel.selectTab(tabIndex);
          } else {
            tabPanel.selectTab(0);
          }

        } catch (IndexOutOfBoundsException e) {
          tabPanel.selectTab(0);
        }
      }
    });

    tabPanel.selectTab(0);
    RootPanel.get().add(tabPanel);
  }
}

Hyperlink Widgets

Hyperlinks are convenient to use to incorporate history support into an application. Hyperlink widgets are GWT widgets that look like regular HTML anchors. You can associate a history token with the Hyperlink, and when it is clicked, the history token is automatically added to the browser's history stack. The History.newItem(token) step is done automatically.

Stateful applications

Special care must be taken in handling history for applications that store state. Enough information must be coded into the history token to restore the application state back to the point at which the history token was set. The application must also be careful to clear away any state not relevant to navigating back to a previously visited page.

As an example, an application that presents a multi-page questionnaire could encode the page number as a token as well as some other states. When a new page in the questionnaire is presented, a history token is added to the history stack. Note that with stateful applications, such as a questionnaire, some careful thought needs to be given to implementing the history callback. When returning to a page using a token, some logic needs to restore the previous state.

Token Action
"info" Navigate to page where user enters biographic info. Restore previously entered data
"page1" Navigate to page 1 in the questionnaire. Restore previous answers.
"page2" Navigate to page 2 in the questionnaire. Restore previous answers.
"page"
<n>
Navigate to page
<n>
...
"end" Navigate to the end of the questionnaire. Validate that all questions were answered. Make sure not to re-submit the questionnaire.

In the above case, navigating back to a page would be possible, but there isn't enough information in the history token to restore the user's previous answers. A better encoding for the token would be a syntax such as:

  page=<pagename>;session=<sessionname>

Where <pagename> tells the application which page to go to and <sessionname> is a key to finding the user's previously entered data in a database.

Handling an onValueChange() callback

The first step of handling the onValueChange() callback method in a ValueChangeHandler is to get the new history token with ValueChangeEvent.getValue(); you'll then want to parse the token. Keep in mind that your parsing needs to be robust! A user may type a URL by hand or have a URL stored from an old version of your application. Once the token is parsed, you can reset the state of the application.

When the onValueChange() method is invoked, your application must handle two cases:

  1. The application was just started and was passed a history token.
  2. The application is already running and was passed a history token.

In the first case, the application must properly initialize itself before handing the state token. In the second case, some parts of the application may need to be re-initialized.

Number and Date Formatting in GWT

GWT does not provide full emulation for the date and number formatting classes (java.text.DateFormat, java.text.DecimalFormat, java.text.NumberFormat, java.TimeFormat, et cetera). Instead, a subset of the functionality of the JRE classes is provided by com.google.gwt.i18n.client.NumberFormat and com.google.gwt.i18n.client.DateTimeFormat.

The major difference between the standard Java classes and the GWT classes are is ability to switch between different locales for formating dates and numbers at runtime. In GWT, the deferred binding mechanism is used to load only the logic needed for the current locale into the application.

In order to use the NumberFormat or DateTimeFormat classes you should update your module XML file with the following inherits line:

  <inherits name="com.google.gwt.i18n.I18N"/>

See the internationalization topic for more information about setting up locale.

Using NumberFormat

When using the NumberFormat class, you do not instantiate it directly. Instead, you retrieve an instance by calling one of its static get...Format() methods. For most cases, you probably want to use the default decimal format:

    NumberFormat fmt = NumberFormat.getDecimalFormat();
    double value = 12345.6789;
    String formatted = fmt.format(value);
    // Prints 1,2345.6789 in the default locale
    GWT.log("Formatted string is" + formatted, null);

The class can also be used to convert a numeric string back into a double:

    double value = NumberFormat.getDecimalFormat().parse("12345.6789");
    GWT.log("Parsed value is" + value, null);

The NumberFormat class also provides defaults for scientific notation:

    double value = 12345.6789;
    String formatted = NumberFormat.getScientificFormat().format(value);
    // prints 1.2345E4 in the default locale
    GWT.log("Formatted string is" + formatted, null);

Note that you can also specify your own pattern for formatting numbers. In the example below, we want to show 6 digits of precision on the right hand side of the decimal and format the left hand side with zeroes up to the hundred thousands place:

    double value = 12345.6789;
    String formatted = NumberFormat.getFormat("000000.000000").format(value);
    // prints 012345.678900 in the default locale
    GWT.log("Formatted string is" + formatted, null);

Here are the most commonly used pattern symbols for decimal formats:

Symbol Meaning
0 Digit, zero forced
# Digit, zero shows as absent
. Decimal separator or monetary decimal separator
- Minus sign
, Grouping separator

Specifying an invalid pattern will cause the NumberFormat.getFormat() method to throw an java.lang.IllegalArgumentException. The pattern specification is very rich. Refer to the class documentation for the full set of features.

If you will be using the same number format pattern more than once, it is most efficient to cache the format handle returned from NumberFormat.getFormat(pattern).

Using DateTimeFormat

GWT provides the DateTimeFormat class to replace the functionality of the DateFormat and TimeFormat classes from the JRE.

For the DateTimeFormat class, there are a large number of default formats defined.

    Date today = new Date();

    // prints Tue Dec 18 12:01:26 GMT-500 2007 in the default locale.
    GWT.log(today.toString(), null);

    // prints 12/18/07 in the default locale
    GWT.log(DateTimeFormat.getShortDateFormat().format(today), null);

    // prints December 18, 2007 in the default locale
    GWT.log(DateTimeFormat.getLongDateFormat().format(today), null);

    // prints 12:01 PM in the default locale
    GWT.log(DateTimeFormat.getShortTimeFormat().format(today), null);

    // prints 12:01:26 PM GMT-05:00 in the default locale
    GWT.log(DateTimeFormat.getLongTimeFormat().format(today), null);

    // prints Dec 18, 2007 12:01:26 PM in the default locale
    GWT.log(DateTimeFormat.getMediumDateTimeFormat().format(today), null);

Like the NumberFormat class, you can also use this class to parse a date from a String into a Date representation. You also have the option of using the default formats for date and time combinations, or you may build your own using a pattern string. See the DateTimeFormat class documentation for specifics on how to create your own patterns.

Be cautious when straying from the default formats and defining your own patterns. Displaying dates and times incorrectly can be extremely aggravating to international users. Consider the date:

12/04/07

In some countries this is understood to mean the date December 4th, 2007 in others, it would be April 12th, 2007, in yet another locale, it might mean April 7th, 2012. For displaying in a common format such as this, use the default formats and let the localization mechanism in the DateTimeFormat do the work for you.

Programming Delayed Logic

Do you need to do any of the following?

  • schedule an activity for some time in the future
  • periodically query the server or update the interface
  • queue up work to do that must wait for other initialization to finish
  • perform a large amount of computation

GWT provides three classes that you can use to defer running code until a later point in time: Timer, DeferredCommand, and IncrementalCommand.

Scheduling work: the Timer class

Use the Timer class to schedule work to be done in the future.

To create a timer, create a new instance of the Timer class and then override the run() method entry point.

   Timer timer = new Timer() {
      public void run() {
    Window.alert ("Timer expired!");
      }
    };

    // Execute the timer to expire 2 seconds in the future
    timer.schedule(2000);

Notice that the timer will not have a chance to execute the run() method until after control returns to the JavaScript event loop.

Creating Timeout Logic

One typical use for a timer is to timeout a long running command. There are a few rules of thumb to remember in this situation:

  • Store the timer in an instance variable.
  • Always check to see that the timer is not currently running before starting a new one. (Check the instance variable to see that it is null.)
  • Remember to cancel the timer when the command completes successfully.
  • Always set the instance variable to null when the command completes or the timer expires.

Below is a an example of using a timeout with a Remote Procedure Call (RPC).

import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class Foo {

  // A keeper of the timer instance in case we need to cancel it
  private Timer timeoutTimer = null;

  // An indicator when the computation should quit
  private boolean abortFlag = false;

  static final int TIMEOUT = 30; // 30 second timeout

  void startWork () {

    // ...

    // Check to make sure the timer isn't already running.
    if (timeoutTimer != null) {
        Window.alert("Command is already running!");
        return;
    }

    // Create a timer to abort if the RPC takes too long
    timeoutTimer = new Timer() {
      public void run() {
        Window.alert("Timeout expired.");
        timeoutTimer = null;
        abortFlag = true;
      }
    };

    // (re)Initialize the abort flag and start the timer.
    abortFlag = false;
    timeoutTimer.schedule(TIMEOUT * 1000); // timeout is in milliseconds

    // Kick off an RPC
    myService.myRpcMethod(arg, new AsyncCallback() {

      public void onFailure(Throwable caught) {
         Window.alert("RPC Failed:" + caught);
         cancelTimer();
      }  

      public void onSuccess(Object result) {
         cancelTimer();
         if (abortFlag) {
           // Timeout already occurred. discard result
           return;
         }
         Window.alert ("RPC returned: "+ (String)result);
      }
    }
  }

  // Stop the timeout timer if it is running
  private void cancelTimer() {
    if (timeoutTimer != null) {
       timeoutTimer.cancel();
       timeoutTimer = null;
    }
  }
}

Periodically Running Logic

In order to keep a user interface up to date, you sometimes want to perform an update periodically. You might want to run a poll to the server to check for new data, or update some sort of animation on the screen. In this case, use the Timer class scheduleRepeating() method:

public class Foo {

  // A timer to update the elapsed time count
  private Timer elapsedTimer;
  private Label elapsedLabel = new Label();
  private long startTime;

  public Foo () {

    // ... Add elapsedLabel to a Panel ...

    // Create a new timer
    elapsedTimer = new Timer () {
      public void run() {
    showElapsed();
      }
    };
    
    startTime = System.currentTimeMillis();

    // Schedule the timer for every 1/2 second (500 milliseconds)
    elapsedTimer.scheduleRepeating(500);

    // ... The elapsed timer has started ...
  }

  /**
   * Show the current elapsed time in the elapsedLabel widget.
   */
  private void showElapsed () {
    double elapsedTime = (System.currentTimeMillis() - startTime) / 1000.0;
    NumberFormat n = NumberFormat.getFormat("#,##0.000");
    elapsedLabel.setText("Elapsed: " + n.format(elapsedTime));
  }
}

Deferring some logic into the immediate future: the DeferredCommand class

Sometimes you want to break up your logic loop so that the JavaScript event loop gets a chance to run between two pieces of code. The DeferredCommand class will allow you to do that. The logic that you pass to DeferredCommand will run at some point in the future, after control has been returned to the JavaScript event loop. This little delay may give the interface a chance to process some user events or initialize other code. To use the DeferredCommand class in its simplest form, you create a subclass of the Command class, overriding the execute() method and pass it to DeferredCommand.addCommand().

 
  TextBox dataEntry;

  // Set the focus on the widget after setup completes.
  DeferredCommand.addCommand(new Command() {
    public void execute () { 
      dataEntry.setFocus();
    }
  }

  dataEntry = new TextBox();

Avoiding Slow Script Warnings: the IncrementalCommand class

AJAX developers need to be aware of keeping the browser responsive to the user. When JavaScript code is running, user interface components like buttons and text areas will not respond to user input. If the browser were to allow this to continue, the user might think the browser is "hung" and be tempted to restart it. But browsers have a built-in defense mechanism, the unresponsive script warning.

Any script that runs without returning control to the JavaScript main event loop for more than 10 seconds or so runs the risk of having the browser popup this dialog to the user. The dialog is there because a poorly written script might have an infinite loop or some other bug that is keeping the browser from responding. But in AJAX applications, the script may be doing legitimate work.

GWT provides an IncrementalCommand class that helps perform long running calculations. It works by repeatedly calling an 'execute()' entry point until the computation is complete.

The following example is an outline of how to use the IncrementalCommand class to do some computation in a way that allows the browser's user interface to be responsive:

public class IncrementalCommandTest implements EntryPoint {
 
  // Number of times doWork() is called
  static final int MAX_LOOPS = 10000;

  // Tight inner loop in doWork()
  static final int WORK_LOOP_COUNT = 50;
  
  // Number of times doWork() is called in IncrementalCommand before
  // returning control to the event loop
  static final int WORK_CHUNK = 100; 
  
  // A button to kick off the computation
  Button button;

  public void onModuleLoad() {
    button = new Button("Start Computation");

    button.addClickHandler(new ClickHandler () {
      public void onClick(ClickEvent event) {
       doWorkIncremental();
      }
    }
  }

  /**
   * Create a IncrementalCommand instance that gets called back every so often
   * until all the work it has to do is complete.
   */
  private void doWorkIncremental () {

    // Turn off the button so it won't start processing again.
    button.setEnabled(false);

    IncrementalCommand ic = new IncrementalCommand(){
      int counter = 0;
     
      public boolean execute() {
        for (int i=0;i<WORK_CHUNK;i++) {
          counter++;   

          result += doWork();

          // If we have done all the work, exit with a 'false'
          // return value to terminate further execution.
          if (counter == MAX_LOOPS) {

        // Re-enable button
        button.setEnabled(true);

            // ... other end of computation processing ...

            return false;
          }
        }
        // Call the execute function again.
        return true;
      }
    };
    
    // Schedule the IncrementalCommand instance to run when 
    // control returns to the event loop by returning 'true'
    DeferredCommand.addCommand(ic);
  }

  /**
   * Routine that keeps the CPU busy for a while.
   * @return an integer result of the calculation
   */
  private int doWork() {
    int result;

    // ... computation...

    return result;
  }

Working with JSON

Many AJAX application developers have adopted JSON as the data format of choice for server communication. It is a relatively simple format based on the object-literal notation of JavaScript. If you choose to use JSON-encoded data within your application, GWT contains classes you can use to parse and manipulate JSON objects, as well as the very useful and elegant concept of JavaScript Overlay Types.

JSON encoding

The JSON format is based on the syntax and data types of the JavaScript language. It supports strings, numbers, booleans, and null values. You can also combine multiple values into arrays and objects. JSON objects are simply unordered sets of name/value pairs, where the name is always a string and the value is any other valid JSON type (even another object). Here's an example of encoding product data in JSON:

{
  "product": {
    "name": "Widget",
    "company": "ACME, Inc",
    "partNumber": "7402-129",
    "prices": [
      { "minQty": 1, "price": 12.49 },
      { "minQty": 10, "price": 9.99 },
      { "minQty": 50, "price": 7.99 }
    ]
  }
}

See json.org/example.html for more JSON examples.

Parsing JSON

GWT's JSON types are contained in a separate module, so you'll need to add the necessary <inherits> tag to your module XML file:

<inherits name="com.google.gwt.json.JSON" />

Typically, you will receive JSON data as the response text of an HTTP request. Thus, you'll first have to convert that String into a data structure you can navigate and manipulate. GWT includes the JSONParser class to handle that transformation. Its lone static method parse(String) will accept the JSON text and parses is into a set of JSONValue-derived objects.

JSONValue is the superclass of all JSON types. Each of the basic JSON types is represented by a class in the com.google.gwt.json.client package. JSONValue contains a series of methods you can use to determine which specific subtype the value represents, and if possible perform the conversion. For example, the isBoolean() method will return a JSONBoolean if the JSONValue is really a JSONBoolean, or null if it is not.

Composite JSON types contain specialized methods for accessing their members. JSONObject has get(String) and put(String, JSONValue) methods for getting and setting the object's properties. JSONArray has corresponding methods named get(int) and set(int, JSONValue).

For a complete example of parsing JSON, see the JSON section in the GWT tutorials.

Mashups with JSON and JSNI

If you're loading JSON-encoded data from your own server, you'll typically use the RequestBuilder and related classes to make HTTP requests. However, you can also retrieve JSON from remote servers in true mashup fashion using GWT's JavaScript Native Interface (JSNI) functionality. The techniques for cross-site JSON is explained more fully in the getting started tutorial. To see a working example, check out the Cross-site Client-Server Communication section of the Getting Started guide.

Working with XML

Extensible Markup Language (XML) is a data format commonly used in modern web applications. XML uses custom tags to describe data and is encoded as plain text, making it both flexible and easy to work with. The GWT class library contains a set of types designed for processing XML data.

XML types

The XML types provided by GWT can be found in the com.google.gwt.xml.client package. In order to use these in your application, you'll need to add the following <inherits> tag to your module XML file:

<inherits name="com.google.gwt.xml.XML" />

Parsing XML

To demonstrate how to parse XML with GWT, we'll use the following XML document that contains an email message:

<?xml version="1.0" ?>
<message>
  <header>
    <to displayName="Richard" address="rick@school.edu" />
    <from displayName="Joyce" address="joyce@website.com" />
    <sent>2007-05-12T12:03:55Z</sent>
    <subject>Re: Flight info</subject>
  </header>
  <body>I'll pick you up at the airport at 8:30.  See you then!</body>
</message>

Suppose that you're writing an email application and need to extract the name of the sender, the subject line, and the message body from the XML. Here is sample code that will do just that (we'll explain the code in just a bit):

private void parseMessage(String messageXml) {
  try {
    // parse the XML document into a DOM
    Document messageDom = XMLParser.parse(messageXml);
    
    // find the sender's display name in an attribute of the <from> tag
    Node fromNode = messageDom.getElementsByTagName("from").item(0);
    String from = ((Element)fromNode).getAttribute("displayName"); 
    fromLabel.setText(from);
    
    // get the subject using Node's getNodeValue() function
    String subject = messageDom.getElementsByTagName("subject").item(0).getFirstChild().getNodeValue();
    subjectLabel.setText(subject);
    
    // get the message body by explicitly casting to a Text node
    Text bodyNode = (Text)messageDom.getElementsByTagName("body").item(0).getFirstChild();
    String body = bodyNode.getData();
    bodyLabel.setText(body);    
    
  } catch (DOMException e) {
    Window.alert("Could not parse XML document.");
  }
}

The first step is to parse the raw XML text into an XML DOM structure we can use to navigate the data. GWT's XML parser is contained in the XMLParser class. Call its parse(String) static method to parse the XML and return a Document object. If an error occurs during parsing (for example, if the XML is not well-formed), the XMLParser will throw a DOMException.

If parsing succeeds, the Document object we receive represents the XML document in memory. It is a tree composed of generic Node objects. A node in the XML DOM is the basic unit of data in an XML document. GWT contains several subinterfaces of Node which provide specialized methods for processing the various types of nodes:

  • Element - represents DOM elements, which are specified by tags in XML: <someElement></someElement>.
  • Text - represents the text between the opening and closing tag of an element: <someElement>Here is some text.</someElement>.
  • Comment - represents an XML comment: <!-- notes about this data -->.
  • Attr - represents an attribute of an element: <someElement myAttribute="123" />.

Refer to the documentation for the Node interface for a complete list of types that derive from Node.

To get to the DOM nodes from the Document object, we can use one of three methods. The getDocumentElement() method retrieves the document element (the top element at the root of the DOM tree) as an Element. We can then use the navigation methods of the Node class from which Element derives (e.g., getChildNodes(), getNextSibling(), getParentNode(), etc.) to drill down and retrieve the data we need.

We can also go directly to a particular node or list of nodes using the getElementById(String) and getElementsByTagName(String) methods. The getElementById(String) method will retrieve the Element with the specified ID. If you want to use ID's in your XML, you'll need to supply the name of the attribute to use as the ID in the DTD of the XML document (just setting an attribute named id will not work). The getElementsByTagName(String) method is useful if you want to retrieve one or more elements with a particular tag name. The list of elements will be returned in the form of a NodeList object, which can be iterated over to get the individual Nodes it contains.

In the example code, we use the getElementsByTagName(String) method to retrieve the necessary elements from the XML containing the email message. The sender's name is stored as an attribute of the <from> tag, so we use getAttribute(String). The subject line is stored as text inside the <subject> tag, so we first find the subject element, and then retrieve its first (and only) child node and call getNodeValue() on it to get the text. Finally, the message body is stored in the same way (text within the <body> tag), but this time we explicitly cast the Node to a Text object and extract the text using getData().

Building an XML document

In addition to parsing existing documents, the GWT XML types can also be used to create and modify XML. To create a new XML document, call the static createDocument() method of the XMLParser class. You can then use the methods of the resulting Document to create elements, text nodes, and other XML nodes. These nodes can be added to the DOM tree using the appendChild(Node) and insertBefore(Node, Node) methods. Node also has methods for replacing and removing child nodes (replaceChild(Node, Node) and removeChild(Node), respectively).

JavaScript Native Interface (JSNI)

Often, you will need to integrate GWT with existing handwritten JavaScript or with a third-party JavaScript library. Occasionally you may need to access low-level browser functionality not exposed by the GWT class API's. The JavaScript Native Interface (JSNI) feature of GWT can solve both of these problems by allowing you to integrate JavaScript directly into your application's Java source code.

The GWT compiler translates Java source into JavaScript. Sometimes it's very useful to mix handwritten JavaScript into your Java source code. For example, the lowest-level functionality of certain core GWT classes are handwritten in JavaScript. GWT borrows from the Java Native Interface (JNI) concept to implement JavaScript Native Interface (JSNI). Writing JSNI methods is a powerful technique, but should be used sparingly because writing bulletproof JavaScript code is notoriously tricky. JSNI code is potentially less portable across browsers, more likely to leak memory, less amenable to Java tools, and harder for the compiler to optimize.

We think of JSNI as the web equivalent of inline assembly code. You can use it in many ways:

  • Implement a Java method directly in JavaScript
  • Wrap type-safe Java method signatures around existing JavaScript
  • Call from JavaScript code into Java code and vice-versa
  • Throw exceptions across Java/JavaScript boundaries
  • Read and write Java fields from JavaScript
  • Use hosted mode to debug both Java source (with a Java debugger) and JavaScript (with a script debugger, only in Windows right now)

Writing Native JavaScript Methods

JSNI methods are declared native and contain JavaScript code in a specially formatted comment block between the end of the parameter list and the trailing semicolon. A JSNI comment block begins with the exact token /*-{ and ends with the exact token }-*/. JSNI methods are called just like any normal Java method. They can be static or instance methods.

The JSNI syntax is a directive to the Java-to-JavaScript Compiler to accept any text between the comment statements as valid JS code and inject it inline in the generated GWT files. At compile time, the GWT compiler performs some syntax checks on the JavaScript inside the method, then generates interface code for converting method arguments and return values properly.

As of the GWT 1.5 release, the Java varargs construct is supported. The GWT compiler will translate varargs calls between 2 pieces of Java code. However, calling a varargs JavaScript method from Java will result in the callee receiving the arguments in an array.

Examples

Here is a simple example of how to code a JSNI method that puts up a JavaScript alert dialog:

public static native void alert(String msg) /*-{
  $wnd.alert(msg);
}-*/;

Note that the code did not reference the JavaScript window object directly inside the method. When accessing the browser's window and document objects from JSNI, you must reference them as $wnd and $doc, respectively. Your compiled script runs in a nested frame, and $wnd and $doc are automatically initialized to correctly refer to the host page's window and document.

Here is another example with a problem:

public static native int badExample() /*-{
  return "Not A Number";
}-*/;
  
 public void onClick () {
   try {
      int myValue = badExample();
      GWT.log("Got value " + myValue, null);
   } catch (Exception e) {
      GWT.log("JSNI method badExample() threw an exception:", e);
   }
 }

This example compiles as Java, and its syntax is verified by the GWT compiler as valid JavaScript. But when you run the example code in hosted mode, it returns an exception. Click on the line in the hosted mode browser to display the exception in the message area below:

com.google.gwt.dev.shell.DevGuideHostedModeException: invokeNativeInteger(@com.example.client.GWTObjectNotifyTest::badExample()): JS value of type string, expected int
    at com.google.gwt.dev.shell.JsValueGlue.getIntRange(JsValueGlue.java:343)
    at com.google.gwt.dev.shell.JsValueGlue.get(JsValueGlue.java:179)
    at com.google.gwt.dev.shell.ModuleSpace.invokeNativeInt(ModuleSpace.java:233)
    at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeInt(JavaScriptHost.java:97)
    at com.example.client.GWTObjectNotifyTest.badExample(GWTObjectNotifyTest.java:29)
    at com.example.client.GWTObjectNotifyTest$1.onClick(GWTObjectNotifyTest.java:52)
    ...

In this case, neither the Java IDE nor the GWT compiler could tell that there was a type mismatch between the code inside the JSNI method and the Java declaration. The GWT generated interface code caught the problem at runtime in hosted mode. When running in web mode, you will not see an exception. JavaScript's dynamic typing obscures this kind of problem.

Tip: Since JSNI code is just regular JavaScript, you will not be able to use Java debugging tools inside your JSNI methods when running in hosted mode. However, you can set a breakpoint on the source line containing the opening brace of a JSNI method, allowing you to see invocation arguments. Also, the Java compiler and GWT compiler do not perform any syntax or semantic checks on JSNI code, so any errors in the JavaScript body of the method will not be seen until run time.

Accessing Java Methods and Fields from JavaScript

It can be very useful to manipulate Java objects from within the JavaScript implementation of a JSNI method. However, since JavaScript uses dynamic typing and Java uses static typing, you must use a special syntax.

When writing JSNI code, it is helpful to occasionally run in web mode. The JavaScript compiler checks your JSNI code and can flag errors at compile time that you would not catch until runtime in hosted mode.

Invoking Java methods from JavaScript

Calling Java methods from JavaScript is somewhat similar to calling Java methods from C code in JNI. In particular, JSNI borrows the JNI mangled method signature approach to distinguish among overloaded methods. JavaScript calls into Java methods are of the following form:

[instance-expr.]@class-name::method-name(param-signature)(arguments)
  • instance-expr. : must be present when calling an instance method and must be absent when calling a static method
  • class-name : is the fully-qualified name of the class in which the method is declared (or a subclass thereof)
  • param-signature : is the internal Java method signature as specified here but without the trailing signature of the method return type since it is not needed to choose the overload
  • arguments : is the actual argument list to pass to the called method

Invoking Java constructors from JavaScript

Calling Java constructors from JavaScript is identical to the above use case, except that the method name is alway new.

Given the following Java classes:

package pkg;
class TopLevel {
  public TopLevel() { ... }
  public TopLevel(int i) { ... }

  static class StaticInner {
    public StaticInner() { ... }
  }

  class InstanceInner {
    public InstanceInner(int i) { ... }
  }
}

We compare the Java expression versus the JSNI expression:

  • new TopLevel() becomes @pkg.TopLevel::new()()
  • new StaticInner() becomes @pkg.TopLevel.StaticInner::new()()
  • someTopLevelInstance.new InstanceInner(123) becomes @pkg.TopLevel.InstanceInner::new(Lpkg/TopLevel;I)(someTopLevelInstance, 123)
    • The enclosing instance of a non-static class is implicitly defined as the first parameter for constructors of a non-static class. Regardless of how deeply-nested a non-static class is, it only needs a reference to an instance of its immediately-enclosing type.

Accessing Java fields from JavaScript

Static and instance fields can be accessed from handwritten JavaScript. Field references are of the form

[instance-expr.]@class-name::field-name

Example

public class JSNIExample {

  String myInstanceField;
  static int myStaticField;

  void instanceFoo(String s) {
    // use s
  }

  static void staticFoo(String s) {
    // use s
  }

  public native void bar(JSNIExample x, String s) /*-{
    // Call instance method instanceFoo() on this
    this.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);

    // Call instance method instanceFoo() on x
    x.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);

    // Call static method staticFoo()
    @com.google.gwt.examples.JSNIExample::staticFoo(Ljava/lang/String;)(s);

    // Read instance field on this
    var val = this.@com.google.gwt.examples.JSNIExample::myInstanceField;

    // Write instance field on x
    x.@com.google.gwt.examples.JSNIExample::myInstanceField = val + " and stuff";

    // Read static field (no qualifier)
    @com.google.gwt.examples.JSNIExample::myStaticField = val + " and stuff";
  }-*/;

}
Tip: As of the GWT 1.5 release, the Java varargs construct is supported. The GWT compiler will translate varargs calls between two pieces of Java code, however, calling a varargs Java method from JSNI will require the JavaScript caller to pass an array of the appropriate type.

Calling a Java Method from Handwritten JavaScript

Sometimes you need to access a method or constructor defined in GWT from outside JavaScript code. This code might be hand-written and included in another java script file, or it could be a part of a third party library. In this case, the GWT compiler will not get a chance to build an interface between your JavaScript code and the GWT generated JavaScript directly.

A way to make this kind of relationship work is to assign the method via JSNI to an external, globally visible JavaScript name that can be referenced by your hand-crafted JavaScript code.

package mypackage;

public MyUtilityClass
{
    public static int computeLoanInterest(int amt, float interestRate, 
                                          int term) { ... }
    public static native void exportStaticMethod() /*-{
       $wnd.computeLoanInterest =
          @mypackage.MyUtilityClass::computeLoanInterest(IFI);
    }-*/;
}

On application initialization, call MyUtilityClass.exportStaticMethod() (e.g. from your GWT Entry Point). This will assign the function to a variable in the window object called computeLoanInterest.

Sharing objects between Java source and JavaScript

Parameters and return types in JSNI methods are declared as Java types. There are very specific rules for how values passing in and out of JavaScript code must be treated. These rules must be followed whether the values enter and leave through normal Java method call semantics or through the special syntax by which Java methods are invoked from JSNI code.

Passing Java values into JavaScript

Incoming Java type How it appears to JavaScript code
String JavaScript string, as in var s = "my string";
boolean JavaScript boolean value, as in var b = true;
long disallowed (see notes)
other numeric primitives JavaScript numeric value, as in var x = 42;
JavaScriptObject JavaScriptObject that must have originated from JavaScript code, typically as the return value of some other JSNI method (see notes)
Java array opaque value that can only be passed back into Java code
any other Java Object opaque value accessible through special syntax

Passing JavaScript values into Java code

Outgoing Java type What must be passed
String JavaScript string, as in return "boo";
boolean JavaScript boolean value, as in return false;
long disallowed (see notes)
Java numeric primitive JavaScript numeric value, as in return 19;
JavaScriptObject native JavaScript object, as in return document.createElement("div") (see notes)
any other Java Object (including arrays) Java Object of the correct type that must have originated in Java code; Java objects cannot be constructed from "thin air" in JavaScript

Important Notes

  • The Java long type cannot be represented in JavaScript as a numeric type, so GWT emulates it using an opaque data structure. This means that JSNI methods cannot process a long as a numeric type. The compiler therefore disallows, by default, directly accessing a long from JSNI: JSNI methods cannot have long as a parameter type or a return type, and they cannot access a long using a JSNI reference. If you find yourself wanting to pass a long into or out of a JSNI method, here are some options:
    1. For numbers that fit into type double, use type double instead of type long.
    2. For computations that require the full long semantics, rearrange the code so that the computations happen in Java instead of in JavaScript. That way they will use the long emulation.
    3. For values meant to be passed through unchanged to Java code, wrap the value in a Long. There are no restrictions on type Long with JSNI methods.
    4. If you are sure you know what you are doing, you can add the annotation com.google.gwt.core.client.UnsafeNativeLong to the method. The compiler will then allow you to pass a long into and out of JavaScript. It will still be an opaque data type, however, so the only thing you will be able to do with it will be to pass it back to Java.
  • Violating any of these marshaling rules in hosted mode will generate a com.google.gwt.dev.shell.DevGuideHostedModeException detailing the problem. This exception is not translatable and never thrown in web mode.
  • JavaScriptObject gets special treatment from the GWT compiler and hosted browser. Its purpose is to provide an opaque representation of native JavaScript objects to Java code.

  • Java null and JavaScript null are identical and always legal values for any non-primitive Java type. JavaScript undefined is also considered equal to null when passed into Java code (the rules of JavaScript dictate that in JavaScript code, null == undefined is true but null === undefined is false). In previous versions of GWT, undefined was not a legal value to pass into Java.

Exceptions and JSNI

An exception can be thrown during the execution of either normal Java code or the JavaScript code within a JSNI method. When an exception generated within a JSNI method propagates up the call stack and is caught by a Java catch block, the thrown JavaScript exception is wrapped as a JavaScriptException object at the time it is caught. This wrapper object contains only the class name and description of the JavaScript exception that occurred. The recommended practice is to handle JavaScript exceptions in JavaScript code and Java exceptions in Java code.

A Java exception can safely retain identity while propagating through a JSNI method.

For example,

  1. Java method doFoo() calls JSNI method nativeFoo()
  2. nativeFoo() internally calls Java method fooImpl()
  3. fooImpl() throws an exception

The exception thrown from fooImpl() will propagate through nativeFoo() and can be caught in doFoo(). The exception will retain its type and identity.

JavaScript Overlay Types

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.6. 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 combine RequestBuilder and 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.

Deferred Binding

Deferred binding is a feature of the GWT compiler that works by generating many versions of code at compile time, only one of which needs to be loaded by a particular client during bootstrapping at runtime. Each version is generated on a per browser basis, along with any other axis that your application defines or uses. For example, if you were to internationalize your application using GWT's Internationalization module, the GWT compiler would generate various versions of your application per browser environment, such as "Firefox in English", "Firefox in French", "Internet Explorer in English", etc... As a result, the deployed JavaScript code is compact and quicker to download than hand coded JavaScript, containing only the code and resources it needs for a particular browser environment.

Deferred Binding Benefits

Deferred Binding is a technique used by the GWT compiler to create and select a specific implementation of a class based on a set of parameters. In essence, deferred binding is the Google Web Toolkit answer to Java reflection. It allows the GWT developer to produce several variations of their applications custom to each browser environment and have only one of them actually downloaded and executed in the browser.

Deferred binding has several benefits:

  • Reduces the size of the generated JavaScript code that a client will need to download by only including the code needed to run a particular browser/locale instance (used by the Internationalization module)
  • Saves development time by automatically generating code to implement an interface or create a proxy class (used by the GWT RPC module)
  • Since the implementations are pre-bound at compile time, there is no run-time penalty to look up an implementation in a data structure as with dynamic binding or using virtual functions.

Some parts of the toolkit make implicit use of deferred binding, that is, they use the technique as a part of their implementation, but it is not visible to the user of the API. For example, many widgets and panels as well as the DOM class use this technique to implement browser specific logic. Other GWT features require the API user to explicity invoke deferred binding by designing classes that follow specific rules and instantiating instances of the classes with GWT.create(Class), including GWT RPC and I18N.

As a user of the Google Web Toolkit, you may never need to create a new interface that uses deferred binding. If you follow the instructions in the guide for creating internationalized applications or GWT RPC calls you will be using deferred binding, but you will not have to actually write any browser dependent or locale dependent code.

The rest of the deferred binding section describes how to create new rules and classes using deferred binding. If you are new to the toolkit or only intend to use pre-packaged widgets, you will probably want to skip on to the next topic. If you are interested in programming entirely new widgets from the ground up or other functionality that requires cross-browser dependent code, the next sections should be of interest.

Defining Deferred Binding Rules

There are two ways in which types can be replaced via deferred binding:

  • Replacement: A type is replaced with another depending on a set of configurable rules.
  • Code generation: A type is substituted by the result of invoking a code genreator at compile time.

Directives in Module XML files

The deferred binding mechanism is completely configurable and does not require editing the GWT distributed source code. Deferred binding is configured through the <replace-with> and <generate-with> elements in the module XML files. The deferred binding rules are pulled into the module build through <inherits> elements.

For example, the following configuration invokes deferred binding for the PopupPanel widget:

Inside the PopupPanel module XML file, there happens to be some rules defined for deferred binding. In this case, we're using a replacement rule.

Deferred Binding Using Replacement

The first type of deferred binding uses replacement. Replacement means overriding the implementation of one java class with another that is determined at compile time. For example, this technique is used to conditionalize the implementation of some widgets, such as the PopupPanel. The use of <inherits> for the PopupPanel class is shown in the previous section describing the deferred binding rules. The actual replacement rules are specified in Popup.gwt.xml, as shown below:

<module>

  <!--  ... other configuration omitted ... -->

  <!-- Fall through to this rule is the browser isn't IE or Mozilla -->
  <replace-with class="com.google.gwt.user.client.ui.impl.PopupImpl">
    <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/>
  </replace-with>

  <!-- Mozilla needs a different implementation due to issue #410 -->
  <replace-with class="com.google.gwt.user.client.ui.impl.PopupImplMozilla">
    <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl" />
    <any>
      <when-property-is name="user.agent" value="gecko"/>
      <when-property-is name="user.agent" value="gecko1_8" />
    </any>
  </replace-with>
  
  <!-- IE has a completely different popup implementation -->
  <replace-with class="com.google.gwt.user.client.ui.impl.PopupImplIE6">
    <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/>
    <when-property-is name="user.agent" value="ie6" />
  </replace-with>
</module>

These directives tell the GWT compiler to swap out the PoupImpl class code with different class implementations according to the the user.agent property. The Popup.gwt.xml file specifies a default implementation for the PopupImpl class, an overide for the Mozilla browser (PopupImplMozilla is substituted for PopupImpl), and an override for Internet Explorer version 6 (PopupImplIE6 is substituted for PopupImpl). Note that PopupImpl class or its derived classes cannot be instantiated directly. Instead, the PopupPanel class is used and the GWT.create(Class) technique is used under the hood to instruct the compiler to use deferred binding.

Example Class Hierarchy using Replacement

To see how this is used when designing a widget, we will examine the case of the PopupPanel widget further. The PopupPanel class implements the user visible API and contains logic that is common to all browsers. It also instantiates the proper implementation specific logic using the GWT.create(Class) as follows:

  private static final PopupImpl impl = GWT.create(PopupImpl.class);

The two classes PopupImplMozilla and PopupImplIE6 extend the PopupImpl class and override some PopupImpl's methods to implement browser specific behavior.

Then, when the PopupPanel class needs to switch to some browser dependent code, it accesses a member function inside the PopupImpl class:

  public void setVisible(boolean visible) {
    // ... common code for all implementations of PopupPanel ...

    // If the PopupImpl creates an iframe shim, it's also necessary to hide it
    // as well.
    impl.setVisible(getElement(), visible);
  }

The default implementation of PopupImpl.setVisible() is empty, but PopupImplIE6 has some special logic implemented as a JSNI method:

  public native void setVisible(Element popup, boolean visible) /*-{
    if (popup.__frame) {
      popup.__frame.style.visibility = visible ? 'visible' : 'hidden';
    }
  }-*/;{

After the GWT compiler runs, it prunes out any unused code. If your application references the PopupPanel class, the compiler will create a separate JavaScript output file for each browser, each containing only one of the implementations: PopupImpl, PopupImplIE6 or PopupImplMozilla. This means that each browser only downloads the implementation it needs, thus reducing the size of the output JavaScript code and minimizing the time needed to download your application from the server.

Deferred Binding using Generators

The second technique for deferred binding consists of using generators. Generators are classes that are invoked by the GWT compiler to generate a Java implementation of a class during compilation. When compiling to web mode, this generated implementation is directly translated to one of the versions of your application in JavaScript code that a client will download based on its browser environment.

The following is an example of how a deferred binding generator is specified to the compiler in the module XML file hierarchy for the RemoteService class - used for GWT-RPC:

Generator Configuration in Module XML

The XML element <generate-with> tells the compiler to use a Generator class. Here are the contents of the RemoteService.gwt.xml file relevant to deferred binding:

<module>

 <!--  ... other configuration omitted ... -->
    
 <!-- Default warning for non-static, final fields enabled -->
 <set-property name="gwt.suppressNonStaticFinalFieldWarnings" value="false" />

 <generate-with class="com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator">
   <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService" />
 </generate-with>
</module>

These directives instruct the GWT compiler to invoke methods in a Generator subclass (ServiceInterfaceProxyGenerator) in order to generate special code when the deferred binding mechanism GWT.create() is encountered while compiling. In this case, if the GWT.create() call references an instance of RemoteService or one of its subclasses, the ServiceInterfaceProxyGenerator's generate()` method will be invoked.

Generator Implementation

Defining a subclass of the Generator class is much like defining a plug-in to the GWT compiler. The Generator gets called to generate a Java class definition before the Java to JavaScript conversion occurs. The implementation consists of one method that must output Java code to a file and return the name of the generated class as a string.

The following code shows the Generator that is responsible for deferred binding of a RemoteService interface:

/**
 * Generator for producing the asynchronous version of a
 * {@link com.google.gwt.user.client.rpc.RemoteService RemoteService} interface.
 */
public class ServiceInterfaceProxyGenerator extends Generator {

  /**
   * Generate a default constructible subclass of the requested type. The
   * generator throws <code>UnableToCompleteException</code> if for any reason
   * it cannot provide a substitute class
   * 
   * @return the name of a subclass to substitute for the requested class, or
   *         return <code>null</code> to cause the requested type itself to be
   *         used
   * 
   */
  public String generate(TreeLogger logger, GeneratorContext ctx,
      String requestedClass) throws UnableToCompleteException {

    TypeOracle typeOracle = ctx.getTypeOracle();
    assert (typeOracle != null);

    JClassType remoteService = typeOracle.findType(requestedClass);
    if (remoteService == null) {
      logger.log(TreeLogger.ERROR, "Unable to find metadata for type '"
          + requestedClass + "'", null);
      throw new UnableToCompleteException();
    }

    if (remoteService.isInterface() == null) {
      logger.log(TreeLogger.ERROR, remoteService.getQualifiedSourceName()
          + " is not an interface", null);
      throw new UnableToCompleteException();
    }

    ProxyCreator proxyCreator = new ProxyCreator(remoteService);

    TreeLogger proxyLogger = logger.branch(TreeLogger.DEBUG,
        "Generating client proxy for remote service interface '"
            + remoteService.getQualifiedSourceName() + "'", null);

    return proxyCreator.create(proxyLogger, ctx);
  }
}

The typeOracle is an object that contains information about the Java code that has already been parsed that the generator may need to consult. In this case, the generate() method checks it arguments and the passes off the bulk of the work to another class (ProxyCreator).