Skip to main content

Template Code Generator Part 2 : FreeMarker

Posted by survivant on January 11, 2009 at 1:28 PM PST

In my previous post, I covered Apache Velocity, Eclipse JET/JET2.
I got a suggestion to look the framework FreeMarker.

FreeMarker look like Velocity. You can even find converters : Velocity -> FreeMarker.
I'll describe in this part how to create the same output but using FreeMarker.

Take a look at the generate method.

SampleFreeMarker.java


  public void generate() {

    try {
      Configuration cfg = new Configuration();
      
      cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);

      Template tpl = cfg.getTemplate("./templates/GalleryTemplateFreeMarker.ftl");
      OutputStreamWriter output = new OutputStreamWriter(System.out);
      
      Map root = new HashMap();
      
      root.put("list", mediaFileList);
      
      tpl.process(root, output);
      
    } catch (Exception e) {
      s_logger.error("generate", e);
    }

  }



Let's compare to the Velocity implementation.

SampleVelocity.java


  public void generate() {

    try {
      Velocity.init();

      VelocityContext context = new VelocityContext();
      context.put("list", mediaFileList);

      Template template = Velocity.getTemplate("./templates/GalleryTemplateVelocity.vm");

      BufferedWriter writer = writer = new BufferedWriter(new OutputStreamWriter(System.out));

      if (template != null)
        template.merge(context, writer);

      /*
       * flush and cleanup
       */

      writer.flush();
      writer.close();
      
    } catch (Exception e) {
      s_logger.error("generate", e);
    }

  }



The main difference is with FreeMarker you need to create a root HashMap and put the objects in it.
With Velocity you put the objects within the context.

Now see the FreeMarker template.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
 
 <html> 
  <head>
    <!-- include the required JavaScript file --> 
  </head>
 
 <body>
  <div align="center">
    <table width="80%">
<#assign maxItembyRow = 2>
<#assign index = 0>
<#assign count = 0>
<#assign newLine = true>
<#foreach mediaFile in list>
  <#if newLine>
      <tr>
  <#assign newLine = false>
  </#if>
        <td>
            <a href="${mediaFile.name}" id="player${count}">
            </a>
        </td>
  <#if index < maxItembyRow-1>        
    <#assign index = index + 1>
  <#else>
    <#assign index = 0>
    <#assign newLine = true>
  </#if>
  <#if newLine>
      </tr>
  </#if>
  <#assign count = count + 1>
</#foreach>
    </tr>
  </table>
  </div>
  </body>
</html> 


It's almost the same as Velocity except that the syntax change a little.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
 
 <html> 
  <head>
    <!-- include the required JavaScript file --> 
  </head>
 
 <body>
  <div align="center">
    <table width="80%">
#set( $maxItembyRow = 2)
#set( $index = 0)
#set( $newLine = true)
#foreach( $mediaFile in $list )
#if( $newLine )
    <tr>
#set( $newLine = false)
#end
#if( $index<$maxItembyRow )
        <td><a href="$mediaFile.name" id="player$velocityCount"> 
            </a>
        </td>
#set($index = $index+1)
#else
#set($index = 0)
#set( $newLine = true)
#end
#end
    </tr>
  </table>
  </div>
  </body>
</html> 


What I didn't like about FreeMarker is the lack of documentation about commons errors.
There is good javadoc and examples for templates here: , but something you need more than that like "real life" samples.
For me you should be able to find easily documentation about commons errors, but I wasn't even able to find solutions using Google.
Now that I found the reason of the compilation error, I can used it for my next projects.
The source code can be downloaded here.

Related Topics >>

Comments

hey nileflowers, I explained to revusky what I mean by lack of documentaiton, but because it still look confusing, I edited the blog. Just to add that I believe in FreeMarker.. I'll continue to use it in my next projects. But I hope not to get to much errors, but that isn't always easy to find answers :)

Lack of documentation? I am surprised by this statement too. Please go to http://freemarker.sourceforge.net/docs/index.html for docs.

You will find good documentation for the templates not for the java part, and for errors, I wasn't able to find answer on google. I had a error like that exception : freemarker.template.TemplateException: Expected hash. mediaFile evaluated instead to ca.sebastiendionne.gallery.model.MediaFileFreeMarker on line 13, column 81 in templates/GalleryTemplateFreeMarker.ftl. never found the answer. (Now I know why.. but still.. I wasn't the only one with this error) What I was looking for in the documentation is samples but also a guide for most of the commons errors with examples and explanations. Like that the users understand what they did wrong and why is not working like they tough it will. but still.. When you have something running.. it's a powerful framework. I'll replace JET with FreeMarker for my projects :)

Expected hash problem - need help !

Expected hash. s evaluated instead to freemarker.template.SimpleScalar on line 19, column 8 in includes/util.ftl. The problematic instruction: ---------- ==> if s.publicationId == publicationId [on line 19, column 3 in includes/util.ftl] ---------- Java backtrace for programmers: ---------- freemarker.template.TemplateException: Expected hash. s evaluated instead to freemarker.template.SimpleScalar on line 19, column 8 in includes/util.ftl. at freemarker.core.TemplateObject.invalidTypeException(TemplateObject.java:135) at freemarker.core.Dot._getAsTemplateModel(Dot.java:78) at freemarker.core.Expression.getAsTemplateModel(Expression.java:89) at freemarker.core.ComparisonExpression.isTrue(ComparisonExpression.java:111) at freemarker.core.ConditionalBlock.accept(ConditionalBlock.java:77) at freemarker.core.Environment.visit(Environment.java:208) at freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:179) at freemarker.core.Environment.visit(Environment.java:415) at freemarker.core.IteratorBlock.accept(IteratorBlock.java:102) My ftl is like this.. <#macro publicationCheckbox publicationId, subs=[]> <#assign isChecked="" /> <#list subs as s> <#if s.publicationId == publicationId> <#assign isChecked="checked" /> <#break>

What I don't like about some framework is the formatted output. Jamon look like that too. if I look at the code Hello, world on <% date %>. The arguments are: <%java int l = s.length; %> <%for int i = 0; i < l; ++i %> <% s[i] %> the output is Hello, world on Wed Dec 31 17:00:00 MST 1969. The arguments are: one two three but I didn't ask for a blank line between the iteration.

I am puzzled by the statement that there is a lack of documentation. I tend to think that FreeMarker's documentation compares favorably to just about any open source project. See http://freemarker.org/docs/ As for the comparison with Velocity, I do not think that a superficial comparison of the syntax gets to the heart of the matter. See: http://freemarker.blogspot.com/2007/12/velocity-of-freemarker-looking-at...

Can I suggest another template engine? Jamon (www.jamon.org). I think it has some interesting ideas like type safety and be compiled. Thank you.