Wicket in Action

A comprehensive guide for Java developers building Wicket-based web applications

Removing Fragile String Expressions From Wicket Code

The most used model in Wicket is the PropertyModel and its derivatives. This model allows the user to quickly and easily navigate object graphs using string-based property-path expressions, and is used extensively when displaying data or creating forms.

However, the PropertyModel and its string-based expressions are also responsible for adding the most fragility to Wicket code. The standard Java tooling does not support refactoring strings that happen to contain references to java constructs such as methods or fields; thus errors in these string expressions are not discovered until runtime.

For example, the string used in the code below:

new Label("state",
        new PropertyModel(personModel, "address.state.code"));

will not be updated by the tooling when the getState() method is renamed into getArea() and will thus cause an error only discoverable at runtime.

So why is PropertyModel used so often in Wicket code even though it causes so many problems? The answer is simple: it is, by far, the easiest and most convenient way to achieve the functionality. We chose to sacrifice robustness of our code for development ease and convenience. What if there was another way to achieve the same, but without using strings?

Enter Bindgen, a Java 6 apt processor [1][2] capable of generating code that can represent the same property-expressions but using real Java objects instead of strings.

Bindgen allows the developer to transform code like this:

new Label("state",
        new PropertyModel(personModel, "address.state.code"));

into code like this:

new Label("state",
        BindingModel.of(personModel,
                new PersonBinding().address().state().code()));

No more strings! And although standard Java tooling will not automatically rename state() when the field or method it references is renamed, the compiler will immediately report all places that need to be updated via a compilation error.

So what does Bindgen get you? It gets you the same ease and convenience of PropertyModels but with the added compile-time safety. Too good to be true? Try it out for yourself…

Setting up the environment

The following demonstrates how to set up a project that is built using maven and eclipse. This code is experimental, and there is not much documentation yet (see Sources section below), but what Bindgen does is worth trying.

Adjust your pom as described here: http://code.google.com/p/bindgen-wicket/wiki/ConfiguringMaven2

Now run mvn eclipse:eclipse and the project should be ready to go using both eclipse and regular maven builds.

Using Bindgen

Using Bindgen itself is simple. Annotate a class whose properties you wish to access using the @org.bindgen.Bindable annotation and Bindgen will generate a <ClassName>Binding class that can be used to create Binding instances that represent property expressions. Eclipse will generate these classes as soon as the class with @Bindable is saved, so the <ClassName>Binding class should be available as soon as you press Ctrl+S after adding the @Bindable annotation.

For example:

Given

public class Address { public String city; }
 
@Bindable public class Person { public Address address; }

Bindgen will generate classes AddressBinding and PersonBinding enabling code like this:

Binding binding=new PersonBinding().address().city();
String city=binding.get();
binding.set("Beverly Hills");
assertEquals("address.city", binding.getPath());

Configuring Bindgen

Bindgen will generate bindings for all classes reachable from the annotated class. Most of the time this is not desirable, eg we do not necessarily want binding classes generated for java.lang.String or for com.caucho.hessian.io.SerializerFactory just because they are reachable from a class with the @Bindable annotation. Bindgen provides a way to limit the generation of binding classes to certain packages by specifying a comma separated list of these packages. To do this, create a file called bindgen.properties in the project’s base folder (the one that contains the pom file) and add the scope property, eg

scope=com.myproject.mypackage,com.myproject.myotherpackage

Using Bindgen with Wicket

The bindgen-wicket module provides classes that facilitate integration between Wicket and Bindgen. These are BindingRootModel and BindingColumn.

BindingRootModel is the replacement for the PropertyModel, and its usage looks like this:

add(new Label("state",
        new BindingRootModel(personModel,
                new PersonBinding().address().state().code()));

Or using a convenience wrapper:

add(new Label("state",
        BindingModel.of(personModel,
                new PersonBinding().address().state().code()));

The BindingColumn class allows binding expressions to be used for creating DataTable columns. Eg:

new BindingColumn(
                 new PersonBinding().address().state().code())
         .setHeader("column.state")

Conclusion

As we can see, Bindgen is able to remove one of the biggest pain points in Wicket code, and do so in a manner mostly transparent to the developer. Wicket is not the only framework that can benefit from Bindgen, any place in code where property expressions are kept in strings can be upgraded to a compile-safe Bindgen binding and if that is not an option at least the property expression string can itself be generated from a binding using the Binding#getPath() method.

It is important to keep in mind that a lot of the code that makes all this possible is still fresh, and so there may be a bug here or there. Your feedback would be very appreciated.

Sources

Bindgen website: http://www.bindgen.org

My fork of bindgen repository which contains my latest tweaks: http://github.com/ivaynberg/bindgen

Bindgen official repository, this is where my changes eventually get merged: http://github.com/stephenh/bindgen

Bindgen-Wicket integration project: http://code.google.com/p/bindgen-wicket

Demo project: http://bindgen-wicket.googlecode.com/svn/trunk/bindgen-wicket-examples/

With this book, Wicket will become the greatest territory the Dutch have settled since Manhattan.

Nathan Hamblen
Senior Software Engineer, Teachscape Inc.

This is the complete and authoritative guide to Wicket, written and reviewed by the core members of the Apache Wicket team. If there's anything you want to know about Wicket, you are sure to find it in this book.

Jonathan Locke
Founder and Architect of Apache Wicket, Foreword Wicket in Action

Without question, Wicket in Action... is the be-all and end-all when it comes to Wicket.

Geertjan Wielenga, Wicket Netbeans Plugin Author

The tutorial and conversational tone of the writing makes the book very approachable.

Nick Heudecker
System Mobile

Loved the sample application—it tied everything together.

Phil Hanna
Senior Software Developer, SAS Institute

The essential guide for learning and using Wicket.

Erik van Oosten
Lead programmer and Project Manager, JTeam

Finally, the Web Framework of web frameworks, Apache Wicket, now has a bible of its own.

Per Ejeklint
Senior Software Architect, Heimore group

Wicket is an innovative evolution of the MVC programming with simple roots, but without a primer such as this, it can be more challenging than it needs to be.

Brian Topping
Founder, Bill2 Inc.

Wicket In Action glues the areas of web development with Apache Wicket together and gives a great overview of Apache Wicket...it will make a great compendium.

Nino Martinez Wael
Java Specialist, Jayway Denmark