Google Code offered in: English - Español - 日本語 - 한국어 - Português - Pусский - 中文(简体) - 中文(繁體)
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.
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:
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.
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:
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.
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.
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.
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.
GWT 1.6 includes lots of bugfixes (as well as little enhancements that didn't make it into the "New Features" section), including
These are but a few. For more details, see the full list of issues addressed in 1.6 in the GWT issue tracker.
There are four tasks involved when upgrading a GWT 1.5 project to a GWT 1.6 project:
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.htmlbecome:
-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.
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:
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.
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.