2.2

Date of release: 2003-03-27

This release introduces some really important new features. Unfortunately, evolution was painful again; we have a few non-backward compatible changes (see below). Also, for those of you awaiting desired native date/time type, sorry, it is still not here (because of some internal chaos in the team... stand by, it's coming).

Non backward-compatible changes!

  • Macros are now plain variables. This means that if you are unlucky and you have both a macro and another variable with the same name, now the variable will overwrite the macro, so your old template will malfunction. If you have a collection of common macros, you should use the new namespace feature to prevent accidental clashes with the variables used in the templates.

  • With the introduction of the new namespace support, global and assign directives are no longer synonyms. assign creates a variable in the current namespace, while global creates variable that is visible from all namespaces (as if the variable would be in the data-model). Thus, the variable created with assign is more specific, and hides the variable of the same name created with global. As a result, if you use both global and assign mixed for the same variable in your templates, now they will malfunction. The solution is to search-and-replace all globals in your old templates with assign.

  • The reserved hash root no longer exists as a predefined variable (we no longer have reserved variables). Use special variable expressions to achieve similar effects. However, we have no equivalent replacement for root because of the changes in the variable scopes caused by the introduction of namespaces. You may should use .globals or .namespace.

  • The BeansWrapper no longer exposes native Java arrays, booleans, numbers, enumerations, iterators, and resource bundles as TemplateScalarModel. This way, number objects wrapped through BeansWrapper are subject to FreeMarker's number formatting machinery. Also, booleans can be formatted using the ?string built-in.

  • The signature of Configuration.setServletContextForTemplateLoading has been changed: the first parameter is now Object instead of javax.servlet.ServletContext. Thus, you have to recompile your classes that call this method. The change was required to prevent class-loading failure when javax.servlet classes are not available and you would not call this method.

  • This release introduces a parse-time white-space remover that strips some of the typical superfluous white-space around FreeMarker tags and comments. This feature is on by default! Most probably this will not cause problems if you generate white-space neutral output like HTML. But if it does cause undesirable reformatting in output you generate, you can disable it with config.setWhitespaceStripping(false). Also, you can enable/disable it on a per-template basis with the new ftl directive.

  • Some new directives were introduced: nested, import, escape, noescape, t, rt, lt. This means that if you are unlucky and the text of your template contains something like <nested>, then that will be misinterpreted as a directive. To prevent this kind of problem in the future, we recommend everybody to switch from the old syntax to the new syntax ("strict syntax"). The strict syntax will be the the default syntax starting from some of the later releases anyway. We plan to release a conversion tool for converting old templates. For more information please read: Template Language Reference/Deprecated FTL constructs/Old FTL syntax

  • The data-model created by the FreemarkerServlet now uses automatic scope discovery, so writing Application.attrName, Session.attrName, Request.attrName is no longer mandatory; it's enough to write attrName (for more information read this). This may break an old template if that rely on the non-existence of certain top-level variables.

  • FreemarkerServlet now uses the encoding of the template file for the output, unless you specify the encoding in the ContentType init-param, such as text/html; charset=UTF-8.

  • The format of template paths is now more restricted than before. The path must not use /, ./ and ../ and :// with other meaning as they have in URL paths (or in UN*X paths). The characters * and ? are reserved. Also, the template loader must not want paths starting with /. For more information please read: Programmer's Guide/The Configuration/Template loading

  • Till now TemplateTransformModel.getWriter has received null as parameter map if the transform was called without parameters. From now, it will receive an empty Map instead. Note that the previous API documentation didn't state that it always receives null if there are no parameters, so hopelessly only very few classes exploit this design mistake.

Changes in FTL (FreeMarker Template Language)

  • User-defined directives: Transform and macro call syntax has been unified; they can be called in the same way, as user-defined directives. This also means that macros support named parameters and nested content (like the -- now deprecated -- transform directive did). For example, if you have a macro called sect, you may call it via <@sect title="Blah" style="modern">Blah blah...</@sect>. For more information read: Template Author's Guide/Miscellaneous/Defining your own directives

  • Macros are now plain variables. This significantly simplifies FreeMarker semantics, while providing more flexibility; for example you can pass macros as parameters to other macros and transforms. As for the problem of clashing commonly-used-macro and variable names, we provide a more powerful solution: namespaces.

  • Namespaces: Names-spaces are invaluable if you want to assemble collections ("libraries") of macros and transforms (and other variables), and then use them in any template without worrying about accidental name clashes with the application specific and temporary variables, or with the variables of other collections you want to use in the same template. This is extremely important if FreeMarker users want to share their macro/transform collections. For more information read: Template Author's Guide/Miscellaneous/Namespaces

  • With the introduction of namespaces our variable related terminology changed. As a result, assign is no longer synonymous with global. The assign directive has been undeprecated, and should be used instead of global almost everywhere. In the new approach assign creates variables in the current namespace, while global creates a variable that is visible from all namespaces (as if the variable were in the root of the data-model). A variable created with assign in the current namespace hides the variable of the same name that was created with global.

  • ftl directive: With this directive you can give information about the template for FreeMarker, like the encoding (charset) of the template, the used FTL syntax variant, etc. Also, this directive helps you to write templates that are less dependent on FreeMarker configuration settings, also it helps third-party tools to identify and correctly parse FreeMarker templates. For more information see: ftl directive

  • White-space stripping: FreeMarker now automatically removes some of the typical superfluous white-spaces around FreeMarker tags and comments, like the indentation spaces before- and line-break after <#if ...> tags. For more information read: Template Author's Guide/Miscellaneous/White-space handling/White-space stripping

  • New directive to apply a common ("escaping") expression to all interpolations in a block: escape. The name comes from the common usage of this directive for automatic HTML-escaping of interpolations.

  • The new and preferred way of number formatting with string built-in is foo?string(format), instead of the less natural foo?string[format].

  • The string built-in works for boolean values. For example: ${spamFilter?string("enabled", "disabled")}. For more information read the reference.

  • The default strings for outputting boolean value using the string built-in can be set using the boolean_format setting.

  • Comments can be placed inside FTL tags and interpolations. For example: <#assign <#-- a comment --> x = 3>

  • All letters and numbers are enabled in variable names, also $ is allowed (as in Java programming language). Thus you can use accents, Arabic letters, Chinese letters, etc.

  • String literals can be quoted with apostrophe-quote. "foo" and 'foo' are equivalent.

  • New string built-ins: index_of, last_index_of, starts_with, ends_with, replace, split, chop_linebreak, uncap_first.

  • New sequence built-ins: sort, sort_by.

  • New built-ins for experts to check the type of a variable. See: is_... built-ins

  • New built-in for experts to create a variable of certain Java TemplateModel implementation. See: new built-in

  • New built-in, namespace, to get the namespace of a macro.

  • New expression type: special variable expression. To prevent backward compatibility problems when we introduce new predefined variables, from now special variable expressions are used to access them.

  • New directives: t, rt and lt directives allow you to do explicit white-space removal in extreme FTL applications. For more information read the reference.

  • assign, local and global now can capture the output generated be the nested template fragment into the variable. This deprecates capture_output transform. More information: assign directive reference

  • Bulk assignments (as <#assign x=1, y=2, z=3>) no longer need colon to separate the assignments (as <#assign x=1 y=2 z=3>), although it is still allowed to preserve backward compatibility.

  • Path that contains //: is considered as absolute path.

  • include and transform directives no longer need a semicolon to separate the template or transform name from the parameter list, although it is still allowed to preserve backward compatibility.

  • #-less tag syntax is deprecated (but still working). That is, you should write <#directive ...> instead of <directive ...>, and </#directive ...> instead of </directive ...>. For more info read: Template Language Reference/Deprecated FTL constructs/Old FTL syntax

  • foreach is depreciated (but still working). Use list instead.

  • Bugfix: Undefined variables in hash and sequence constructors (as [a, b, c]) didn't caused errors.

  • Bugfix: String concatenation had performance problem if there was multiple concatenations chained, as: "a"+x+"a"+x+"a"+x+"a"+x+"a"+x.

Changes on the Java side

  • Arbitrary JSP custom tags can be used as FreeMarker transforms in FreemarkerServlet-driven templates. More information: Programmer's Guide/Miscellaneous/Using FreeMarker with servlets

  • Various improvements for BeansWrapper:

    • The BeansWrapper no longer exposes arbitrary objects as TemplateScalarModels, only java.lang.String and Character objects. This way, number objects wrapped through BeansWrapper are subject to FreeMarker's number formatting machinery. As a side effect, non-string and non-number objects that were previously accepted in equality and inequality operations (because they had a string representation) will now cause the engine to throw exception on comparison attempt.

    • java.lang.Character objects are exposed as scalars through BeansWrapper.

    • Experimental feature: With the setSimpleMapWrapper method of BeansWrapper you can configure it to wrap java.util.Map-s as TemplateHashModelEx-s, and do not expose the methods of the object.

  • TransformControl interface (was experimental earlier): If the Writer returned by TemplateTransformModel.getWriter implements this interface, it can instruct the engine to skip or to repeat evaluation of the nested content, and gets notified about exceptions that are thrown during the nested content evaluation. Note that the onStart and afterBody methods now are allowed to throw IOException. For more information please read the API documentation.

  • Localized lookup can be disabled with the new Configuration methods: set/getLocalizedLookup, clearTemplateCache

  • The new interface freemarker.cache.CacheStorage allows users to plug custom template caching strategies with the cache_storage setting. The core package now ships with two implementations: SoftCacheStorage and StrongCacheStorage. For more information read: Programmer's Guide/The Configuration/Template loading

  • You can set settings with string name and string value with the new setSetting(String key, String value) method of Configurable super-classes (as Configuration). Also you can load settings from .properties file with the setSettings method.

  • Other new Configuration methods: clearTemplateCache, clearSharedVariables, getTemplateLoader, and clone.

  • Changes to TemplateTransformModel interface: getWriter can throw IOException, and can return null if the transform does not support body content.

  • Till now TemplateTransformModel.getWriter has received null as parameter map if the transform was called without parameters. From now, it will receive an empty Map instead. Note that the previous API documentation didn't state that it always receives null if there are no parameters, so hopelessly only very few classes exploit this design mistake.

  • Various improvements for FreemarkerServlet:

    • The data-model now uses automatic scope discovery, so writing Application.attrName, Session.attrName, Request.attrName is no longer mandatory; it's enough to write attrName. For more information read this.

    • FreemarkerServlet now uses the encoding of the template file for the output, unless you specify the encoding in the ContentType init-param, such as text/html; charset=UTF-8.

    • All Configuration level settings can by set with Servlet init-params (template_exception_handler, locale, number_format, etc.).

    • The object wrapper the servlet internally uses is now set as the default object wrapper for its Configuration instance.

    • It no longer forces session creation for requests that don't belong to an existing session, improving scalability.

  • JDOM independent XML-wrapping: freemarker.ext.xml.NodeListModel is a re-implementation of freemarker.ext.jdom.NodeListModel that does not rely on JDOM; you don't need JDOM .jar anymore. The new NodeListModel automatically uses W3C DOM, dom4j, or JDOM, depending on which library is available (that is, depending on what object do you pass to its constructor).

  • Bugfix: WebappTemplateLoader: Template updating didn't worked correctly with Tomcat due the caching of resources. Now WebappTemplateLoader tries to access the resources directly as File, if it is possible, thus bypasses the caching.

  • Various bug-fixes for FreemarkerServlet:

    • The servlet now loads the correct template if it was called through RequestDispatcher.include.

    • The caching of HttpServletRequest objects is now compliant with the servlet specification.

    • TemplateExceptions was suppressed in certain situations resulting in half-rendered pages without error message.

  • Bugfix: FreeMarker didn't work if the javax.servlet classes was not available, because Configuration explicitly referred to javax.servlet.ServletContext.

  • Bugfix: classes may were not found if they was available only in the WEB-INF, and FreeMarker tried to load the class dynamically.

  • Bugfix: the Template constructor (and thus Configuration.getTemplate) sometimes threw TokenMgrError (a non-checked exception) instead of ParseException.

Other changes

  • The Web application related examples has been replaced.

The history of the releases before the final version

Differences between the final and RC2 releases

  • You can load settings from .properties file with the setSettings method of Configuration and other Configurable subclasses.

  • New string built-in: uncap_first

  • Bugfix: When exposing an XML document to a template and accessing it with XPath using Jaxen a ClassCastException has occurred.

  • Bugfix: The template cache has loaded templates with bad Configuration instance in certain situations if you use not the static default Configuration instance.

Differences between the RC2 and RC1 releases

  • Non backward compatible change!: FreemarkerServlet now uses the encoding of the template file for the output, unless you specify the encoding in the ContentType init-param, such as text/html; charset=UTF-8.

  • Non backward compatible change compared to RC1!: The capture_output transform creates variable in the current namespace (as assign directive) with the var parameter, not a global variable.

  • The new and preferred way of number formatting with string built-in is foo?string(format), instead of the less natural foo?string[format].

  • The string built-in works for boolean values. For example: ${spamFilter?string("enabled", "disabled")}. For more information read the reference.

  • The default strings for outputting boolean value using the string built-in can be set using the boolean_format setting.

  • String literals can be quoted with apostrophe-quote. "foo" and 'foo' are equivalent.

  • The new interface freemarker.cache.CacheStorage allows users to plug custom template caching strategies with the cache_storage setting. The core package now ships with two implementations: SoftCacheStorage and StrongCacheStorage. For more information read: Programmer's Guide/The Configuration/Template loading

  • You can set settings with string name and string value with the new setSetting(String key, String value) method of Configurable super-classes (as Configuration).

  • Other new Configuration methods: getTemplateLoader, clone.

  • assign, local and global now can capture the output generated be the nested template fragment into the variable. This deprecates capture_output transform. More information: assign directive reference

  • Other new Configuration methods: getTemplateLoader, clone.

  • Changes to TemplateTransformModel interface: getWriter can throw IOException, and can return null if the transform does not support body content.

  • Till now TemplateTransformModel.getWriter has received null as parameter map if the transform was called without parameters. From now, it will receive an empty Map instead. Note that the previous API documentation didn't state that it always receives null if there are no parameters, so hopelessly only very few classes exploit this design mistake.

  • Changes to TemplateControl interface: onStart and afterBody methods are now allowed to throw IOException.

  • Path that contains //: is considered as absolute path.

  • New string built-ins: index_of, last_index_of, starts_with, ends_with, replace, split, chop_linebreak.

  • New sequence built-ins: sort, sort_by.

  • All Configuration level settings can by set with Servlet init-params (template_exception_handler, locale, number_format, etc.).

  • Bugfix: classes may were not found if they was available only in the WEB-INF, and FreeMarker tried to load the class dynamically.

  • Bugfix: setLocalizedLookup(false) of Configuration was overridden when you have called setTemplateLoader.

  • Bugfix: String concatenation had performance problem if there was multiple concatenations chained, as: "a"+x+"a"+x+"a"+x+"a"+x+"a"+x.

  • Bugfix: white-space stripping was not worked with tags spanning over multiple lines.

  • Bugfix: Removing several dependencies on JDK 1.3, so FreeMarker can be build for JDK 1.2.2.

Differences between the Preview 2 and RC1 releases

  • ftl is now stricter, and does not allow custom parameters. To associate custom attributes to templates, we may add a new directive later, if there is a demand for it.

  • escape directive does not affect numerical interpolations (#{...}) anymore, as it has caused errors with string escapes as ?html.

  • The normalizeName method of freemarker.cache.TemplateLoader has been removed, because it has caused too many complications. Instead, normalization happens on a single point in the TempateCache. In consequence, FreeMarker is now stricter about the format of template paths, as things like /../ are interpreted by the core.

  • Experimental feature: With the setSimpleMapWrapper method of BeansWrapper you can configure it to wrap java.util.Map-s as TemplateHashModelEx-s, and do not expose the methods of the object.

  • New Configuration methods: set/getLocalizedLookup, clearTemplateCache, clearSharedVariables.

  • More cleanups in the Environment API.

  • Better JSP standard compliance: JSP page-scope variables are the global variables that were created in the template (not the variables of the data-model).

  • JDOM independent XML-wrapping: freemarker.ext.xml.NodeListModel is a re-implementation of freemarker.ext.jdom.NodeListModel that does not rely on JDOM; you don't need JDOM .jar anymore. The new NodeListModel automatically uses W3C DOM, dom4j, or JDOM, depending on which library is available (that is, depending on what object do you pass to its constructor).

  • Bugfix: WebappTemplateLoader: Template updating didn't worked correctly with Tomcat due the caching of resources. Now WebappTemplateLoader tries to access the resources directly as File, if it is possible, thus bypasses the caching.

  • Bugfix: Templates loaded with MultiTemplateLoader subclasses was removed from the template cache after the template update delay has elapsed (5 seconds by default) even if the template file was unchanged. This can cause lot of extra load for a high-traffic server if you have many templates or if the template update delay was set to 0 second.

  • Bugfix: Undefined variables in hash and sequence constructors (as [a, b, c]) didn't caused errors.

Differences between the Preview 1 and Preview 2 releases

  • All 16-bit Unicode letters and numbers are allowed in identifiers, as well as the $ character (as in Java programming language). Thus you can use accented letters, Arabic letters, Chinese letters, etc. as identifiers in templates

  • Macros now can create loop variables for the nested content. For more information read this.

  • New directives: t, rt and lt directives allow you to do explicit white-space removal in extreme FTL applications. For more information read the reference.

  • The syntax of assignment-with-namespace has changed from <#assign foo=123 namespace=myLib>) to <#assign foo=123 in myLib>, since the previous syntax was confusing because its similarity to a bulk-assignment.

  • Bulk assignments (as <#assign x=1, y=2, z=3>) no longer need colon to separate the assignments (as <#assign x=1 y=2 z=3>), although it is still allowed to preserve backward compatibility.

  • Positional parameter passing is supported for macro calls as shorthand form of normal named parameter passing. For more details read read the reference.

  • New built-in, namespace, to get the namespace of the currently executing macro.

  • TransformControl interface (was experimental earlier): If the Writer returned by TemplateTransformModel.getWriter implements this interface, it can instruct the engine to skip or to repeat evaluation of the nested content, and gets notified about exceptions that are thrown during the nested content evaluation. For more information please read the API documentation.

  • Jython wrapper can now wrap arbitrary Java objects, not only PyObject-s. If an object is passed to the wrapper that is neither a TemplateModel, nor a PyObject, it is first coerced into a PyObject using Jython's own wrapping machinery, and then wrapped into a TemplateModel as any other PyObject.

  • Some cleanups in the Environment API.

  • The Web application related examples has been replaced.

  • Bugfix: Templates loaded with URLTemplateLoader subclasses was removed from the template cache after the template update delay has elapsed (5 seconds by default) even if the template file was unchanged. This can cause lot of extra load for a high-traffic server if you have many templates or if the template update delay was set to 0 second.

  • Bugfix: FreeMarkerServlet has thrown ServletException even if a debug TemplateException handler was in use (so you may got Error 500 page instead of debug information).