Saturday, April 26, 2008

@UiComesAfter versus setFields

Update: the information shown in this blog entry has changed slightly in newer releases of Metawidget. Specifically you can now use an InspectionResultProcessor to implement a .setFields approach if you so desire. Please download the latest documentation from http://metawidget.org

I was recently asked why Metawidget uses @UiComesAfter and @UiHidden annotations to define the ordering and visibility of fields, rather than something like:

metawidget.setToInspect(myLoginBean);
metawidget.setFields("login","password");

There are a few reasons:

1. Separation of Concerns

In Metawidget's architecture, Inspectors inspect objects (at runtime) and Metawidgets display them. The Metawidget itself has no compile-time knowledge of what it is displaying. This has all sorts of useful side effects.

For example, in the Swing Address Book example application, the code says:

metawidget.setToInspect(contact);

At compile time, contact is of type Contact. But Contact is actually an abstract class. At runtime, contact can be either a BusinessContact or a PersonalContact. It would not be possible to say...

metawidget.setToInspect(contact);
metawidget.setFields("firstname","lastname","dateOfBirth");

...without introducing compile-time dependencies on the type of object, which means we could no longer just have a single ContactDialog class - we'd need two separate BusinessContactDialog and PersonalContactDialog classes.

Think of Metawidget like JPA's EntityManager. If you were building a very generic CRUD app, you could use a single EntityManager instance and a single Metawidget instance to manage your whole app.

2. Duplication of Declaration

Metawidget is very big on avoiding duplicate declarations between the UI and the application. If you do...

metawidget.setFields("firstname","lastname","dateOfBirth");

...you are effectively restating that the business class has a firstname field. If ever that field name changes (or is deleted), it now has to be changed in at least two places - more if you have several screens using that Metawidget.

3. Not just Java

It's a shame the Java bytecode specification doesn't retain the ordering of fields and methods, but not all technologies have that limitation. If you use HibernateInspector or XmlInspector, for example, their XML is inherently ordered and the inspectors use that information, instead of you having to use @UiComesAfter. SQL schemas also retain field ordering (though we don't have a SqlSchemaInspector yet).

And there are some other clever approaches we can try. Tapestry 5's ClassFactory, for example, uses Javassist to extract line numbering information and sort getter methods that way.

Conclusion

I think these are compelling reasons to avoid the setFields approach. However, feedback is very welcome!

0 comments: