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/

33 Comments »

  1. [...] This post was mentioned on Twitter by ildella and Planet Apache, Igor Vaynberg. Igor Vaynberg said: PropertyModels without Strings are here: http://bit.ly/4qkqFr [...]

    Pingback by Tweets that mention Removing Fragile String Expressions From Wicket Code | Wicket in Action -- Topsy.com — November 26, 2009 @ 12:35 am

  2. Wow, neat but what a mess!

    Fortunately there is Scala for some of us.

    @serializable
    class SafePropertyModel[T](expression: => T) extends IModel[T] {

    def getObject: T = {
    try {
    expression
    } catch {
    case npe: NullPointerException => null.asInstanceOf[T]
    }
    }
    }

    case class Address(val street: String)
    case class Person(val address: Address)

    val p = Person(Address(“Some street”))
    val p_null = Person(null)

    val model = new SafePropertyModel(p.address.street)
    val model_null = new SafePropertyModel(p_null.address.street)

    val result = model.getObject // result is “Some street”
    val result_null = model_null.getObject // result is null

    I haven’t compiled this code, but that should be about it.

    Comment by Francisco — November 26, 2009 @ 10:33 am

  3. Whats wrong with:

    add(new Label(“state”, new Model() {
    @Override
    public Object getObject() {
    return person.getAddress().getSate().getCode();
    }
    }));

    Comment by WicketCoder — November 26, 2009 @ 2:05 pm

  4. I see 3 possible NPE’s in your code. It isn’t reusable. It adds to the permgen. It is a lot more typing. If person changes, your code doesn’t detect the change.

    Comment by dashorst — November 26, 2009 @ 2:12 pm

  5. Not resuable – how come?
    Adds to the permgen? Wow scraping the barrel with what one
    More typing? Not really I use an IDE
    Dont get your last point.

    KISS.

    Comment by WicketCoder — November 26, 2009 @ 2:20 pm

  6. @WicketCoder

    Certainly this is the best thing one can do, but

    the problems with your code are:
    a) like Martijn mentioned NPEs.
    b) you are missing the setter
    c) you are missing the detach call propagation because 99% of the time person is an IModel

    by the time you are done you end up with:
    add(new Label(”state”, new Model() {
    @Override
    public Object getObject() {
    Person _person=person.getObject();
    if (_person!=null&&_person.getAddress()!+null&&_person.getAddress.getState()!=null) {
    return _person.getAddress().getSate().getCode();
    } else return null;
    }

    public void setObject(Object v) {
    person.getObject().getAddress().getSate().setCode(v);
    }

    public void detach() {
    if (person!=null)
    {
    person.detach();
    }
    }

    }));

    Now imagine a form with 10 fields, it wont look pretty. I, certainly, would not want to read that code. Like I said in the article, PropertyModel is extremely popular because its easy and concise, the alternative is far too verbose.

    Comment by ivaynberg — November 26, 2009 @ 6:27 pm

  7. @Francisco wow, Scala looks nice, but what a mess!

    Comment by ivaynberg — November 26, 2009 @ 6:28 pm

  8. PropertyModel uses reflection and reflection is bad for reasons we all know.

    I think the major problem here is that everyone uses properties in their Java programs but strangely Java language knows nothing of properties – a major language deficiency IMHO.

    Anyway, probably with closures things will get better (when wicket moves to Java 7).

    Comment by Dotchev — November 27, 2009 @ 10:16 am

  9. I agree with Dotchev that the lack of compile time safe, refactorable means to reference properties is a huge language deficiency.

    This bindgen generator, much like JPA 2’s typesafe criteria API seems a bit weird. It seems to me that anything that will be processed and anything generated has to go into a separate project/module. Is there a way this would work if the @Bindable and generated classes reside in the same project/module?

    Comment by Paul — November 27, 2009 @ 5:56 pm

  10. Not necessarily nulls could be checked for elsewhere.
    Do you check null check every reference in your application before using it?

    Comment by WicketCoder — November 27, 2009 @ 7:09 pm

  11. @Paul you dont need a separate project because the generated sources are generated into a separate folder and are never checked into the scm – they are regenerated on every compilation.

    Comment by ivaynberg — November 27, 2009 @ 9:25 pm

  12. @WicketCoder in business layer i would expect an NPE, but in the UI layer where i am interested in simply displaying the value to the user I would not want to make sure that the domain model contains dummy associations down to the primitives level.

    Comment by ivaynberg — November 27, 2009 @ 9:28 pm

  13. @ivaynberg Now I understand: bindgen reads source and generates source, not compiled classes.

    Comment by Paul — November 27, 2009 @ 11:31 pm

  14. @paul you got it

    Comment by ivaynberg — November 28, 2009 @ 12:46 am

  15. @ivaynberg:

    The Scala solution a mess? I really can’t see why.

    – No external libraries/processors/build systems required.
    – ~20 LOC in *one* file including the model itself, the domain classes, and two examples.
    – No strange vocabulary (“binding”) in the code.

    I understand if you can’t or don’t want to use Scala. But I don’t know how much more signal vs. noise you can get. Check out the Wicket with Scala presentation by Jan Kriesten.

    Comment by Francisco — November 29, 2009 @ 2:02 pm

  16. @Francisco

    well you did not bother qualifying why Bindgen solution was a mess, so i did not bother qualifying why Scala was either.

    > No external libraries/processors/build systems required.

    Bindgen uses a feature built directly into the javac compiler itself so it is not an “exteral” build tool, it is just a library that provides a compiler plugin. i was not aware that Scala was so complete that no one needs to write any libraries at all to build any kind of application. that is great to hear, maybe i will give it a try one day.

    > ~20 LOC in *one* file including the model itself, the domain classes, and two examples.

    so? i can rewrite it using Brainfuck and make it look like ascii art, which i think is way cooler. can you make a domain class look like ascii art in Scala? or perhaps i can use Whitespace and make it look like its zero lines of code.

    in either case it will be irrelevant to this discussion, seeing how this is about Java and not [insert your favorite language that can do this way better here]

    > No strange vocabulary (”binding”) in the code.

    but your code has this weird “SafePropertyModel” i have to know about, weird…

    Comment by ivaynberg — November 29, 2009 @ 7:58 pm

  17. Does this Bindgen work at all with CompoundPropertyModel? Doesn’t seem like it would, and we primarily use the CPM due to how clean it keeps the java code.

    Comment by Steve — November 30, 2009 @ 4:25 pm

  18. @Steve the whole point of using Bindgen is that you remove the dependence on fragile strings from your code, in this view the CPM is flawed at the very core.

    Comment by ivaynberg — November 30, 2009 @ 6:04 pm

  19. @ivaynberg

    I didn’t mean to offend you with the word mess. Sorry. It’s not worth to make a big deal out of it.

    I’ll rephrase it then, *I* think that the solution in Scala is neat, because I think the code is more expressive and because I don’t have to rely on Maven, a tool I dislike.

    I thought it would be a good idea to share that alternative, since Wicket can be effectively used from Scala today (in contrast to Brainfuck and Whitespace – that IMO have a lower s/n ratio).

    It might enlighten some people, who knows, that surprisingly might be trying to “remove fragile string expressions from Wicket code”. That’s why I think it is not irrelevant, and it’s fine if you disagree.

    Comment by Francisco — November 30, 2009 @ 6:19 pm

  20. @Francisco i wasnt offended, just annoyed; and not by the word, but by the lack of explanation :)

    Comment by ivaynberg — November 30, 2009 @ 6:21 pm

  21. bindgen is really cool. Did anyone run it successfully in IDEA 9? I still have some issues with test classes (src/test/java) not finding the main classes (src/main/java) during apt processing. I did enable ‘Annotation Processing’ in IDEA *btw*

    Comment by Peter — December 1, 2009 @ 8:20 pm

  22. Maybe what needs addressing is the way the PropertyModel (or similar) is binding the values, rather than fixing how the values are named (referenced).

    Annotations to the rescue?

    Comment by Nico — December 2, 2009 @ 4:14 am

  23. @Peter im an Eclipse user myself, but maybe this will help: http://blogs.jetbrains.com/idea/2009/11/userfriendly-annotation-processing-support-jpa-20-metamodel/

    Comment by ivaynberg — December 2, 2009 @ 4:48 am

  24. @Francisco if i read your code correctly there is a pretty huge gap left out that your SafePropertyModel does not take care of…

    your code says p.address.street which, with my non-existant knowledge of all things Scala, creates a lambda expression to be avaluated later? but, the expression is tied to a specific instance of the root object “p”. can you show an easy way to achieve the same but with interchangeable “p”? so in other words:

    new BindingModel(personModel, new PersonBinding().address.street())
    

    the above creates a “address.street” expression that is evaluated against which ever “p” is provided by the personModel…

    Comment by ivaynberg — December 2, 2009 @ 5:52 am

  25. @Nico mind elaborating? im not sure i get what you mean. the problem is that java has no way to express a chain of method calls easily, this is why we resort to things like strings…

    Comment by ivaynberg — December 2, 2009 @ 6:49 am

  26. Hi Igor,

    Sure. I haven’t really thought about that, but I guess it could be solved with an implicit conversion?

    So instead of:

    val model = new SafePropertyModel(p.address.street)

    by introducing the following (or mixing-in a trait with it):

    implicit def m2o[A](model: IModel[A]): A = model.getObject

    we can now invoke the expression on a model:

    // this is a concrete instance of a person model
    object personModel extends IModel[Person] {
    def getObject = Person(Address(“My model’s street”))
    }

    val model = new SafePropertyModel(personModel.address.street)

    Now,

    assert(model.getObject == “My model’s street”)
    println(model.getObject)

    All it does is convert under the hood a model to an object when needed. Is this what you meant?

    Francisco

    Comment by Francisco — December 7, 2009 @ 4:19 pm

  27. @Francisco not really sure, maybe its easier with code :)

    Person bob=new Person("bob");
    Person john=new Person("bob");
    
    IModel model=new BindingModel(person, new
    PersonBinding().address().street());
    
    model.getObject() <== bob.getAddress().getStreet();
    model.setObject(john);
    model.getObject() <== john.getAddress().getStreet();
    

    Comment by ivaynberg — December 7, 2009 @ 6:48 pm

  28. Alright, I see what you mean.

    In that case I would just do:

    object personModel extends IModel[Person] {
    var p = Person(Address(“first”))
    def getObject = p
    def setObject(p: Person) = { this.p = p }
    }

    model.getObject
    // here i would obtain first

    personModel.setObject(Person(Address(“second”)))

    model.getObject
    // here i would obtain second

    But most probably I can’t see in which cases I would benefit from that (a “generic safe street model” :). And afaik that is not possible with PropertyModel, or is it?

    Anyways, in general I tend to avoid setters whenever possible… they’re evil =)

    Comment by Francisco — December 7, 2009 @ 8:03 pm

  29. @Francisco

    It is possible with a PropertyModel. BindingModel is exactly the same as the PropertyModel, the only exception being that it uses a type-safe expression instead of a string to specify the property.

    Comment by ivaynberg — December 7, 2009 @ 8:17 pm

  30. If you’re using hibernate 3.5, then I don’t think you need bindgen to accomplish this, at least when dealing with entities which is probably most of the time. It has it’s static typesafe metamodel generator. Tutorial to set it up can be found here: http://relation.to/Bloggers/HibernateStaticMetamodelGeneratorAnnotationProcessor

    I’ve just been glancing at it so I don’t know if this can be a complete solution. If it can just be used directly with the PropertyModel, or even if you can get complex property strings out of it (or even if you’d want to).

    Comment by Paul — January 14, 2010 @ 5:55 pm

  31. @Paul, i would guess that while Entities take up a large usecase space for this kind of object navigation they still only account for about 60%. In Wicket you still bind a lot to non-entities such as DTOs or to Component properties.

    The JPA2 solution doesnt chain properties :( so you cant say new PersonBinding().address().state().code(), instead you woul dhave to do something like:
    new EntityBinding(Person_.address, Address_.state, State_.code) which is more error prone. And as you said, it only works for Entities.

    Comment by ivaynberg — January 15, 2010 @ 6:01 am

  32. I tried something similar using an own class that can be used as follows:
    new AccessorModel(modelOrObjectItself){{
    registrar.getFoo();
    registrar.setFoo(null);
    }} where registrar is of the type InputType, thus allowing auto-complete features of the IDE. I was also thinking of allowing chaining expressions, but as I wasn’t able to use final classes as InputType, I gave up. However, today I discovered PowerMock, and they seem to have the solution to my problem. Is this a path worth investigating, and if yes, is anybody interested in trying to work this out in an small open source thingie?

    Comment by Bert Bruynooghe — May 13, 2010 @ 10:45 pm

  33. Try using Bindgen in Eclipse in a project with over 1k entity classes and try to refactor something (or even better change generics). Coffee and lunch anyone? :)

    Half the time Bindgen does not understand generics and just leaves the building…

    Comment by Hielke Hoeve — May 28, 2010 @ 9:17 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

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