2010-11-23

Custom UiBinder ElementParsers for GWT

The other day, I released two new open source projects for GWT development to make it easier to adapt GWT widget libraries to UiBinder.

GWT UiBinder was introduced in GWT 2.0 as a declarative approach to building user interfaces.  Rather than programmatically instantiating objects and adding objects to containers, a new XML structure was added.  This approach not only saves hours of development time, but it also reduces the complexities of many application layouts.

Unfortunately, UiBinder wasn't made to support registering custom ElementParsers, thus only supporting core GWT widgets.  This means that if you're planning on using widgets in UiBinder XML, they must conform to the GWT rules. For example, "containers" must implement the HasWidgets interface to support nested children.

After doing a little bit of research, I have found that some people have tried modifying GWT classes (such as UiBinderWriter) and use ClassLoader tricks (changing class path search order) to get their modified versions of the GWT code loaded first, thus giving them the ability to use custom ElementParsers. Typically, this involves editing the UiBinderWriter every time you add a new ElementParser.

I have also recently come across discussions on a new annotation called @ElementParserToUse. With this annotation, a developer would be able to add it to any widget class to specify a specific ElementParser to use. This is a great step towards registering custom ElementParsers.

Unfortunately, this approach does not help me as I'm currently using Ext GWT from Sencha (GXT).  The current version of GXT was created prior to GWT 2.0 UiBinder, thus not implementing the proper interfaces, so when adding GXT widgets into your app, you are basically required to use a programmatic approach to the UI layouts.

I wanted to use GXT for it's rich widgets, but didn't want to fall back to developing my user interface programmatically.  To solve this problem, I started making my own modifications to the UiBinder code generation and released my work as gwt-customuibinder.

Using gwt-customuibinder and Registering Custom ElementParsers

To use gwt-customuibinder in your project, the first thing to do is to <inherit> the module.  This is done like this:
<module>
  ...
  <inherits name="com.jhickman.web.gwt.customuibinder.CustomUiBinder" />
</module>

This inherit line must be the last one for your module (or at least after com.google.gwt.user.User) as it overrides the UiBinderGenerator configuration. If the inherit line comes before, then the GWT UiBinderGenerator will be used, thus not giving you the desired results.

To register custom ElementParsers, you must "extend" a GWT configuration property called "gwt.uibinder.elementparser". This means that there are no code changes needed to support new ElementParser classes.

Here is an example:
<module>
  <extend-configuration-property 
    name="gwt.uibinder.elementparser"
    value="com.foo.client.ui.SomeWidget:com.foo.uibinder.elementparsers.SomeWidgetParser" />
</module>

As you can see from this code snippet, we "extend-configuration-property" called "gwt.uibinder.elementparser".  The value of this property must be a colon separated widget:parser combination.

Note: If you use "set-configuration-property", it will override the previous definitions and not all of the custom ElementParsers will be available.

Using gwt-customuibinder and Registering Custom HandlerEvaluators

Another item I realized when adapting 3rd party widget libraries to GWTs UiBinder is that not all libraries support the same Event model GWT provides. In order to have an equivalent of @UiHandler in the view code, I needed the ability to register a custom HandlerEvaluator. This supports the creation of any handler method annotation needed for your widget library.

Just as registering custom ElementParser classes, we can extend a different configuration property called "gwt.uibinder.customHandlerEvaluator" and use the full classname as the value.

For example:
<module>
  <extend-configuration-property
    name="gwt.uibinder.customHandlerEvaluator"
    value="com.foo.rebind.SomeCustomHandlerEvaluator" />
</module>

The value specified here must implement the "com.jhickman.web.gwt.customuibinder.rebind.CustomHandlerEvaluator" interface.


Conclusion

Although I am glad to start this new open source project as it gives me something fun to work on, I am fully hoping that the project will become unnecessary once the GWT team adds the support for registering custom ElementParsers.


Example Project
The other project I released is called gxt-uibinder. Watch for upcoming blog entry describing that project.

4 comments:

Unknown said...

Hi there! I'm fairly new to GWT and GXT. I'm working with them for about two months now and I'm very satisfied with what they offer.

The project I'm involved with is using the UiBinder interface, and before I started to use GXT everything was going ok.

However, after GXT entered the picture, everything you mention in your blog became a reality. I'm talking about loosing quite a lot of time to programmatically setup GXT widgets, which I then wrap in a GWT panel and add to the UiBinder.

Finally, a few days ago I was so annoyed with this that I did a little research and stumbled upon your gxt uibinder. I still haven't implemented and tested it in my project but from what I can tell, it's an answer to all my GXT prayers :)

So, let me say kudos for creating it, and releasing it as open source as well! It's wonderful, and I hope it continues to grow! I hope Google picks it up into the standard GWT kit.

I was actually hoping to get more specific information concerning its installation and use. Is it possible to get in touch with you so I can throw a few questions your way? Perhaps directly via e-mail or the project page?

Again, excellent work! Thanks!

Justin Hickman said...

Thanks for the positive feedback. The gxt-uibinder project has a Google Group that can be used for these conversations. http://groups.google.com/group/gxt-uibinder

I have a GettingStarted guide on the project wiki. This should help getting started.
http://code.google.com/p/gxt-uibinder/wiki/GettingStarted

Also, you can check out the source code for the demo/showcase project.
http://code.google.com/p/gxt-uibinder/source/browse/#hg%2Fgxt-uibinder-test

Daniel Dietrich's Blog said...

Nice work! After the release of GWT 2.0 I had the same question and played around a bit with the UiBinder ElementParsers.
Here are my most recent thoughts: http://cafebab3.blogspot.com/2010/01/non-intrusive-gwt-2-mod-2nd-part.html
Perhaps you find it useful for future development of your project.
- Daniel

Justin Hickman said...

Thanks. I think I may have read that page sometime last year. I had submitted a patch to Google earlier this year, but was disappointed to see that they are not wanting to open up that API yet. I had considered annotating Widgets, but knew that most of the time I wouldn't have the source in order to annotate, since I work a lot with 3rd party Widgets. I decided to register parsers through the gwt.xml files instead.
http://gwt-code-reviews.appspot.com/1454804/