My favorites | English | Sign in

Faster apps faster - GWT 2.0 with Speed Tracer New!

Google Web Toolkit

What's New in GWT 1.6?

GWT 1.6 includes direct support for web archive (war) output, faster compilation, new widgets, new-and-improved event handling, and much more. In addition, GWT 1.6 resolves dozens of bugs from the GWT issue tracker. If you're currently using GWT 1.5, follow the step-by-step instructions for upgrading existing projects to GWT 1.6.

  1. New Features
  2. Bug Fixes
  3. How to Upgrade

New Features

New Project Structure

One of the biggest changes to GWT 1.6 is a new project structure. The old output format has been replaced by the standard Java web app "expanded war" format, and the actual directory name does default to "/war". Note that the war directory is not only for compiler output; it is also intended to contain handwritten static resources that you want to be included in your webapp alongside GWT modules (that is, things you'd want to version control). Please also note that the "GWTShell" and "GWTCompiler" tools will maintain their legacy behavior, but they have been deprecated in favor of new HostedMode and Compiler tools which use the new war output. When 1.6 is officially released, we will be encouraging existing projects to update to the new directory format and to use the new tools to take advantage of new features and for compatibility with future GWT releases.

The sample projects provided in the GWT distribution provide an example of correct new project configurations. For more details on the specifics of the new project format, please see the design document.

A couple of important changes to highlight here:

  • Projects with server-side code (GWT RPC) must configure a web.xml file at /war/WEB-INF/web.xml. This web.xml file must define and publish any servlets associated with the web application. See the included DynaTable sample. Additionally, server-side library dependencies must be copied into /war/WEB-INF/lib. For example, any GWT RPC servlets must have a copy of gwt-servlet.jar in this folder.
  • HTML host pages will no longer typically be located in a GWT module's public path. Instead, we'll be recommending that people take advantage of the natural web app behavior for serving static files by placing host pages anywhere in the war structure that makes sense. For example, you might want to load a GWT module from a JSP page located in the root of your web app. To keep such handwritten static files separate from those produced by the GWT compiler, the latter will be placed into module-specific subdirectories. Any page that wishes to include a GWT module can do so via a script tag by referencing the GWT-produced <module>.nocache.js script within that module's subdirectory. As of 1.6, we'll be recommending that only module-specific resources used directly by GWT code, such as image files needed by widgets, should remain on the public path. See the included Showcase sample for some examples of this distinction.
  • When you do need to load resources from a module's public path, always construct an absolute URL by prepending GWT.getModuleBaseURL(). For example, GWT.getModuleBaseURL() + "dir/file.ext". This advice has not changed, but in the past it was easy to be sloppy with this, because the host page and GWT module typically lived in the same directory, so using a relative URL would usually do the right thing. Now that GWT modules live in a subdirectory, you must reference public resources through GWT.getModuleBaseURL().

Hosted Mode Enhancements

Although the legacy GWTShell still uses an embedded Tomcat server, the new HostedMode runs Jetty instead. There is also a new "Restart Server" button on the main hosted mode window. Clicking this button restarts the internal Jetty server, which allows Java code changes to take effect on the server without having to completely exit and restart hosted mode. This is useful when making code changes to RPC servlets, or when serializable RPC types are modified and the server and client are out of sync.

New EventHandler System

Event handlers have been added to replace the old event listeners used by Widgets, History, and various other classes. The new system has a few differences from the old system:

  • EventHandler methods always take a single parameter: the GwtEvent that the widget fired. For example, ClickHandler has a single method onClick(ClickEvent).
  • Each GwtEvent contains accessors relevant to the event, such as the key that was pressed on KeyEvents. Native events provide access to the underlying native event object.
  • Each EventHandler defines only one method, so you do not need to create empty methods just to satisfy the interface requirements.

For users who create their own Widgets, you no longer need to manage listeners manually. Every widget has a HandlerManager that manages all of its handlers. For native events, such as ClickEvent, just call addDomHandler() from within your code to register a handler and sink the associated event on the Widget. When the native event is detected, the handler will automatically be called. For logical events, such as SelectionEvent, call addHandler() and fire the event manually using the fireEvent() method.

You can see examples of EventHandler usage in many of the updated GWT widgets and samples, or in new projects created with the new webAppCreator tool.

Creation and Triggering of Native Events

You can now trigger a native event on almost any element. Create a new native event using the Document.create*Event() methods, then dispatch it on a specific element by calling Element.dispatchEvent(). These methods allow you to expand your test coverage in ways that were previously impossible.

New Widgets

DatePicker Widget

The new DatePicker and DateBox widgets allow your users to select a date from a calendar. The Showcase sample provides examples of both of these widgets.

LazyPanel Widget

The new LazyPanel widget allows you to delay the creation of certain sections of your application until they are first accessed, improving startup performance. For example, if your application has a seldom used "Help" section, you can wrap it in a LazyPanel and create the user interface only if and when the user tries to access it. To use the LazyPanel, extend the class and override the abstract createWidget() method. The createWidget() method will be called the first time you call setVisible() on the LazyPanel.

Bug Fixes

GWT 1.6 includes lots of bugfixes (as well as little enhancements that didn't make it into the "New Features" section), including

  • Issue 1032: An often-requested bug related to class loading affecting Maven plugins
  • Issue 2906: SortedSet is now serializable
  • Issue 779: GWT now works with EMMA to support code coverage during unit tests
  • Issue 2223: @Override is now allowed on methods implementing interfaces, making GWT work more smoothly with Java 6 SDKs

These are but a few. For more details, see the full list of issues addressed in 1.6 in the GWT issue tracker.

Upgrading

There are four tasks involved when upgrading a GWT 1.5 project to a GWT 1.6 project:

  • Download the new JAR files and update your launch configurations.
  • GWTShell has been replaced by HostedMode, so you will need to update your Eclipse project settings accordingly.
  • GWT now uses a war directory for most public resource and server configuration files. The war directory is a standard directory recognized by many web servers, including GWT hosted mode.
  • Event listeners have been replaced by event handlers.

Download GWT 1.6

  1. Download GWT 1.6 for your platform and unpack it to the directory of your choice.
  2. Update your GWT project build path to use the latest GWT JARs. This includes gwt-user.jar and gwt-dev-<platform>.jar.
  3. Update any run configurations or application compile and shell scripts to include the latest JARs in the classpath (same JARs as mentioned in step 2).
  4. Run a GWT compilation over your project to generate the latest GWT application files for your project.
  5. Deploy the latest GWT application files to your web server.

Switch from GWTShell to HostedMode

After upgrading to the GWT 1.6 jars, you will see the following message when running hosted mode using the GWTShell:

WARNING: 'com.google.gwt.dev.GWTShell' is deprecated and will be removed in a future release.
Use 'com.google.gwt.dev.HostedMode' instead.

In order to eliminate this warning, change your main class from com.google.gwt.dev.GWTShell to com.google.gwt.dev.HostedMode. HostedMode takes different arguments, so you will need to modify those as well. Specifically, you need to remove the -out argument if you use it, and you need to add a -startupUrl argument that takes the name of your host page. For example, if your host page is TestApp.html, you would add the argument "-startupUrl TestApp.html". Finally, HostedMode takes the module name as its last argument. If you currently pass the host page into GWTShell as part of the module name, you'll need to remove it.

For example, the following program arguments:

-out www com.google.gwt.TestApp/TestApp.html
become:
-startupUrl TestApp.html com.google.gwt.TestApp

Open your module .gwt.xml file and add a rename-to attribute to the module definition. When your module is compiled, it will be output to a directory with this name. For example, the following would output your app to a directory called 'testapp' in the war directory.

<module rename-to='testapp'>
  ...
</module>

You will need to create a war directory as described in the next section before you can run your application.

Creating a directory

The war directory is a standard way of specifying server files including static resources, server configuration files, and classes used by the RPC servlet. Create a war/ directory on the same level as your src/ directory, and add a WEB-INF/ directory inside of it. In the WEB-INF/ directory, add a lib/ directory with the gwt-servlet.jar file and any other libraries that your project relies on. Now, move your host .html page and public resources into the war/ directory. Your file structure should look like this when complete:

+ TestApp/
  + src/
  + war/
    + WEB-INF
        + lib/
            gwt-servlet.jar
        web.xml
      TestApp.css
      TestApp.html

All files in the war directory will be available as static resources. Files in the WEB-INF directory will be available on the server only. You may choose which public resources you move to the war directory. If you want a resources, such as an image or CSS file, to only be available within the compiled folder of your GWT app, you can leave it in the public directory of your application.

Now, open the host page and add the output directory as a prefix to the nocache.js file. The output directory is the name you used in the rename-to attribute of the module definition. For example, this:

<script type="text/javascript" language="javascript" src="com.google.gwt.TestApp.nocache.js"></script>

becomes:

<script type="text/javascript" language="javascript" src="testapp/testapp.nocache.js"></script>

In your host page, you should also update any references to style sheets or other javascript files. Remember that files in your public/ directory will now be output to the testapp directory. If you include a style sheet in your module gwt.xml file, you'll need to leave the style sheet in the public/ directory where it usually sits. However, if include your style sheet directly from your host page .html file, you should update the path as needed when you move the files to your war directory.

The web.xml file contains information to configure your server. Copy and paste the following into the web.xml file, modifying it as needed.

<?xml version="1.0" encoding="UTF-8"?>
<web-app>

  <!-- Default page to serve -->
  <welcome-file-list>
    <welcome-file>TestApp.html</welcome-file>
  </welcome-file-list>
  
  <!-- Servlets -->
  <servlet>
    <servlet-name>echoServlet</servlet-name>
    <servlet-class>com.google.gwt.server.EchoServiceImpl</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>echoServlet</servlet-name>
    <url-pattern>/testapp/echo</url-pattern>
  </servlet-mapping>

</web-app>

Replace the welcome-file with the name of your host page.

If your GWT application does not use RPC, you can remove the servlets section. Otherwise, replace the servlet name, class, and url-pattern with whatever you want to use. The servlet-name is just a convenience used within the web.xml file, so you can change it to something descriptive. The servlet-class should point to a RemoteServiceServlet implementation. The url-pattern refers to the URL used to access the service, which you set via ServiceDefTarget.setServiceEntryPoint() when creating the service or with a @RemoteServiceRelativePath annotation in your RemoteService definition. In the example above, the echo part of the url-pattern came from an annotation (the /testapp/ prefix comes from the rename-to attribute on the GWT module definition):

@RemoteServiceRelativePath("echo")
public interface EchoService extends RemoteService {
  String echo(String input);
}

The last thing that you need to put in your war directory is the compiled classes used by your RPC server. If you do not use an RPC server, this step is not technically required, but it is good practice to be consistent with GWT modules created with GWT 1.6. Change the output location of your compiled classes to war/WEB-INF/classes/. If you are using Eclipse, do the following:

  1. Right click on the project and select 'properties'
  2. Select 'Java Build Path'
  3. Select the 'Source' tab
  4. Change the 'Default output folder' to '<project-name>/war/WEB-INF/classes'

Using EventHandler instead of EventListener

You may have noticed some deprecation warnings in your project after updating to GWT 1.6. The old EventListener classes have been replaced by EventHandlers, so you'll want to upgrade your code accordingly. Before completing this step, you should read the Events and Handlers Developers Guide to familiarize yourself with the new handlers.

In general, replacing a listener with a handler is very simple. The handler is usually named with a similar name and contains a similar method. The main difference is that each EventHandler method takes a single GwtEvent as an argument, whereas listener methods take a set of parameters. The GwtEvent usually contains all of the information that would be passed to a listener. For example, to replace a ClickListener with an equivalent ClickHandler, you would replace this:

closeButton.addClickListener(new ClickListener() {
  public void onClick(Widget sender) {
    dialogBox.hide();
  }
});

with this:

closeButton.addClickHandler(new ClickHandler() {
  public void onClick(ClickEvent event) {
    dialogBox.hide();
  }
});

In some cases, a listener has been replaced by multiple handlers. For example, TabListener contains two methods: onBeforeTabSelection() and onTabSelected(). This has been replaced by a BeforeSelectionHandler and a SelectionHandler. The JavaDoc for each listener method will tell you which handler replaced it.

Widget Developers

If you develop your own widgets and have overridden Widget.onBrowserEvent(), make sure that your override calls super.onBrowserEvent(). The Widget.onBrowserEvent() method contains code to automatically fire native events to their associated EventHandlers, so if you override the code and do not call the super method, your EventHandlers will not fire.

For example, this will not automatically call ClickHandlers added using the Widget.addDomHandler() method:

public class MyWidget extends Widget {
  @Override
  public void onBrowserEvent(Event event) {
    if (DOM.eventGetType(event) == Event.ONCLICK) {
      // Do something with click
    }
  }
}

but this code will:

public class MyWidget extends Widget {
  @Override
  public void onBrowserEvent(Event event) {
    super.onBrowserEvent(event);
    if (DOM.eventGetType(event) == Event.ONCLICK) {
      // Do something with click
    }
  }
}

An even better alternative is to use an anonymous inner class to handle the ClickEvent as follows (notice how we no longer need to override onBrowserEvent()):

public class MyWidget extends Widget {
  public MyWidget() {
    addDomHandler(new ClickHandler() {
      public void onClick(ClickEvent event) {
        // Do something with click
      }
    }, ClickEvent.getType());
  }
}

Any problems while upgrading? As always, let us know on the GWT Developer Forum and our great community or GWT team members will get back to you to make sure the upgrade process detailed in this guide is accurate and works for our users.