Saturday, December 19, 2009

GWT 2 Declarative Layout: Beyond UiBinder

Google Web Toolkit (GWT) 2 brings Declarative Layout

Google brought with GWT 2.0.0 a new major release of Google Web Toolkit (GWT) to us some days ago. This toolkit enables java guys (including girls!) to write rich internet applications based on javascript and ajax.
The version 2 of the toolkit is bundled with great new tools and features (also have a look here). One of these features is declarative layout with UiBinder. UiBinder "now allows you to create user interfaces declaratively in XML instead of having to assemble them programmatically". Here's an example...

Programmatical approach (common style):

*) With the use of setters instead of constructor arguments I intend to understate the nature of layouting gwt applications programmatically.

Corresponding declarative code (new style):

In real-world projects your program will be a mixture of the two approaches. The xml based ui declarations will unclutter your code and separate the layout from the logic. Because xml is static (like a plain html page) the declared Widgets (or UIObjects in general) can be injected into java fields and dynamically modified at runtime. Because GWT translates your code into javascript, the modifications will occur at the client side. Sounds easy - and that's what it is. Thank you, Google!

Do 3rd Party GWT Libraries work with GWT 2?

Yes and no. Considering the programmatical point of view all should work fine. The only point of interest is the case where third party Widgets are build on top of standard GWT Widgets which were changed with the new version in some way (UPDATE: this is theory - I don't know if there are api changes). This should be a minor problem because if the third party library is a good choice then it will be updated soon. If not it should be replaced by a good choice ;-)

The more interesting point of view is the one where declarative layouts are considered. GWT 2 ui declarations are allowing the import and usage of 3rd party Widgets. For example let's substitute the center component of the above standard GWT example with a DatePicker of the Ext GWT (GXT) 2.1 library. You see the complete ui.xml because the use of namespaces is essential here:

I will not describe the technical details of how to integrate a third party GWT library and get it running. The focus here is set on the ability to declare layouts with (a mixture of) Widgets from different GWT libraries. Let's take a look at the following GXT snippet:

The question is now how to formulate this in a declarative manner... The answer is simple but dissatisfying: It is currently not possible.

As we see with DatePicker in the example above, GWT is able to construct simple Widgets (by calling their constructor with no arguments). If GWT finds attributes in a declaration it will call the corresponding setters of the associated java object (follwing the Java Beans standard). But there are more complex Widgets where this strategy does not work. The ContentPanel of GXT can be configured with a specific layout strategy. The default is FlowLayout but in the example BorderLayout is used. Depending on the layout the LayoutData has to be set appropriately when adding children to the ContentPanel. This leads to the assertion that the declarative layout parser has to know the structure of the xml presentation of each (3rd party) Widget and how to wire together the underlying Widgets to an object graph.

How would you formulate the above example as ui declaration? Here's one of several possible answers: UPDATE: Here's an answer, depending on a specific parser:

How to get it work?

Currently I work on a solution for the described problem of declaring layouts containing arbitrary Widgets of 3rd party libraries. I am focusing on these key topics:

  1. Hooking into the code generator of GWT (finished)
  2. Creating a custom code generator (work in progress)
  3. Defining a plugin language for 3rd party customization of the code generator (next step)

UPDATE: I realized, that it is possible to write specific element parsers which are bound to an UiBinder element via reflection. There are two things to do now:

  1. Write specific parsers for 3rd party Widgets (few code because recursive)
  2. Register these parsers (access private var UiBinderWriter.elementParsers)

The discussion of these three topics will follow soon on this blog... A parser for the last example will be posted on this blog soon...

3 comments:

  1. I haven't look that deeply into this problem, but at what point of the parsing process are you planning to inject a call to addWidgetParser("YourParser")?

    ReplyDelete
  2. My initial idea was to provide custom UiBinder generator (in .gwt.xml). The custom generator delegates to the default UiBinderGenerator. The default UiBinderGenerator is loaded by a custom ClassLoader. The custom ClassLoader is aware of requests for UiBinderWriter class and provides a modified UiBinderWriter (e.g. subclass). Because the (default) UiBinderWriter encapsulates the list of parsers the subclass has to initialize this list at creation time (@idlebot: this was your question). The custom UiBinderWriter depends on a custom parser manager and the parser manager provides register / unregister methods for custom parsers... Currently I stuck in ClassLoader hell - but I'm on it...

    ReplyDelete