Date of release: 2002-10-17

Templates and the Java API are not fully compatible with 2.0 releases. You will need to revisit existing code and templates, or use 2.1 for new projects only. Sorry for this inconvenience; FreeMarker has undergone some revolutionary changes since the 1.x series. We hope things will soon be sufficiently mature for us to offer (almost) backward-compatible releases. Note that there is a backward-compatibility flag that can be set via Configuration.setClassicCompatible(true) that causes the new FreeMarker to emulate most of FreeMarker 1.x's quirks.

Changes in FTL (FreeMarker Template Language)

  • More strict, reveals accidental mistakes in the templates, prevents showing incorrect information when something went wrong:

    • An attempt to access an undefined variable causes an error and aborts template processing (by default at least; see later). In earlier versions undefined variables were silently treated as empty (zero-length) strings. However, you can handle undefined variables in the template with some new built-ins. For example, ${foo?if_exists} is equivalent with the ${foo} of earlier versions. Another way of looking at this is that null values no longer exist from the viewpoint of a template designer. Anything referenced must be a defined variable.

      Note however that the programmer can configure FreeMarker so that it ignores certain errors (say, undefined variables), and continues template processing by skipping the problematic part. This "loose" policy should be used only for sites that don't show critical information.

    • New variable type: boolean. Conditions in if/elseif and operands of logical operators (&&, ||, !) must be booleans. Empty strings are no longer treated as a logical false.

  • Local and global variables. More info: Template Author's Guide/Miscellaneous/Defining variables in the template

    • Local variables for macros. You can create/replace local variables in macro definition bodies with the local directive

    • You can create/replace global (non-local) variables with the global directive

  • The include directive now by default treats the passed filename as being relative to the including template's path. To specify absolute template paths, you now have to prepend them with a slash.

  • The include directive can now use the acquisition algorithm (familiar from the Zope system) to look up the template to include. Basically, if a template is not found where it is looked up first, it is looked up in parent directories. This is however not a default behavior, rather it is triggered by a new syntactic element.

  • Strict syntax mode: Allows you to generate arbitrary SGML (XML) without worrying about clashes with FreeMarker directives. For more information read: Template Language Reference/Deprecated FTL constructs/Old FTL syntax

  • Terse comments: you can use <#-- ... --> instead of <comment>...</comment>

  • Directive that you can use to change the locale (and other settings) inside the template: setting

  • Directive to explicitly flush the output buffer: flush

  • The top-level (root) hash is available via the variable root, which is now a reserved name.

  • The misnamed function directive has been renamed to macro.

  • String literals support various new escape sequences, including UNICODE escapes (\xCODE)

  • The compress directive is now more conservative in removing line breaks.

  • Built-in to capitalize the first word: cap_first

  • Built-in to generate on-the-fly templates: interpret

  • stop directive has an optional parameter to describe the reason of termination

  • Better error messages.

  • New variable type: date. Date support is experimental. It can change substantially in the future. Keep this in mind if you use it.

Changes on the Java side

  • ObjectWrapper: You can put non-TemplateModel objects directly into hashes, sequences and collections, and they will be automatically wrapped with the appropriate TemplateModel implementation. The API of objects that are exposed to templates (SimpleXXX) has been changed according to this, for example in SimpleHash the old put(String key, TemplateModel value) is now put(String key, Object object). Also, you can pass any kind of object as data-model to Template.process. The alternative reflection based ObjectWrapper can expose the members of any Java object automatically for the designer. More information: Object wrapping, Bean wrapper, Jython wrapper.

  • The Configuration object was introduced as a central point to hold all your FreeMarker-related global settings, as well as commonly used variables that you want to have available from any template. Also it encapsulates the template cache and can be used to load templates. For more information read Programmer's Guide/The Configuration.

  • TemplateLoader: pluggable template loader, separates caching from template loading

  • TemplateNumberModel-s do not control their formatting anymore. They just store the data (i.e. a number). Number formatting is done by the FreeMarker core based on the locale and number_format settings. This logic applies to the new experimental date type as well.

  • TemplateBooleanModel introduced: Only objects that implements this interface can be used as a boolean in true/false conditions. More info: Programmer's Guide/The Data Model/Scalars

  • TemplateDateModel introduced: objects that implements this interface are recognized as dates and can be locale-sensitively formatted. Date support is experimental in FreeMarker 2.1. It can change substantially in the future. Keep this in mind if you use it.

  • The TemplateModelRoot interface was deprecated. As of FreeMarker 2.1, you can simply use any instance of TemplateHashModel instead. This actually is due to a significant architectural change. Variables set or defined in a template are stored in a separate Environment object that only exists while the template is being rendered. Thus, the template doesn't modify the root hash.

  • Changes to transformations

    • Completely rewritten TemplateTransformModel interface. More flexible, and does not impose output holding. More information: Programmer's Guide/The Data Model/Directives

    • The transform directive now takes an optional set of key/value pairs. <transform myTransform; key1=value1, key2=value2 ...>. More information: transform directive

    • The transforms that ship with the FreeMarker core are now available by default to all templates - i.e. <transform html_escape> will invoke the freemarker.template.utility.HtmlEscape transform. More information: Programmer's Guide/The Configuration/Shared variables

  • User-defined TemplateModel objects now can access the runtime environment (read and set variables, get the current locale, etc.) using an Environment instance, which can be obtained by the static Environment.getCurrentEnvironment() method. As a result, TemplateScalarModel.getAsString has been changed: it has no locale parameter.

  • TemplateExceptionHandler-s make it possible to define your own rules on what to do when a runtime error occurs (e.g. accessing a non existing variable) during template processing. For example, you can abort template processing (recommended for most sites), or skip the problematic statement and continue template processing (similar to old behavior). DebugMode has been removed, use TemplateExceptionHandler.DEBUG_HANDLER or HTML_DEBUG_HANDLER instead.

  • Logging: FreeMarker logs certain events (runtime errors for example). For more information read Programmer's Guide/Miscellaneous/Logging.

  • SimpleIterator was removed, but we provide a TemplateCollectionModel implementation: SimpleCollection.

  • Arithmetic engine is pluggable (Configuration.setArithmeticEngine). The core distribution comes with two engines: ArithmeticEngine.BIGDECIMAL_ENGINE (the default) that converts all numbers to BigDecimal and then operates on them, and ArithmeticEngine.CONSERVATIVE_ENGINE that uses (more-or-less) the widening conversions of Java language, instead of converting everything to BigDecimal.

  • Changes to freemarker.ext.beans package: The JavaBeans adapter layer has suffered several major changes. First, BeansWrapper is no longer a static utility class - you can now create instances of it, and every instance can have its own instance caching policy and security settings. These security settings are also new - you can now create JavaBeans wrappers that hide methods that are considered unsafe or inappropriate in a templating environment. By default, you can no longer call methods like System.exit() from the template (although you can manually turn off these safeguards). The StaticModel and StaticModels classes are gone; their functionality is now replaced with the BeansWrapper.getStaticModels() method.

  • freemarker.ext.jython package: FreeMarker can now directly use Jython objects as data-models using the Jython wrapper.

  • Changes to freemarker.ext.jdom package: The package now uses the Jaxen package instead of its predecessor, the werken.xpath package to evaluate XPath expressions. Since Jaxen is a successor to werken.xpath, this can be considered to be an upgrade. As a consequence, namespace prefixes are now recognized in XPath expressions and the overall XPath conformance is better.

  • Better error reporting: If the processing of a template is aborted by a TemplateException being thrown, or using a <#stop> directive, FreeMarker will now output an execution trace with line and column numbers relative to the template source.

  • The output is written to a simple Writer; no more PrintWriter. This redesign causes FreeMarker to no longer swallow IOExceptions during template processing.

  • Various API cleanups, primarily the removing of superfluous constructor and method overloads.

Other changes

  • Documentation has been rewritten from scratch

Differences between the RC1 and final release

  • Added the support for date models and locale-sensitive date formatting. Date support is experimental in FreeMarker 2.1. It can change substantially in the future. Keep this in mind if you use it.

  • Added the default built-in which makes it possible to specify default values for undefined expressions.

  • SimpleIterator has been removed, SimpleCollection has been introduced

  • Arithmetic engine is pluggable. The core now contains two arithmetic engines: ArithmeticEngine.BIGDECIMAL_ENGINE and ArithmeticEngine.CONSERVATIVE_ENGINE.

  • BeansWrapper supports a new exposure level: EXPOSE_NOTHING

  • Constants interface was removed. ..._WRAPPER constants have been moved from Constants to ObjectWrapper, EMPTY_STRING constant was moved to TemplateScalarModel, NOTHING constant was moved to TemplateModel, TRUE and FALSE constants were moved to TemplateBooleanModel.


  • Configuration.get and put, putAll were renamed to getSharedVariable and setSharedVariable, setAllSharedVariables

  • Configuration.getClassicCompatibility, setClassicCompatibility were renamed to isClassicCompatible, setClassicCompatible

  • Template.process method overloads with useReflection parameter was removed. But now we have setObjectWrapper method in the Configuration, so you can set the preferred root-object wrapper there.

  • Some superfluous method overloads were removed; these changes are backward compatible with RC1

  • Various minor JavaDoc and Manual improvements

  • Bugfix: include directive has calculated the base path of relative paths wrongly

  • Bugfix: We have accidentally used a J2SE 1.3 class, but FreeMarker 2.1 must able to run on J2SE 1.2