Wicket in Action

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

Fixing Wicket Property Models Using Salve

Introduction

Ironically, property models are the most convenient and the most troublesome feature of wicket. Lets use the following code as an example:

new TextField(“zip”, 
    new PropertyModel(person, “addressBook.addresses.0.zip));

They are convenient because they make it trivial to bind components to domain objects using one line of code.

They are troublesome because they create code that is easily broken and whose breakage is not apparent until run time. For example: if the AddressBook#getAddresses() method used in the example above is renamed to AddressBook#getLocations() it will not cause a compilation error, but rather a runtime error when the page is rendered. This is a big problem unless every page of the webapp is covered by a unit test.

Possible Solutions

There are a couple of ways to fix the problem:

  • Do not use property models; instead create models that implement get/setObject methods using plain java code. Advantages: easy, refactor-safe, compile time errors. Disadvantage: extremely verbose, no default null handling in intermediate return values.
  • Use proxies to generate dynamic builders. Advantages: refactor-safe, compile time errors. Disadvantages: runtime overhead (negligible), use of proxies limits code features(cannot intercept final methods, etc), most likely cannot be inlined thus requires at least two lines of code instead of one.
  • Use a source code analyzer to check the expression string at compile time. Advantages: compile time errors, most visibility into code – can take advantage of generic types that are erased at runtime. Disadvantages: not refactor-safe, requires source for all classes used in the expression, extra compilation step.
  • Use apt to generate metadata about classes and use that metadata instead of the expression string. Advantages: transparent code generation in java 6, compile time errors. Disadvantages: not refactor-safe, only works for classes compiled with apt processor.
  • Use a bytecode analyzer to check the expression string at compile time or test time. Advantages: compile or test time errors, no extra compilation step if used in test time. Disadvantages: not refactor-safe.

Salve’s solution

The bytecode analyzer is what I chose to implement as part of Salve. It is implemented as a unit test that scans for use of salve.expr.Pe class that represents property expressions in Salve.

A property model usage with Salve’s Pe class can look something like this:

new TextField(“zip”, 
    new PropertyModel(person,
        new Pe(Person.class, “addressBook.addresses.0.zip).toString()));

While the unit test can be installed by creating a simple subclass of Salve’s PropertyExpressionTest within the project being checked:

public class ExpressionValidatorTest extends PropertyExpressionTest {}

When executed the unit test will scan for .class files in the project folder, look for instantiations of Pe class and check the string expression. Any error will cause the test to fail.

Using Pe class does make the code somewhat longer. The checker supports definitions of custom classes. For example we can create a more convenient version of the PropertyModel like so:

public class PeModel<T> extends PropertyModel<T>
{
    public PeModel(Object modelObject, Class< ? > clazz, String expression)
    {
        // we do not use the clazz param, it is only here for bytecode analyzer
        super(modelObject, expression);
    }
}

With usage:

new TextField(“zip”, 
    new PeModel(person, Person.class, “addressBook.addresses.0.zip));

And let the unit test know about it by specifying a matching rule:

public class ExpressionValidatorTest extends PropertyExpressionTest
{
 
    @Override
    protected Set<Rule> getRules()
    {
        Set<Rule> rules = super.getRules();
       rules.add(new Rule("commons/web/util/model/PeModel", Part.TYPE, Part.PATH));
        return rules;
    }
}

Rules match on the last x parameters. In the above example the rule will match instantiations of the PeModel class with constructor signature of (*,Class rootType, String path).

Another convenient usage pattern is binding components to fields of the parent via: new PropertyModel(this, “name”);. Salve’s checker supports this pattern like so:

    public PeModel(Object modelObject, String expression)
    {
        super(modelObject, expression);
    }
 
    rules.add(new Rule("commons/web/util/model/PeModel", Part.THIS, Part.PATH));

Installing Salve:

svn checkout http://salve.googlecode.com/svn/trunk/ salve
cd salve
mvn install

<dependency>
  <groupId>salve</groupId>
  <artifactId>salve-expr-validator</artifactId>
  <version>0.10-SNAPSHOT</version>
</dependency>

Conclusion

The code to all this is still brand new, raw, unfinished, undocumented, untested, etc. This is mainly a call out for feedback and ideas. Let me know what you think.

4 Comments »

  1. Nice idea, I will give this a try, just one observation: is not possible for the bytecode analyzer to get the Class from modelObject.getClass() instead of specifying the class?

    Comment by Daniele — January 27, 2009 @ 5:37 pm

  2. @Daniele: doing so will push the check back into runtime which is highly undesirable. All the analyzer sees is “new Pe(…)” and it checks just that part of the bytecode.

    Comment by ivaynberg — January 27, 2009 @ 5:49 pm

  3. Igor,

    I like your idea. I would definitely prefer to use such a PeModel over a PropertyModel (although I find the names Pe and PeModel too cryptic). Could it be taken a step further such that this new model would be integrated into the Wicket core, and that testing is happening automatically when running in development mode?

    –Antoine

    Comment by Antoine — February 21, 2009 @ 7:11 am

  4. @Anotine:

    The names are a bit cryptic, but the reason is that I want to keep them as short as possible, I got tired of typing out PropertyModel all the time :)

    There is no need to do this in development mode; when your application is running, in any mode, you will already get a runtime exception. The entire point of this is to shift the error from runtime into a lower phase such as compile or test because runtime is the hardest to test.

    Comment by ivaynberg — February 21, 2009 @ 8:32 pm

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