Tuesday, May 26, 2009

Metawidget and Seam: saying goodbye to boilerplate code

This blog is to celebrate the inclusion of the Metawidget examples in the upcoming release of Seam. What is Metawidget? It's a 'smart User Interface widget' that populates itself, at runtime, with UI components to match the properties of your business objects.

If you think of a typical Seam stack, you may have JPA at the bottom, then EJB, then Seam itself, then JSF, then maybe RichFaces to add a bit of polish. But there is still a gap at the very top - a gap that leads to a lot of 'boilerplate code'. This is where Metawidget comes in.

Let me try and convey it visually using the image below. On the left are the complete contents of the book.xhtml file from the Seam Groovy Booking example. On the right are the complete contents from the new Seam Metawidget Groovy Booking example. The red boxes and lines highlight the chunks of boilerplate that have been replaced:

The original file is 177 lines long. The Metawidget equivalent is 52 lines. That represents a 70% reduction in code, on top of the considerable reductions Seam already affords when developing enterprise applications. This ability to retrofit existing UIs, integrating with existing front-end and back-end technologies, is unique to Metawidget.

Now I want to be completely fair here - I'm a developer, not a marketing guy! You also have to add a few extra annotations to your business classes, add the Metawidget JAR to your project and create a little metawidget.xml file. If we compare all the source files that change:


By comparing file sizes, we see the overall code reduction is around 20%. We could allow that in such a small example the size of metawidget.xml is more significant than it should be: for apps with hundreds of screens, the impact of 2,789 bytes of metawidget.xml will be negligible. So if we compare file sizes without including metawidget.xml, we see the overall code reduction is around 40%. If you repeat this exercise with the Seam Metawidget DVD Store example (also included in the Seam distribution) the overall reduction is around 30%.

Of course, on top of all that, lines of code is never a wondeful metric for comparing implementations. But anyway, hopefully you get the idea. Still, if you want a soundbite: Metawidget can save you up to 40% of your UI code.

My deepest thanks to the Seam guys, especially Dan Allen, for all their help integrating Metawidget into the Seam 2.1.2.GA build.

Monday, May 11, 2009

Dynamic User Interface Generator: Metawidget v0.75

Update: the APIs shown in this blog entry have changed slightly in newer releases of Metawidget. Specifically metawidget.xml uses <array> instead of <list>. Please download the latest documentation from http://metawidget.org

Version 0.75 of Metawidget, the dynamic user interface generator, is now available. This release includes:
  • Pluggable widget libraries
  • SwingX support
  • DisplayTag support
  • Improved documentation

'Pluggable widget libraries' represents a significant refactoring of the widget generation code, intended to:

  • simplify support of third party libraries, including mixing multiple third party libraries in the same application
  • pave the way for supporting Collections
  • pave the way for supporting some more UI toolkits (ie. SWT)

It is also, unfortunately, a breaking change. Sorry!

Migration Guide

To migrate from v0.7 to v0.75:

Change #1: inspector-config.xml is now metawidget.xml

The role of inspector-config.xml has been expanded from configuring pluggable inspectors to configuring pluggable inspectors and widget builders. It is also now a general configuration mechanism for all aspects of your Metawidget, such as default CSS settings etc.

You will need to refactor inspector-config.xml files of the form...

<inspector-config>
   <compositeInspector xmlns="org.metawidget.inspector.composite">
      <myinspector>
      <...
      </myinspector>
</inspector-config>
...to be metawidget.xml files of the form...

<metawidget>
   <swingMetawidget xmlns="org.metawidget.swing">
      <inspector>
         <compositeInspector xmlns="org.metawidget.inspector.composite">
            <list>
               <myinspector>
               ...
               </myinspector>
            </list>
         </compositeInspector>
      </inspector>
   </swingMetawidget>
</metawidget>
The main differences with this new XML format are:

  • it is now concerned with the top-level Metawidget, not just the inspectors inside it. This means you can also configure other Metawidget properties (see below)
  • method values must now be wrapped with their type (ie. <list>) - this allows us to support configuring multi-value methods such as setParameter
  • Full documentation can be found here
Use metawidget.setConfig to set this new format, instead of metawidget.setInspectorConfig.

Change #2: Metawidget.buildWidget is now WidgetBuilder.buildWidget

If you had previously extended Metawidget to add support for a third party widget, you'll need to refactor your code into a WidgetBuilder. WidgetBuilders can be configured programmatically, or with the new metawidget.xml:

<metawidget>
   <swingMetawidget xmlns="org.metawidget.swing">
      <widgetBuilder>
         <compositeWidgetBuilder xmlns="org.metawidget.widgetbuilder.composite">
            <list>
               <myWidgetBuilder />
               <swingWidgetBuilder />
            </list>
         </compositeWidgetBuilder>

      </widgetBuilder>
      <inspector>
      ...
      </inspector>
   </swingMetawidget>
</metawidget>
WidgetBuilders higher in the list get called first. If they return null the next WidgetBuilder in the list will be called. If all WidgetBuilders return null the parent Metawidget will instantiate a nested Metawidget.

Change #3: RichFacesMetawidget has been removed

To use JBoss RichFaces, you now use a regular UIMetawidget with a RichFacesWidgetBuilder. Full documentation can be found here.

Thanks!
We apologise for the disruption these changes will cause, but strongly believe they will make Metawidget a better product for our v1.0 release. All documentation and examples have already been migrated.