Sep 06 2009

Freemarker: Java Template Engine

Category: JavaPhil @ 8:35 pm

Freemarker has been around for several years and is an unbelievably simple and powerful tool. Freemarker is used by numerous tools and frameworks, just click the “powered by” link to the right. Although it has not had a major release for some time, it is still an active project. I believe the tool is so mature, that it essentially does exactly what it needs to, minimizing the need for new features/releases. I first became aware of Freemarker using the Hibernate reverse engineering tool. We had some specific code fragments and styles we wanted to generate; it was very simple to augment and override the base code generation functionality, once you knew what was going on! I also worked on a Struts2-based project, which also utilized Freemarker.

I liked the Freemarker overview picture, taken from the project’s web site; it shows just how simple the tool is to understand and use. I thought I would highlight a non-traditional use of Freemarker to demonstrate how easily it can be integrated into any project. And, hopefully get you thinking about some interesting ways it can be utilized. The API is extremely configurable, capable of utilizing multiple types of input, such as databases or files, and can even be used as an alternative to XSLT. Please read the feature page for a full list of capabilities.

To start with, I created a simple little wrapper class to hide the Freemarker specifics and make it easier to deal with different type input objects. Freemarker can populate templates using a Map or simple Java bean, my preferred method of interaction. The helper class has a simple API, one overloaded method named process. You simply provide the template as a String, along with the input object; the generated result String is returned from the method. I have not really needed to do anything super fancy and the helper class meets all of my needs, from conditional logic, iteration, to custom formating, which is all implemented in the template.

public class FreemarkerHelper {

    private static final Logger LOGGER = LoggerFactory.getLogger(FreemarkerHelper.class);

    public String process(final String template, final Object input) {
       final Configuration cfg = new Configuration();
       cfg.setObjectWrapper(new DefaultObjectWrapper());
       return process(cfg, template, input);
    }

    public String process(final String template, final Map<String, Object> input) {
	return process(new Configuration(), template, input);
    }

    private String process(final Configuration cfg, final String template, final Object input) {
        String rc = null;

       try {
           final Template temp =new Template("TemporaryTemplate", new StringReader(template), cfg);

           final Writer out = new StringWriter();
	   temp.process(input, out);
	   rc = out.toString();
	   out.close();
       }
       catch (final Exception e) {
           LOGGER.error("Problem",e));
       }

       return rc;
    }
}

In a recent project, I used Freemarker for multiple purposes, generating dynamic filenames and simple XML files. The system needed to dynamically generate filenames based on a specific set of meta data, such as the object id, user id, date, and other application specific data. We allowed the files names to be specified as a Freemarker template, such as….

String template = “MyFile_${userid}_${date?string(\”yyyyMMddHHmmss\”)}_${oid?string(\”#\”)}.xml“;
String template2 = “${oid?string(\”0000000000\”)}.${filename}“;

Using the basic formatting features, Freemarker allowed us to generate any filename (format) that was required, without changing the code. We could format the numeric object id as a simple number or padded with leading zeros. Likewise, dates could also be formatted using any combination of the date’s components, using just part of the date or the time. The more interesting part is that you just pass in a Java bean or map with those attributes defined and Freemarker does the real work. This is a pretty trivial usage of Freemarker, and might not be the most common usage pattern. However, I literally did not have to write any code, other than my little helper class, which I have used on multiple projects, and I can support unlimited filename combinations; Huge bang for the buck! Once I had the filename generated, I needed to generate a simple XML file to control some external processing. The file always had the same structure, just different values. This was perfect use of Freemarker, no need for for any heavy frameworks such as XML Beans or Castor. I just created a simple Java bean that captured the descriptive data and an XML template; within minutes, my XML control file was generated.

Another quick example, I recently built a little Servlet to act as a web service for a function that we wanted to make available to multiple applications. The primary output from was either a JSON or XML stream, but I also added a basic HTML response for testing and demonstrations purposes. I hacked together some basic HTML, but was disappointed by how ugly the application was! I Google for a free CSS template, and integrated it with my Servlet. I created a single page as a template and added variables for the title, menu, and body. Using my helper class, I was able to conditionally control the menus, as well as dynamically add the main body contents. Once again, this only took minutes to implement, and was quite a bit simpler than messing with Tiles or Sitemesh!

<#if current == "home" >
      <li id="current"><a href="/Context">Home</a></li>
<#else>
      <li><a href="/Context">Home</a></li>
</#if>
https://www.beilers.com/wp-content/plugins/sociofluid/images/digg_48.png https://www.beilers.com/wp-content/plugins/sociofluid/images/reddit_48.png https://www.beilers.com/wp-content/plugins/sociofluid/images/dzone_48.png https://www.beilers.com/wp-content/plugins/sociofluid/images/stumbleupon_48.png https://www.beilers.com/wp-content/plugins/sociofluid/images/delicious_48.png https://www.beilers.com/wp-content/plugins/sociofluid/images/blinklist_48.png https://www.beilers.com/wp-content/plugins/sociofluid/images/blogmarks_48.png https://www.beilers.com/wp-content/plugins/sociofluid/images/google_48.png https://www.beilers.com/wp-content/plugins/sociofluid/images/facebook_48.png