Thursday, July 10, 2008

Metawidget: Javassist versus @UiComesAfter

Update: the APIs shown in this blog entry have changed slightly in newer releases of Metawidget. Specifically PropertyStyles are now set as object instances, not as classes. Please download the latest documentation from http://metawidget.org

There's been some feedback that having to annotate your business model with @UiComesAfter like this...

public class Person {
   public String name;

   @UiComesAfter( "name" )
   public int age;

   @UiComesAfter( "age" )
   public boolean retired;
}

...to order the UI fields is a bit annoying. I agree. The problem is the Java classfile specification doesn't maintain the original declaration order of methods and fields, so we can't extract this information from reflection.

Of course, Metawidget can extract it from other places instead, such as hibernate-config.xml or metawidget-metadata.xml files, where available - but failing that you have to provide the ordering information somehow.

Well, thanks to an idea by those guys from the Tapestry team, there is now another option: JavassistPropertyStyle.

If you have Javassist available in your environment, the new JavassistPropertyStyle can use Javassist to extract debug information from the Java classfile and order the fields according to source code line number! No more @UiComesAfter! You use it like this:

<propertyTypeInspector xmlns="java:org.metawidget.inspector.propertytype"
   config="org.metawidget.inspector.impl.BasePropertyInspectorConfig">
   <propertyStyle>
      org.metawidget.inspector.impl.propertystyle.javassist.JavassistPropertyStyle
   </propertyStyle>

</propertyTypeInspector>

There are downsides. First, if you accidentally recompile your business model without debug information (like, say, when you go from development to production) all your fields will quietly unorder themselves. To protect from this, JavassistPropertyStyle fails early and fails hard if there is no debug information.

Second, JavassistPropertyStyle uses the following sorting algorithm:
  • superclass public fields come first, sorted by name

  • superclass methods come next, sorted by getter line number (or, if no getter, setter line number)

  • public fields come next, sorted by name

  • methods come last, sorted by getter line number (or, if no getter, setter line number)
This algorithm is less flexible than @UiComesAfter, which can interleave superclass and subclass properties. However, it is possible to use both @UiComesAfter and JavassistPropertyStyle together to get the best of both worlds!

2 comments:

Dan said...

By way of comparison (and as an alternative idea), the Naked Objects programming model uses an annotation called @MemberOrder, which takes an ordering in dewey decimal notation.

So, we have:

@MemberOrder("1.1")
public String getFirstName() { ... }
@MemberOrder("1.2")
public String getLastName() { ... }


One benefit of this approach, apart from being typesafe, is that it allows for subclasses to insert fields:


public class MyCustomer extends Customer {
@MemberOrder("1.1.5")
public String getMiddleInitial() { ... }
}


Cheers
Dan

Richard said...

Dan,

That's really neat. I particularly like the type safety aspect.

With your permission, I may steal that for the next release of Metawidget (with due credit, of course :)

Richard.