Frequently Asked Questions

Table of contents

Assembling template data models

Can you give me some examples showing how to assemble a template data model?
Can I use XML documents as data models?
What's a good way to wrap an existing object so that a template can call its methods?

Integration

Is there a HTTP servlet for FM-Classic I can use out-of-the-box?
Can I use FM-Classic template processing in Ant?

Features

Is it possible to do integer arithmetic in templates?
I'm using a visual HTML editor that mangles template tags. Will you change the template language syntax to accommodate my editor?
How can my Java classes ask a template for information about its structure (e.g. a list of all the variables)?
Can I serialize my data model?
Can I serialize FM-Classic templates once they're compiled?
What are the differences between FM-Classic and FreeMarker Lazarus?

Legal issues

If we distribute FM-Classic with our product, do we have to release the source code for our product?

If your question was not answered by this FAQ, write to Nicholas Cull (the current maintainer).


Can you give me some examples showing how to assemble a template data model?

The easiest way is to use SimpleHash, SimpleList, SimpleScalar, and SimpleNumber. For example, suppose you want to be able to use a variable called foo.bar.baz.bing in your template. You could make a structure of nested SimpleHash objects like this:

SimpleHash foo = new SimpleHash();
SimpleHash bar = new SimpleHash();
SimpleHash baz = new SimpleHash();
SimpleScalar bing = new SimpleScalar("value of bing");
baz.put("bing", bing);
bar.put("baz", baz);
foo.put("bar", bar);
modelRoot.put("foo", foo);

What about nested lists? Suppose you wanted to write something like this in a template:

<list list1 as list2>
    <list list2 as list3>
        <list list3 as element>
            ${element}<br>
        </list>
    </list>
</list>

You could make nested SimpleLists like this:

SimpleList list1 = new SimpleList();
for (int i = 0; i < 3; i++) {
    SimpleList list2 = new SimpleList();
    for (int j = 0; j < 3; j++) {
        SimpleList list3 = new SimpleList();
        for (int k = 0; k < 3; k++) {
            list3.add(new SimpleScalar("test " +
                                       String.valueOf(i) +
                                       " " +
                                       String.valueOf(j) +
                                       " " +
                                       String.valueOf(k)));
        }
        list2.add(list3);
    }
    list1.add(list2);
}

modelRoot.put("list1", list1);

The template code above would then produce this output:

test 0 0 0
test 0 0 1
test 0 0 2
test 0 1 0
test 0 1 1
test 0 1 2
test 0 2 0
test 0 2 1
test 0 2 2
test 1 0 0
test 1 0 1
test 1 0 2
test 1 1 0

etc.

Back to top


Can I use XML documents as data models?

Yes, you can. One way to do this is to first build a JDOM tree from your XML document, and afterwards expose JDOM tree nodes as data models. The FreeMarker-Ext library has a class that can wrap JDOM nodes to expose them to FM-Classic as a template model. In order to wrap your JDOM document tree in a FM-Classic TemplateModel, it is sufficient to do the following:

...
org.jdom.Document document = getMyDocumentSomehow(...);
TemplateModel model = new freemarker.ext.jdom.NodeListModel(document);
...
      

In the example below, the templates will be able to access the XML document through the "document" variable. The adapter supports all kinds of tree traversals and filterings, allows use of a node list as a TemplateListModel, and outputs XML fragments of contained nodes when used as a string literal. It also features full XPath support.

This FAQ page itself is created by applying a FM-Classic template to an XML document. Table of contents with links, topic grouping, and "Back to top" are all generated by the template. See the examples/jdom and examples/ant directories in the FM-Classic distribution for example on using the XML support.

Back to top


What's a good way to wrap an existing object so that a template can call its methods?

The FreeMarker-Ext library has classes to wrap arbitrary Java objects as data models. In general, all you need to do to wrap your object obj into a TemplateModel is to call a single static factory method:

...
TemplateModel model = freemarker.ext.beans2.Wrapper.wrap(obj);
...
      

After this, you can write arbitrary method calls on the wrapped object, i.e. you can write ${obj.getFoo()} in a template to execute method foo and place its result in the template output. The wrapper uses the JavaBeans introspector to discover available methods, so you can use bean property-style invocations as well: in the previous example you could have written ${obj.foo} as well. If any property or method call returns an object, it is automatically wrapped for you, so you can chain invocations: {$obj.bar.baz.bing} would translate to what in Java would be obj.getBar().getBaz().getBing(). The framework automatically recognizes arrays as well as iterators, maps and collections from java.util package and provides them with additional capabilities (arrays, iterators, and collections act as list models and maps act as both lists of their entries and allow lookup when used as a method model). There is even a facility for invoking static methods (in case you ever needed System.currentTimeMillis() in a template).

It is worth noting that the introspection framework caches the results of introspection, so that the negative performance impact resulting from reflected method lookup is minimized.

Back to top


Is there a HTTP servlet for FM-Classic I can use out-of-the-box?

Yes, there is. The FreeMarker-Ext library has the class freemarker.ext.servlet.FreeMarkerServlet that you can use to provide template processing capabilities to your webapp.

In general, you should only place the following inside your web.xml file:

  <servlet>
    <servlet-name>freemarker</servlet-name>
    <servlet-class>freemarker.ext.servlet.FreeMarkerServlet</servlet-class>
    <init-param>
      <param-name>TemplatePath</param-name>
      <param-value>/templates</param-value>
    </init-param>
    <init-param>
      <param-name>TemplateDelay</param-name>
      <param-value>0</param-value>
    </init-param>
    <init-param>
      <param-name>NoCache</param-name>
      <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>freemarker</servlet-name>
    <url-pattern>/templates/*</url-pattern>
  </servlet-mapping>

This will map all URLs beginning with /templates/ to templates in your webapp/templates directory. The servlet readily provides access to ServletContext, HttpSession, HttpServletRequest and HttpServletRequest parameters in the template data model. If you need to have additional variables available in your data model, just subclass the servlet and override the preTemplateProcess() method to shove any additional data you need into the model before the template gets processed.

Back to top


Can I use FM-Classic template processing in Ant?

Yes, you can. In particular, there is a FM-Classic task for Ant that will get a set of XML files, run them through a FM-Classic template, and output the resulting files in a target directory. This method is ideal for generating documentation, SQL scripts, or any other transformation required during your build process. It is a viable alternative to Ant's xslt task. The Ant task is part of the FreeMarker-Ext library. See the examples/ant directory in the FM-Classic distribution for a sample build.xml file that employs FM-Classic.

Back to top


Is it possible to do integer arithmetic in templates?

Yes. As of 1.8, FM-Classic supports integer operations, along with a new template model TemplateNumberModel. See the manual for more details of the operators supported. In many cases, though, the things people want to do with numbers in templates are better done in Java classes, because they have to do with controlling the application rather than formatting data for display. For more advanced numerical operations, you can write custom intermediate TemplateModel classes that perform the required operators.

For those who need floating point numerical support, you could consider the FreeMarker 2.X releases.

Back to top


I'm using a visual HTML editor that mangles template tags. Will you change the template language syntax to accommodate my editor?

I won't change the standard version, because a lot of templates depend on it. However, FM-Classic is designed to make it easy for you to change the syntax to suit your needs. Changing the tag delimiters, making tags case-insensitive, and representing operators differently would be simple changes to make. Take a look at freemarker.template.compiler.StandardTemplateParser, and read the notes on the source code. Let me know if you need further explanation of anything in the source code.

My view is that the editors that break template code are themselves broken; you'll probably have the same problem if you try to use them with other template systems. A good editor should ignore, not mangle, what it doesn't understand.

Back to top


How can my Java classes ask a template for information about its structure (e.g. a list of all the variables)?

This isn't possible, because variable names can be dynamically generated from data (see the manual). However, there's a more important reason why FM-Classic doesn't support this. The design of FM-Classic is based on the idea of a separation between business objects and presentation objects. This separation takes two forms:

  1. The templates know what data to expect, but they don't know how it's generated.
  2. The business objects know what data to produce, but they don't know how it's going to be displayed. Therefore, they don't know anything about templates.

Since the business objects don't rely on the templates, if you need to use them with some other presentation system, you won't have to rewrite your application.

Back to top


Can I serialize my data model?

All the Simple models (SimpleHash, SimpleList, SimpleScalar, and SimpleNumber) and most of the Fast models (FastHash, FastList, FastScalar, FastNumber and FastBoolean) support serialization. FastIterator cannot be serialized because the underlying iterator class cannot be serialized. In addition, most of the models in the freemarker.ext package are serializable. A few of the freemarker.ext.beans classes are not serializable, because the underlying data models cannot be serialized.

All the serializable models above are portable between the Java 1.2 and Java 1.5 releases.

If you want to serialize your own data models, you'll need to implement the java.io.Serializable or the java.io.Externalizable interfaces yourself.

Back to top


Can I serialize FM-Classic templates once they're compiled?

Yes, although the serialized form is typically much larger than the original uncompiled template. Three to four times larger is not uncommon. This may be useful if you want to send a parsed template over RMI, or in other situations where the original template cannot be recompiled. Normally, however, it is more efficient to simply recompile the template when required.

The serialized form of compiled templates is portable between the Java 1.2 and Java 1.5 releases.

Time efficiency is very similar for serialization versus re-compilation, since the majority of time spent in either case is in performing I/O operations and class loading.

Back to top


What are the differences between FM-Classic and FreeMarker Lazarus?

The main differences between FM-Classic and FreeMarker 2.x are related to:

Full floating-point numerical support is provided in FreeMarker 2.0 onwards. FM-Classic support integer numerics from 1.8 onwards. However, there are differences in the implementations. Lazarus uses the heavy-weight java.math.BigDecimal class internally whenever it performs numerical computations. This is because Lazarus is intended to support arbitrary precision floating point arithmetic. Classic takes a more light-weight approach, and offer only integer precision. See above for the reasoning.

Lazarus has been aggressively refactored during its design, and uses a JavaCC-based parser to compile templates. Other areas of Lazarus have been completely reworked, such as the caching system. The Classic code base is a continual refinement the original code, reflecting gradual improvements, in preference to massive overhauls.

Lazarus introduced a collection of built-in operators, for things such as capitalization, the size of a list, etc, and made them a "core" part of the template engine. Classic works on the assumption that these are things best exposed by the template model, either in the form of "special" keys, or by method calls. Classic assumes that a template engine (or its designers) can never guess all the functionality that might be needed from a template model.

Back to top


If we distribute FM-Classic with our product, do we have to release the source code for our product?

No. If you distribute FM-Classic, you have to distribute the FM-Classic source code. The license does not apply to your product.

The complicated legal language of the LGPL is intended to prevent people from making proprietary versions of the library, while still allowing you to write proprietary programs that use the library.

If you use FM-Classic, I hope you'll send me a link to some information about your product, but that's optional as well.

Back to top