Thursday, February 28, 2013

Metawidget meets FreeMarker

A recent conversation with the JBoss AeroGear team inspired me to add FreeMarker support to Metawidget. This should be useful for those wanting to declare static layouts using FreeMarker templates rather than Java code.

To use the new FreeMarkerLayout, simply configure it:

StaticHtmlMetawidget metawidget = new StaticHtmlMetawidget();

BaseObjectInspectorConfig config = new BaseObjectInspectorConfig()
   .setPropertyStyle( new StaticPropertyStyle() );

metawidget.setInspector( new CompositeInspector( new CompositeInspectorConfig()
   .setInspectors(
      new PropertyTypeInspector( config ),
      new MetawidgetAnnotationInspector( config ) ) ) );

metawidget.setLayout( new FreemarkerLayout( new FreemarkerLayoutConfig()
   .setDirectoryForTemplateLoading( "./src/main/resources" )
   .setTemplate( "template.ftl" ) )
);

Or you can use metawidget.xml if your prefer...

<staticHtmlMetawidget xmlns="java:org.metawidget.statically.html">
   ...
   <layout>
      <freemarkerLayout xmlns="java:org.metawidget.statically.freemarker.layout"
         config="FreemarkerLayoutConfig">
         <directoryForTemplateLoading>
            <string>./src/main/resources</string>
         </directoryForTemplateLoading>
         <template>
            <string>template.ftl</string>
         </template>
      </freemarkerLayout>

   </layout>
</staticHtmlMetawidget>

...define your FreeMarker template...

<table>
   <tbody>
      <#list widgets as widget><tr>
         <th>${widget.label}:</th>
         <td>${widget.xml}</td>
         <#if (widget.attributes.required!"false") == "true">
         <td>*</td>
         <#else>
         <td></td>
         </#if>
      </tr></#list>
   </tbody>
</table>

...and point Metawidget at your business class...

metawidget.setPath( Person.class.getName() );

StringWriter writer = new StringWriter();
metawidget.write( writer );
System.out.println( writer );

Metawidget will use its existing Inspectors, InspectionResultProcessors, WidgetBuilders and WidgetProcessors to prepare the widgets - but will lay them out using your FreeMarker template.

I've put together a complete example you can download here. Feedback welcome!

11 comments:

vikas bhatnagar said...
This comment has been removed by the author.
Richard Kennard said...

As I understand it, FreeMarker Templates (.ftl) are an inherently compile-time (static) technology.

But yes, you could have your FTL output an m:metawidget tag, which then uses SpringMetawidget to render the page at runtime.

vikas bhatnagar said...
This comment has been removed by the author.
Richard Kennard said...

I think you're confusing yourself with FTL.

FTL is a *compile-time* technology. It will never be able to render the HTML controls at runtime.

All it can do is render an m:metawidget tag, which at *runtime* will render the HTML controls. But this runtime process is totally separate from FTL.

The Spring Address Book is a project that consumes a spring MVC model object at runtime. It has a sample metawidget.xml as well as a sample JSP page. So your FTL could generate something that looks like that project, and it'll work at runtime.

On the other hand, perhaps you want a purely compile time solution? In that case you should look at StaticSpringMetawidget.

However, you originally asked about 'possible to generate widgets at run time in the .ftl with spring mvc'. This is probably a confusing design decision.

If you're using FTL, maybe you should choose compile-time and StaticSpringMetawidget. If you want runtime, maybe you should forget FTL.

vikas bhatnagar said...
This comment has been removed by the author.
Richard Kennard said...

Can you please send a small, simple, example project to support@metawiget.org and I'll take a look.

vikas bhatnagar said...
This comment has been removed by the author.
Richard Kennard said...

Thanks for the test app - it helped to understand what you were trying to do. Apologies for my confusion - I didn't know there was a org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver

There were a couple problems with your code. The main one is that FTL doesn't use the <m:metawidget syntax. It uses <@m.metawidget

I have fixed your test app and returned it.

vikas bhatnagar said...

Thanks Richard.

rish said...

Hi, I have downloaded this example and modified pom.xml with new version, when I execute this example I get error- Exception in thread "main" java.lang.NoClassDefFoundError: freemarker/template/ObjectWrapper

I updated pom.xml with

org.metawidget.modules.static.html
metawidget-static-html
4.2


org.metawidget.modules
metawidget-all
4.2


org.metawidget.modules.static
metawidget-static-freemarker
4.2

Richard Kennard said...

That is a FreeMarker class. Can you confirm it is in your classpath?