Introducing FreeMarker

When you're writing servlets to generate dynamic web pages, how do you keep the HTML separate from your Java code, so that graphic designers can change the HTML without your having to change your classes? FreeMarker solves this problem by encapsulating HTML in templates.

FreeMarker can be used for lot more than generating dynamic web pages. You can use it whenever your program needs to generate textual output based on templates. This includes many applications, ranging from generating bulk personalized e-mail messages to dynamic generation of templatized source code. FreeMarker - being a generic template engine - is a viable solution for all of these needs. For now, let's go back to our HTML example:

The source code for a template is an HTML document that contains instructions for including dynamically-generated data. These instructions are simple and unobtrusive (so the graphic designers can still do their work), but powerful enough to let you use data structures of arbitrary complexity. It's easy to generate tables of data, and you can use "if/else" or "switch" statements to generate conditional HTML. Control structures (lists, if-else structures, and switch-case structures) can be nested as in any other programming language.

A servlet or other Java object can construct an object of class Template on initialization; the Template object compiles the template into an efficient, reusable form. Compiled templates respond almost as fast as static HTML pages. When processing a request, the servlet passes the Template a tree of data objects; the Template inserts the data from these objects into the appropriate places in the HTML, and sends the finished HTML page to the servlet's output stream. You can use the package to display data from your existing data objects, by writing thin adapter classes or using some of the built-in automatic adapters.

The data objects passed to a Template object must form a tree structure. Each node in the tree must implement one of four interfaces, allowing it to be used as a scalar (an object used for its string or numerical value), a hash (an object containing named elements), a list (an object whose elements can be read sequentially), or a method (an object that takes a list of arguments and returns one of the other object types). The root node must act as a hash. A simple data model could have this structure:

            hash
  +----------+----------+
  |          |          |
method      hash       list
  |          |          |
scalar   +---+---+      +hash--+------+
         |       |      |      |      |
       scalar  scalar   |    scalar scalar
                        |
                        +hash--+------+
                               |      |
                             scalar scalar

That is, a method returning a scalar, a hash of scalars, and a list of hashes of scalars. A list of hashes of scalars could be used to represent rows of data from a relational database.

After preparing the data model, the servlet can output HTML with a method call on the Template object:

// modelRoot is the root node of the data model
// and out is a Writer
template.process(modelRoot, out);
        

Error messages generated by template syntax errors, and messages from exceptions thrown by objects in the data model, are inserted as comments in the HTML output, unless this behavior is overriden by an event handler.

The FreeMarker classes you'll need to use directly are in the package freemarker.template.

All instructions in the template language are case-sensitive.


Note that FreeMarker is a tool that elegantly solves the problem of separating the presentation layer from the underlying business logic in a web-based application. On the other hand, there are problems typical of this space that it does not address. If you are looking for a complete MVC (model-view-controller) framework that interoperates seamlessly with FreeMarker, you might want to investigate The Niggle Web Application Framework.