With GWT, the Vaadin client side is so powerful when used correctly, it synergizes well with Vaadin, which in the end should make it even easier for you to write your applications on the server side and care about the client side even less. Of course, this also means that someone has to take the red pill, and have a look behind the nice and shiny world of Vaadin. Good thing we are not in the Matrix, so we can get the blue pill, too.
The next feature I'm introducing to you is deferred binding. This is one of the main features that make GWT so powerful. It enables the compiler to optimize your application, or WidgetSet
in the context of Vaadin, specifically for a set of parameters that you are able to define in the WidgetSet
file.
These parameters are usually the different supported browsers. But you can extend this to also distinguish between languages or any other parameter you provide. That way, the compiler can optimize every compilation to the exact environment that is defined, resulting in fast and compact JavaScript files that download fast to the client.
This means, there is no code targeted for Chrome or Firefox when opening the application in Internet Explorer, nothing in English when the client asked for French, no logic that decides during runtime which code for which browser to run, as I have seen all over the place in handwritten JavaScript. Looking through GWT code, you see browser specific implementations defined that way all over the place. And you can use this for your own code, too.
You all have seen the GWT compiler count up to 5 when compiling the WidgetSet
:
Compiling 6 permutations
Compiling permutation 1...
Process output
Compiling
Compiling permutation 0...
Process output
Compiling
Compiling permutation 2...
Process output
Compiling
Compiling permutation 3...
Compiling permutation 4...
Compiling
Compiling permutation 5...
Compile of permutations succeeded
This is deferred binding at work. GWT compiles for every defined browser a separate permutation. Thankfully it is possible to tell GWT which browser you use during development time, reducing the compilation time significantly. Just add this to the WidgetSet
file, and replace <browserid> with safari for Chrome and gecko1_8 for Firefox.
<set-property name="user.agent" value="<browserid>"/>
So, how can you use this in your own applications? This is what you need to do:
- provide an alternative implementation for any of your classes, of different implementations for an interface
- add a replace-when rule to the Widgetset file
Done.
I had a lot of ideas to show off the this feature in action, but they all became too complex to explain in the context of a blog post in the end. So please excuse this simple example. Feel free to ask questions when you are interested in more specific information.
So now I decided to create a simple TextField
with a caption. Then assume that we know that our users have all the latest Firefox, so we can use the HTML 5 placeholder attribute to show the caption inside the TextField
instead of a separate Label
.
So, first we create the implementation for the general layout that is used by everyone. The constructor looks like this:
public CaptionFieldWidget() {
FlowPanel panel = new FlowPanel();
caption = new Label("caption");
panel.add(caption);
field = new TextBox();
panel.add(field);
initWidget(panel);
}
Nothing fancy here: We create a plain panel, add a Label
for the caption and the TextBox
(which is a TextField
in Vaadin speak). As this class extends com.google.gwt.user.client.ui.Composite
, we need to initialize it with initWidget()
with this panel.
The setter for the caption text adds the parameter to the Label
:
public void setCaption(String text) {
caption.setText(text);
}
The alternative implementation extends the above class. The constructor looks like this:
public InlineCaptionFieldWidget() {
FlowPanel panel = (FlowPanel) getWidget();
panel.remove(caption);
}
As we don’t want to use the caption element which was created by the superclass, we remove it from the panel.
The setter for the caption sets the placeholder attribute of the TextField
:
@Override
public void setCaption(String text) {
getField().getElement().setAttribute("placeholder", text);
}
Now that the implementation of the classes is done, we can configure deferred binding. For this, we need to add a replace rule to the Widgetset
file (which in turn is more or less a regular GWT module file). The rule looks like this:
<replace-with
class="com.example.deferred.client.captionfield.InlineCaptionFieldWidget">
<when-type-is
class="com.example.deferred.client.captionfield.CaptionFieldWidget"/>
<when-property-is name="user.agent" value="gecko1_8" />
</replace-with>
This rule says, when the permutation for Firefox is compiled, replace the class CaptionFieldWidget
with the class InlineCaptionFieldWidget
. The when rule can be more complex, or can be omitted in case you want to have a class replaced for all browsers. This can be useful when you replace a class of GWT or Vaadin itself.
So, now the setup is complete. Only one important step is left to do. Usually you would create an instance of a class with new operator. When you want to use defered binding, you need to use GWT.create()
instead. So this is why createWidget()
function in the Connector looks like this:
@Override
protected Widget createWidget() {
return GWT.create(CaptionFieldWidget.class);
}
When you create a Widget
with the Eclipse plugin template, this is already done for you correctly. So, when we start up this application and access it with any browser (except Firefox), the Widget
looks like this:
And in Firefox it looks like this
This example shows the simplest setup for deferred binding. But you can set up your classes in many different ways. What I use often is that I create an Interface
I code against, then use deferred binding to define its implementation (when I don’t use GIN for CI, that is).
For a bit more complete explanation of this feature, please look at the documentation from Google.
There seems to be a good application that uses deferred binding to find out if the client is a phone or a tablet device in the samples of GWT, which sadly is not supported by GWT directly so far.
When you have an hour to spare, here is a video from Google I/O 2008 with a very good in depth introduction, and also explains how you can define your own parameters.
Hope you found this introduction interesting. If you have a question about this, feel free to ask here in the blog or in the forum.
For my next blog post I plan to introduce JSNI
, the JavaScript Native Interface, that allows an GWT application to communicate with the rest of the Javascript environment of the browser.
Hope to see you there.