» Articles » deciding on a new general purpose template engine

deciding on a new general purpose template engine

template engines

I’ve been using velocity for a long time and I’ve decided to let it retire. Now the question is what will replace my beloved velocity? And maybe more importantly: Why does it need replacement at all? I will come to that. But first…

There are many template engines out there. More often than not they differ from each other in terms how to express things rather than what needs to be expressed. There are fewer differences than I would expect.

Over the years I’ve looked and employed the following template engines: velocity, freemarker, jet, etc.

velocity

This has been my favorite up till now. It has a simple language that is easy to learn and yet is very powerful. You can do everything within templates, from building data structures (and maps, lists) to accessing java classes and methods. As a matter of fact, you could write your whole application in a VTL.

velocityexample.vm
This template creates a map within a template
#set ($map = {})
## note that we must do an assignment in order to call a java method.
#set ($dummy = $map.put("somekey", "somevalue"))
$map.somekey

Beautiful.

Velocity is very fast, has a nice plug-in system and is easy to use. It has served me well over the years.

However, the templates invariably feel like perl scripts in the sense of ‘write once but beware if you ever want to read it’. It’s very hard to maintain more complicated templates. My conclusion is that velocity is too lenient and doesn’t enforce patterns that will help you in the long run.

freemarker

freemarker has been often marketed as a ‘better velocity’. I feel about freemarker in relation to velocity the same way I feel about CVS versus subversion: While subversion may be better in minor points, it’s overall the same old thing.

(But I digress. I love to insert some rant against subversion in random places.)

The fact that freemarker depends on awt and swing indicates that there is something very wrong with it. Overall it does the same as velocity, just with a slightly different flavor.

There are many template engines. Here’s is a nice gallery of template engines, however not all of them are general purpose.

enter stringtemplate

stringtempate has been around for a while but somehow managed to escape my attention until now. The creator Terence Parr seems quite opinionated about what a template engine allows its user to do.

stringtemplate concepts

stringtemplate is different. I will try to describe stringtemplate for someone who expects a template engine to work like velocity.

  • The stringtemplate DSL only gives read access to a model. You may never call methods or do anything that changes the state of the model.
  • velocity makes encapsulation possible by way of macro definitions and @#include#s that may or may not be parsed. Velocity’s approach here is a bit confusing. When do you use #parse, #include or #macro? Encapsulation is very natural in stringtemplate: you can define templates within template files (ending in .st) and template group files (ending in .stg). A template file’s name serves as a function name that is accessible in other templates or template groups. Template groups may contain several template definitions, each of which is identified by a name. Template groups are purely a convenience.

consider the following three files, simpletemplate.st, simpletemplategroup.stg, anothersimpletemplate.st:

simpletemplate.st
hello $name$
simpletemplategroup.stg
group simplegroup;
template1 ::= <<
calling simpletemplate produces: $simpletemplate(world)$
>>
anothersimpletemplate.st
hello $template1()$

The group file ‘simpletemplategroup’ adds more syntax to the pot and lets you defines many templates and assign them names. These can then be called from within other templates.

  • handling of collections. velocity has deficits here. You can iterate through arrays and lists in velocity, but they behave differently. In velocity I usually convert arrays into lists in order to be able to access them in the same way. In code generation you will often face the situation where you need an output akin to this:

1, 2, 3, 4, 5

velocity: (assuming $list contains the numbers up to 5)
#foreach ($c in $list)
$c#if($velocityCount < $list.size()), #{end}#end

This is getting a bit messy.

stringtemplate:
$list; separator=","$

This is a really neat feature. If you’ve ever generated a considerate amount of code with velocity, you’ll appreciate this: the separator can be anything, and is not applied after the last element.

In stringtemplate lists are always expanded, there is no need for a loop construct, in fact, string template has no loops. This makes for very readable tempates. Consider you want to generate the setter methods in a java class:

setter.sgt
group bean;
setter ::= <<
    public void set$it$() {
        this.$it$ = $it$;
    }
>>
allsetters(namelist) ::= <<
$namelist:setter()$
>>

That’s it! Very simple and intuitive. No need for a loop. ‘$it$’ contains the current value of the iteration.

The entry ends here abruptly.