New GWT UiBinder

Moving towards GWT 3

Vertispan LLC, Justin Hickman

GWT 3 is currently in active development, and to handle some core architectural changes many of the GWT modules are being updated and some being completely rewritten. The UiBinder module in particular needed somewhat of an overhaul to handle these upcoming changes.

One of the biggest changes in GWT 3 is how the generators work. To reduce the maintenance required to support the custom generator APIs in previous versions of GWT, the use of generators are being removed completely in favor of using Java annotation processing with the Annotation Processing Tool (APT). 

What is UiBinder

Although I won't go into a full API description or documentation of UiBinder, there are some key parts that should be noted in relation to where we were, and where we are going.

GWT Widgets, just as with most other widget/ui frameworks, is capable of building very complex user interfaces by programmatically instantiating objects and calling methods on them to build a hierarchy of these objects. UiBinder provides developers the means of building user interfaces in a more declarative way (via XML), which is a more natural way of building user interfaces.

There are several advantages and benefits to writing UIs with UiBinder

  • helps productivity and maintainability — it’s easy to create UI from scratch or copy/paste across templates;

  • makes it easier to collaborate with UI designers who are more comfortable with XML, HTML and CSS than Java source code;

  • provides a gradual transition during development from HTML mocks to real, interactive UI;

  • encourages a clean separation of the aesthetics of your UI (a declarative XML template) from its programmatic behavior (a Java class);

  • performs thorough compile-time checking of cross-references from Java source to XML and vice-versa;

  • offers direct support for internationalization that works well with GWT’s i18n facility; and

  • encourages more efficient use of browser resources by making it convenient to use lightweight HTML elements rather than heavier-weight widgets and panels.

More information can be found over at gwtproject.org.

Getting Started with the New UiBinder

At the time of this writing, none of the new GWT UiBinder jars have been uploaded to maven central. However, these jars can be obtained either through the Vertispan maven repository, downloading of the prebuilt jars from the Vertispan build server, or can be manually built using Maven.

Configuring Maven

The easiest way to get the jars for the new UiBinder is to configure the Vertispan maven repository for gwt project snapshots. Add the following <repository> section to your $HOME/.m2/settings.xml

<repositories>
<repository>
<id>gwtproject-snapshots</id>
<url>https://repo.vertispan.com/gwt-snapshot/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

Once the <repository> is added, update your client module pom to include the following dependencies. 

  <dependency>
    <groupId>org.gwtproject.uibinder</groupId>
    <artifactId>gwt-uibinder-client</artifactId>
    <version>1.0.0-SNAPSHOT</version>
  </dependency>
  <dependency>
    <groupId>org.gwtproject.uibinder</groupId>
    <artifactId>gwt-uibinder-processor</artifactId>
    <version>1.0.0-SNAPSHOT</version>
  </dependency>


Building

Building from source is really straight forward. From a fresh checkout of the code from the GitHub repository, perform a manual maven build with the following command and add the dependencies to your client module pom as described above. This will build and add the jar snapshots to your local machine maven repository.

mvn clean install


Usage and Notable Changes 

The new GWT UiBinder has been completely renamespaced to the org.gwtproject.uibinder package. This means that both the old AND new UiBinder modules can be imported and used without interference between the two in a single GWT application. This can be beneficial in multiple ways, specifically with giving the ability to migrate your application from the old to the new.

Import the module in your gwt.xml file and you'll be all set.

<!-- new UiBinder -->
<inherits name="org.gwtproject.uibinder.UiBinder"/>


Most of the functionality from the original UiBinder still exists, so anyone familiar with UiBinder development will be at ease with the changes in this module. The goal from the beginning was to be feature parity with the old module. Today, there are only a few minor differences to note.


@UiTemplate is Required

The @UiTemplate annotation was carried over from GWT 2 UiBinder, but with some slight modifications. With the former GWT 2 generator for UiBinder, the generator was able to locate the associated .ui.xml file automatically based upon the name of the owning class. For example, a class named MyView would attempt to locate a MyView.ui.xml. If, however, the name of the file were something different, the @UiTemplate annotation can be added and the value attribute would represent the name of the .ui.xml to look up.

@UiTemplate(value = "MyOtherViewTemplate.ui.xml")
interface SomeUiBinder extends UiBinder<Widget, MyView> {}


With the former GWT 2 generators, code generation can be configured to look for specific interfaces or classes. However with APT, annotations are required. Using the existing @UiTemplate annotation made the most sense for triggering the annotation processing. Unlike the GWT 2 UiBinder, the value attribute for @UiTemplate is now optional. Having the value attribute behaves just as it did before, but without, the default behavior is to locate the .ui.xml file based upon the name of the owning class. 

Other than that, setup for the rest is essentially identical with the documentation on gwtproject.org. Just remember to check your imports in both the owning class as well as the .ui.xml urn:import's to make sure they point to the new org.gwtproject classes.


GWT.create() is no longer used

GWT.create(Class<?>) has traditionally been the way for GWT applications to return the appropriate instance for the current permutation. With the switchover to APT, GWT.create is no longer used. The implementation to the UiBinder interface is created during compile time with the naming convention:

<owning_class>_<uibinderinterface>Impl

This naming convention is subject to change in later builds.


Widget Support

The current iteration of the new GWT UiBinder uses legacy GWT Widgets. This means that all of the existing HasWidgets, HasHTML, etc all work as before with building the structure inside of a .ui.xml file. Supporting legacy widgets is subject to change in later releases. This change depends on when/if the legacy widgets migrate or some other widget/ui mechanism is added. 

Also, any owning class annotations such as @UiFactory, @UiHandler, @UiChild, @UiConstructor, etc all work the same - be sure to use from the new namespace.


Example

Here is an example of an owning class to a UiBinder template. As you can see, it is analogous to previous versions as a new interface will be created that extends the UiBinder interface. This allows the code generation to utilize the generics parameterization for type detection.

package com.example.myapplication.view;

import org.gwtproject.uibinder.client.UiBinder;
import org.gwtproject.uibinder.client.UiFactory;
import org.gwtproject.uibinder.client.UiHandler;
import org.gwtproject.uibinder.client.UiTemplate;

import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.IsWidget;

public class MyView implements IsWidget {

  @UiTemplate
  interface MyUiBinder extends UiBinder<VerticalPanel, MyView> {}

  private MyUiBinder binder = new MyView_MyUiBinderImpl();

  private Widget widget;

  @Override
  public Widget asWidget() {
    if (widget == null) {
      widget = binder.createAndBindUi(this);
    }
    return widget;
  }

@UiHandler("myButton")
protected void onMyButtonClicked(ClickEvent event) {
Window.alert("Button Clicked");
}
}


<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder
  xmlns:ui='urn:ui:com.google.gwt.uibinder'
  xmlns:g="urn:import:com.google.gwt.user.client.ui">

  <g:HTMLPanel>
    <h1>Welcome to MyView</h1>

    <g:Button ui:field="myButton" text="Click Me" />
  </g:HTMLPanel>

</ui:UiBinder>


Conclusion

When the GWT widgets module has been ported, this project will be updated accordingly. As for being able to support both widget libraries (old and new), efforts will be made along the way to ensure the ability to utilize the GWT 2 UiBinder in parallel to the new.

As mentioned previously, the new UiBinder module is currently hosted on GitHub. Contributions are very welcomed. Updates to the module will be available there moving forward. Also, be sure to follow us on Twitter for any announcements!