Date of release: 2004-June-15

FreeMarker 2.3 introduces numerous little new features and quality improvements compared to the 2.2.x series. The most notable improvements are the ability to define functions (methods) in templates, the ability to interpolate variables in string literals, the support for a variable number of macro parameters, and the more intelligent default object wrapper. Although none of the improvements is a drastic change, the 2.3.x series is not backward compatible with the 2.2.x series (see the list below), so you may choose to use it for new projects only.

Probably the most ``loudly promoted'' new feature is the totally redesigned XML wrapper. With the new XML wrapper FreeMarker targets a new application domain, which is similar to the application domain of XSLT: transforming complex XML to whatever textual output. Although this subproject is young, it is definitely usable in practice. See the XML Processing Guide for more details.

Non backward-compatible changes!

  • Since interpolations (${...} and #{...}) now work inside string literals, the character sequence ${ and #{ in string literals are reserved for that. So if you have something like <#set x = "${foo}">, then you have to replace it with <#set x = r"${foo}"> -- beware, escapes such as \n will not work in raw (r) strings.

  • The default (initial) value of the strict_syntax setting has been changed from false to true. When strict_syntax is true, tags with old syntax as <include "foo.ftl"> will be considered as static text (so they go to the output as-is, like HTML tags do), and not as FTL tags. Such tags have to be rewritten to <#include "foo.ftl">, since only parts that starts with <#, </#, <@, or </@ count as FTL tags. Or, to recover the old transitional behavior, where both legacy and new tag syntax was recognized, you have to explicitly set strict_syntax to false: cfg.setStrictSyntaxMode(false). Also, for individual templates you can force the old behavior by starting the template with <#ftl strict_syntax=false>. (For more information about why strict syntax is better than old syntax read this...)

  • Several classes were moved from the freemarker.template package, to the new freemarker.core package:

    • "Normal" classes: ArithmeticEngine, Configurable, Environment
    • Exceptions: InvalidReferenceException, NonBooleanException, NonNumericalException, NonStringException, ParseException, StopException
    • Errors: TokenMgrError

    The main reason of the splitting of freemarker.template package was that the amount of "expert" public classes and interfaces grows too much, as we introduce API-s for third-party tools, such as debugging API.

  • freemarker.template.TemplateMethodModel.exec now returns Object instead of TemplateModel.

  • White-space stripping is now more aggressive as before: it always removes leading and trailing white-space if the line only contains FTL tags. (Earlier the white-space was not removed if the tag was <#include ...> or user-defined directive tag with empty directive syntax as <@myMacro/> (or its equivalents: <@myMacro></@myMacro> and <@myMacro></@>). Now white-space is removed in these cases as well.) Also, white-space sandwiched between two non-outputting elements, such as macro definitions, assignments, imports, or property settings, is now ignored. More information: 模板开发指南/其它/空白处理/剥离空白

  • The function directive is now used for defining methods. You should replace function with macro in your old templates. Note, however, that old function-s will still work if you don't use the return directive in them, and you invoke them with the deprecated the call directive.

  • The expressions as, in, and using are now keywords in the template language and cannot be used as top-level variable names without square-bracket syntax. If, by some chance, you have top-level variables that use one of these names, you will have to rename them, or use the square-bracket syntax with the .vars special variable: .vars["in"].

  • The ?new built-in, as it was implemented, was a security hole. Now, it only allows you to instantiate a java object that implements the freemarker.template.TemplateModel interface. If you want the functionality of the ?new built-in as it existed in prior versions, make available an instance of the freemarker.template.utility.ObjectConstructor class to your template. (For example: myDataModel.put("objConstructor", new ObjectConstructor());, and then in the template you can do this: <#assign aList = objConstructor("java.util.ArrayList", 100)>)

  • Changes to the FreemarkerServlet:

    • The FreemarkerServlet uses ObjectWrapper.DEFAULT_WRAPPER by default instead of ObjectWrapper.BEANS_WRAPPER. What this means is that, by default, objects of type java.lang.String, java.lang.Number, java.util.List, and java.util.Map will be wrapped as TemplateModels via the classes SimpleScalar, SimpleNumber, SimpleSequence, and SimpleHash respectively. Thus, the java methods on those objects will not be available. The default wrapper implementation in FreeMarker 2.3 automatically knows how to wrap Jython objects, and also wraps org.w3c.dom.Node objects into instances of freemarker.ext.dom.NodeModel.

    • The FreemarkerServlet base implementation no longer deduces the locale used for templates with HttpRequest.getLocale(). Rather, it simply delegates to the new protected method, deduceLocale. The default implementation of this method simply returns the value of configuration the locale setting.

Changes on the FTL side

  • Interpolation in string literals. For convenience, interpolations are now supported in string literals. For example: <@message "Hello ${user}!" /> is the same as <@message "Hello " + user + "!" />

  • Raw string literals: In string literals prefixed with r, interpolations and escape sequences will not be interpreted as special tokens. For example: r"\n${x}" will be simply interpreted as the character sequence '\', 'n', '$', '{', 'x', '}', and not as line-feed and the value of the x variable.

  • Method variables can be defined in FTL, with the function directive.

  • Support for a variable number of macro parameters. If the last parameter in a macro declaration ends with ..., all extra parameters passed to the macro will be available via that parameter. For macros called with positional parameters, the parameter will be a sequence. For named parameters, the parameter will be a hash. Note that it all works with the new function directive as well.

  • A new header parameter, strip_text, that removes all top-level text from a template. This is useful for ``include files'' to suppress newlines that separate the macro definitions. See ftl directive

  • New special variable: .vars. This is useful to read top-level variables with square bracket syntax, for example .vars["name-with-hyphens"] and .vars[dynamicName].

  • macro and assignment directives now accept arbitrary destination variable name with quoted syntax. For example: <#macro "name-with-hyphens">... or <#assign "foo bar" = 123>.

  • The ?keys and ?values hash built-ins now return sequences. In practical terms this means you can access their sizes or retrieve their sub variables by index, and use all of the sequence built-ins. (Note for the programmers: The TemplateHashModelEx interface has not been changed. Your old code will work. See the API documentation to see why.)

  • Existence built-ins (?default, ?exists, etc.) are now working with sequence sub variables as well. Read the documentation of the default built-in for more information.

  • White-space stripping is now more aggressive as before: it always removes leading and trailing white-space if the line only contains FTL tags. (Earlier the white-space was not removed if the tag was <#include ...> or user-defined directive tag with empty directive syntax as <@myMacro/> (or its equivalents: <@myMacro></@myMacro> and <@myMacro></@>). Now white-space is removed in these cases as well.) Also, top-level white-space that separates macro definitions and/or assignments is now ignored. More information: 模板开发指南/其它/空白处理/剥离空白

  • White-space stripping can be disabled for a single line with the nt directive (for No Trim).

  • Hashes can be concatenated using the + operator. The keys in the hash on the right-hand side take precedence.

  • New built-ins for Java and JavaScript string escaping: j_string and js_string

  • The replace and split built-ins now support case-insensitive comparsion and regular expressions (J2SE 1.4+ only), and some other new options. More information can be found here.

  • New built-in for regular expression matching (J2SE 1.4+ only): matches

  • New built-in, eval, to evaluate a string as FTL expression. For example "1+2"?eval returns the number 3.

  • New built-ins for Java and JavaScript string escaping: j_string and js_string

  • New special variables to read the value of the locale setting: locale, lang. See more in the reference...

  • New special variable to read the FreeMarker version number: version. See more in the reference...

  • Tree new directives, recurse, visit and fallback, were introduced to support declarative node-tree processing. These are meant to be used typically (though not exclusively) for processing XML input. Together with this, a new variable type has been introduced, the node type. See the chapter on declarative XML processing for more details.

  • The ?new built-in, as it was implemented, was a security hole. Now, it only allows you to instantiate a java object that implements the freemarker.template.TemplateModel interface. If you want the functionality of the ?new built-in as it existed in prior versions, make available an instance of the freemarker.template.utility.ObjectConstructor class to your template. (For example: myDataModel.put("objConstructor", new ObjectConstructor());, and then in the template you can do this: <#assign aList = objConstructor("java.util.ArrayList", 100)>)

  • Variable names can contain @ anywhere (without using quote-bracket syntax). For example: <#assign x@@@ = 123> is valid.

  • The expressions as, in, and using are now keywords in the template language and cannot be used as top-level variable names without square-bracket syntax (as .vars["in"]).

  • New parameter to the ftl directive: attributes. The value of this attribute is a hash that associates arbitrary attributes (name-value pairs) to the template. The values of the attributes can be of any type (string, number, sequence... etc.). FreeMarker doesn't try to understand the meaning of the attributes. It's up to the application that encapsulates FreeMarker (as a Web application framework). Thus, the set of allowed attributes and their semantic is application (Web application framework) dependent.

  • Other minor quality improvements...

Changes on the Java side

  • Smarter default object wrapping: The default object wrapper is now freemarker.template.DefaultObjectWrapper, which falls back on wrapping arbitrary objects as beans using the freemarker.ext.beans.BeansWrapper. Also, it will wrap org.w3c.dom.Node objects with the new DOM wrapper. Also, it is aware of Jython objects, and will use freemarker.ext.jython.JythonWrapper if the object passed in is a Jython object. (We count it as a backward compatible change, since this new object wrapper wraps differently only those objects that the old wrapper was not able to wrap, so it has thrown exception.)

  • freemarker.template.TemplateMethodModel.exec now returns Object instead of TemplateModel.

  • The default (initial) value of the strict_syntax setting has been changed from false to true. When strict_syntax is true, tags with old syntax as <include "foo.ftl"> will be considered as static text (so they go to the output as-is, like HTML tags do), and not as FTL tags. Such tags have to be rewritten to <#include "foo.ftl">, since only parts that starts with <#, </#, <@, or </@ count as FTL tags. Or, to recover the old transitional behavior, where both legacy and new tag syntax was recognized, you have to explicitly set strict_syntax to false: cfg.setStrictSyntaxMode(false). Also, for individual templates you can force the old behavior by starting the template with <#ftl strict_syntax=false>. (For more information about why strict syntax is better than old syntax read this...)

  • New CacheStorage implementation: freemarker.cache.MruCacheStorage. This cache storage implements a two-level Most Recently Used cache. In the first level, items are strongly referenced up to the specified maximum. When the maximum is exceeded, the least recently used item is moved into the second level cache, where they are softly referenced, up to another specified maximum. freemarker.cache.SoftCachseStorage and StrongCachseStorage are deprected, MruCachseStorage is used everywhere instead. The default cache storage is now an MruCachseStorage object with 0 strong size, and infinite soft size. Configuration.setSetting for cache_storage now understands string values as "strong:200, soft:2000".

  • For BeansWrapper generated models, you can now use the ${obj.method(args)} syntax to invoke methods whose return type is void. void methods now return TemplateModel.NOTHING as their return value.

  • freemarker.template.SimpleHash now can wrap read-only Map-s, such as the map of HTTP request parameters in Servlet API.

  • The TemplateNodeModel interface was introduced to support recursive processing of trees of nodes. Typically, this will be used in relation to XML.

  • New package: freemarker.ext.dom. This contains the new XML wrapper, that supports the processing of XML documents using the visitor pattern (i.e. with <#visit ...> and similar directives), and to provide more convenient XML traversing as the legacy wrapper. See the XML processing guide for more details.

  • New package: freemarker.core. Classes used by mostly power-users was moved here from the freemarker.template package. The main reason of the splitting of freemarker.template package was that the amount of "expert" public classes and interfaces grows too much, as we introduce API-s for third-party tools, such as debugging API.

  • New package: freemarker.debug. This provides a debugging API, by which you can debug executing templates through network (RMI). You have to write the front-end (client), as the API is just the server side. For more information please read the JavaDoc of the freemarker.debug package.

  • You can query the FreeMarker version number with static method Configuration.getVersionNumber(). Also, the Manifest.mf included in freemarker.jar now contains the FreeMarker version number, furthermore, executing it with java -jar freemarker.jar will print the version number to the stdout.

  • Added a new protected FreemarkerServlet method: Configuration getConfiguration().

  • Date support is now labeled as final. (It was experimental earlier.)

  • The BeansWrapper has been improved to prevent some security exceptions when introspecting.

  • Other minor quality improvements and extensions...

Other changes

  • Fixes and improvements in the Manual and in the API JavaDoc.

The history of the releases before the final version

Differences between the final release and Release Candidate 4

  • Added a new special variable to print the FreeMarker version number: version. See more in the reference...

  • Minor documentation fixes and improvements.

Differences between the Release Candidate 4 and Release Candidate 3

  • The BeansWrapper has been improved to prevent some security exceptions when introspecting.

  • The FreemarkerXmlTask has two new sub-tasks that can be used to prepare template execution with Jython scripts: prepareModel and prepareEnvironment. The jython sub-task is now deprecated, and does the same as prepareEnvironment. See the Java API documentation for more details.

  • New special variable to read the FreeMarker version number: version. See more in the reference...

  • Bugfix: Greater-than sign doesn't confuse the eval built-in anymore.

  • Bugfix: The BeansWrapper now wrapps the null return values of methods appropriately.

  • Bugfix: The FreemarkerXmlTask doesn't need Jython classes anymore, unless you really use Jython scripts. Several other bugfixes in the Jython related features.

  • Bugfix: If the template exception handler has ignored the exception, errors occurring in interpolations inside FTL tags (e.g. <#if "foo${badVar}" != "foobar">) were handled in the same way as errors occuring in interpolations outside FTL tags. Thus, the directive call was not skipped, and the problematic interpolation was replaced with an empty string. (This was inconsistent with the behavior of <#if "foo"+badVar != "foobar">, which should be 100% equivalent with the previous example.)

  • Bugfix: The FileTemplateLoader is now more robust when it receives paths that are malformed according the native file system. In the earlier version such paths sometimes caused unexpected IOException that aborted the searching for the template in further FileTemplateLoader-s when you use the MultiTemplateLoader.

Differences between the Release Candidate 3 and Release Candidate 2

  • Bugfix: Fixing a fatal bug in the template cache that was introduced with the latest cache ``bugfix''. The template cache has always reloaded the unchanged template when the update delay has been elapsed, until the template has been actually changed, in which case it has never reloaded the template anymore.

Differences between the Release Candidate 2 and Release Candidate 1

  • Bugfix: The template cache didn't reload the template when it was replaced with an older version.

  • API JavaDoc fix: date/time related classes/interfaces were marked as experimental. They are not experimental.

  • Minor site improvements.

Differences between the Release Candidate 1 and Preview 16 releases

  • Warning! Non-backward-compatible change! The default (initial) value of the strict_syntax setting has been changed from false to true. When strict_syntax is true, tags with old syntax as <include "foo.ftl"> will be considered as static text (so they go to the output as-is, like HTML tags do), and not as FTL tags. Such tags have to be rewritten to <#include "foo.ftl">, since only parts that starts with <#, </#, <@, or </@ count as FTL tags. Or, to recover the old transitional behavior, where both legacy and new tag syntax was recognized, you have to explicitly set strict_syntax to false: cfg.setStrictSyntaxMode(false). Also, for individual templates you can force the old behavior by starting the template with <#ftl strict_syntax=false>. (For more information about why strict syntax is better than old syntax read this...)

  • New parameter to the ftl directive: attributes. The value of this attribute is a hash that associates arbitrary attributes (name-value pairs) to the template. The values of the attributes can be of any type (string, number, sequence... etc.). FreeMarker doesn't try to understand the meaning of the attributes. It's up to the application that encapsulates FreeMarker (as a Web application framework). Thus, the set of allowed attributes and their semantic is application (Web application framework) dependent.

  • Bugfix: freemarker.template.utility.DeepUnwrap unwrapped sequences to empty ArrayList-s.

  • Bugfix: If you included/imported a template with */ in path (acquisition), and that template in turn itself included/imported another template with */ in path, it may failed.

  • New methods to the freemarker.core.Environment: importLib(Template loadedTemplate, java.lang.String namespace), getTemplateForImporting(...), getTemplateForInclusion(...).

  • Improvements in the java.io.IOException related error messages of the include and import directives.

  • Minor improvements in the documentation.

Differences between the Preview 16 and Preview 15 releases

  • New package: freemarker.debug. This provides a debugging API, by which you can debug executing templates through network (RMI). You have to write the front-end (client), as the API is just the server side. For more information please read the JavaDoc of the freemarker.debug package. (The debugging API is present for a while, just I forgot to announce it in the version history. Sorry for that.)

  • Bugfix: With the new XML wrapper, @@markup and similar special keys:

    • have returned <foo></foo> for empty elements instead of <foo />. Other than it was needlessly verbose, it has confused browsers if you generate HTML.

    • have showed the attributes that have no explicitly given value in the original document, just a default value coming form the DTD.

    • have forgot to put space before the system identifier in the <!DOCTYPE ...>.

  • Bugfix: XPath with Jaxen has died with NullPointerException if the context was an empty node set.

  • A bit more intelligent Xalan XPath error messages.

  • Revoked fallback-to-classloader logic from the template cache.

  • From now, if no XPath engine is available, and the hash key in an ``XML query'' can't be interpreted without XPath, an error will tell this clearly, rather than silently returning undefined variable (null).

  • Bugfix: Some templates have caused the parser to die.

  • Some other minor improvements here and there...

Differences between the Preview 15 and Preview 14 releases

  • Bugfix: The new default template cache storage (MruCacheStorage) has started to continually fail with NullPointerException from a random point of time, usually when the memory usage was high in the JVM.

  • Bugfix: In error messages, when the quoted FTL directive had nested content, that was quoted as well, so the quotation could be very long and expose nested lines needlessly.

Differences between the Preview 14 and Preview 13 releases

  • freemarker.template.TemplateMethodModel.exec now returns Object instead of TemplateModel.

  • Fixes and improvements for XPath with Jaxen (not Xalan). Non-node-set XPath expressions are now working. FreeMarker variables are accessible in XPath expressions with XPath variable references (e.g. doc["book/chapter[title=$currentTitle]"]).

  • freemarker.cache.SoftCachseStorage and StrongCachseStorage is deprected. The more flexible MruCachseStorage is used instead everywhere. The default cache storage is now an MruCachseStorage object with 0 strong size, and infinite soft size. Configuration.setSetting for cache_storage now understands string values as "strong:200, soft:2000".

  • Bugfix: freemarker.cache.MruCachseStorage has died with ClassCastException sometimes.

  • New built-ins for Java and JavaScript string escaping: j_string and js_string

  • freemarker.template.TemplateExceptionHandler.HTML_DEBUG_HANDLER now prints more HTML-context-proof messages.

  • You can query the FreeMarker version number with static method Configuration.getVersionNumber(). Also, the Manifest.mf included in freemarker.jar now contains the FreeMarker version number, furthermore, executing it with java -jar freemarker.jar will print the version number to the stdout.

  • Added a new protected FreemarkerServlet method: Configuration getConfiguration().

  • Bugfix: FreeMarker has frozen on empty conditional blocks in certain contexts.

  • Bugfix: Methods called twice on an object using the list directive, as parent.getChildren() with <#list parent.children as child> ...</#list>

Differences between the Preview 13 and Preview 12 releases

  • White-space stripping is now more aggressive as before: it always removes leading and trailing white-space if the line only contains FTL tags. (Earlier the white-space was not removed if the tag was <#include ...> or user-defined directive tag with empty directive syntax as <@myMacro/> (or its equivalents: <@myMacro></@myMacro> and <@myMacro></@>). Now white-space is removed in these cases as well.) Also, top-level white-space that separates macro definitions and/or assignments is now ignored. More information: 模板开发指南/其它/空白处理/剥离空白

  • White-space stripping can be disabled for a single line with the nt directive (for No Trim).

  • A new directive for the declarative XML processing: fallback

  • freemarker.template.SimpleHash now can wrap read-only Map-s, such as the map of HTTP request parameters in Servlet API.

Differences between the Preview 12 and Preview 11 releases

The only change between this and the previous preview release is that Preview 11 had a bug where DOM trees would never be garbage-collected.

Differences between the Preview 11 and Preview 10 releases

  • Many XML related changes. Some of them are incompatible with the previous preview releases! For a more detailed explanation of how XML related features now work, see: XML处理指南

    • Attention! Attribute queries such as foo.@bar now return sequences (similarly to child element queries and XPath queries), not single nodes. Because of the rule with node sequences of size 1, it is still good to write ${foo.@bar}, but built-ins such as ?exists, ?if_exists or ?default don't work as before. For example, instead of foo.@bar?default('black'), you now have to write foo.@bar[0]?default('black'). So if you have used existence built-ins with attributes, you have to find those occurrences in the templates and add that [0].

    • Attention! XML name-space handling has been totally reworked and is absolutely incompatible with pre 10. Don't worry about this if none of your XML input documents use you use xmlns attributes. Worry, though, if you have utilized the ``loose mode'', where only the local name of elements were compared, because that's now gone. Sorry...

    • Attention! Special-keys @@ and @* now return a sequence of attribute nodes instead of the hash of them.

    • Several hash keys are now working for node sequences that store multiple nodes. For example, to get the list of all para elements of all chapter-s, just write doc.book.chapter.para. Or, to get list of title attributes of all chapter-s write doc.book.chapter.@title.

    • New special hash keys: **, @@start_tag, @@end_tag, @@attribute_markup, @@text, @@qname.

    • ?parent for attribute nodes now returns the element node the attribute node belongs to.

    • You can use Jaxen instead of Xalan for XPath expressions, if you call the static freemarker.ext.dom.NodeModel.useJaxenXPathSupport() method once. We plan to use Jaxen automatically instead of Xalan if it is available, just the Jaxen support is not fully functional yet.

  • New special variable: .vars. This is useful to read top-level variables with square bracket syntax, for example .vars["name-with-hyphens"] and .vars[dynamicName].

  • New built-in, eval, to evaluate a string as FTL expression. For example "1+2"?eval returns the number 3.

  • FreemarkerServlet now uses the configuration's locale setting, rather than Locale.getDefault(), to set the locale of the templates. Also, the signature of the deduceLocale method has been changed.

  • We have a new (beta status) CacheStorage implementation: freemarker.cache.MruCacheStorage. This cache storage implements a two-level Most Recently Used cache. In the first level, items are strongly referenced up to the specified maximum. When the maximum is exceeded, the least recently used item is moved into the second level cache, where they are softly referenced, up to another specified maximum. You can plug to try it with cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(maxStrongSize, maxSoftSize)).

Differences between the Preview 10 and Preview 9 releases

  • The special key @@xmlns was removed in favor of a new FTL directive for the same purpose, <#xmlns...>.

  • By default, the system is stricter about the use of namespace prefixes. In general, you must use a prefix to qualify subelements that are associated with an XML nampespace. You can do this with the new <#xmlns...> directive, but prefixes declared in the input XML doc will actually work with no declaration.

  • Introduced a new special key called @@text that returns all the text nodes contained (recursively) in an element all concatenated together.

  • Either Jaxen or Xalan can be used to provide XPath functionality. Prior versions only worked with Xalan.

  • The FreemarkerServlet uses ObjectWrapper.DEFAULT_WRAPPER by default instead of ObjectWrapper.BEANS_WRAPPER. What this means is that, by default, objects of type java.lang.String, java.lang.Number, java.util.List, and java.util.Map will be wrapped as TemplateModels via the classes SimpleScalar, SimpleNumber, SimpleSequence, and SimpleHash respectively. Thus, the java methods on those objects will not be available. The default wrapper implementation in FreeMarker 2.3 automatically knows how to wrap Jython objects, and also wraps org.w3c.dom.Node objects into instances of freemarker.ext.dom.NodeModel.

  • The FreemarkerServlet base implementation no longer deduces the locale to use from the HttpRequest.getLocale() hook. Rather, it simply delegates to a deduceLocale() hook that is overridable in subclasses. The base implementation simply uses Locale.getDefault()

Differences between the Preview 9 and Preview 8 releases

  • Fixed bugs introduced with Preview 8: XPath, @@markup and @@nested_markup now works with the document node.

Differences between the Preview 8 and Preview 7 releases

  • macro and assignment directives now accept arbitrary destination variable name with quoted syntax. For example: <#macro "foo-bar">... or <#assign "this+that" = 123>. This is important, because XML element names can contain hyphen, and it was not possible to define a handler macro for those elements, till now.

  • Special key @@content was renamed to @@nested_markup.

  • Fixed outdated XML related Manual parts (that were outdated even in Preview 7).

  • Better parse-error messages.

  • Minor bugfixes here and there...

Differences between the Preview 7 and Preview 6 releases

  • Caching of XPath queries should lead to significant performance improvements for XML processing, at least when XPath is heavily used.

  • Refinements in handling of XML namespaces in the XML processing functionality. The new strict_namespace_handling setting introduced in 2.3pre6 was removed. A general-purpose solution was arrived at that should make that configuration setting unnecessary.

  • Special key @xmlns was renamed to @@xmlns. Reserved namespace prefix default was renamed to @@default.

  • The ftl directive now accepts non-string types.

  • New special keys were introduced for XML node wrappers in the freemarker.ext.dom package. The @@markup key returns the literal markup that make up that element and the @@content key returns all the element's markup excluding the opening and closing tags.

  • Minor bugfixes here and there...

Differences between the Preview 6 and Preview 5 releases

  • Existence built-ins (?default, ?exists, etc.) now work with sequence sub variables as well. Read the documentation of the default built-in for more information.

  • The matches built-in now returns a sequence instead of a collection.

  • Refinements in handling of XML namespaces in the XML processing functionality. A new setting, strict_namespace_handling was introduced. If this is set (it is off by default) any node-handling macro used in with the visit/recurse machinery must be from a macro library that declares in its ftl header that it handles the namespace in question.

  • Minor bugfixes here and there...

Differences between the Preview 5 and Preview 4 releases

  • The replace and split built-ins now support case-insensitive comparison and regular expressions (J2SE 1.4+ only), and some other new options. More information can be found here.

  • New butilt-in for regular expression matching (J2SE 1.4+ only): matches

  • Minor bugfixes here and there...

  • Manual: More browser-safe HTML-s. More updated content.

Differences between the Preview 4 and Preview 3 releases

  • Bugfix: with multi-type variables, + operator overload for hash type had higher precedence than the precedence of some older overloads.

  • The API documentation was missing from the distribution tar.gz.

Differences between the Preview 3 and Preview 2 releases

  • XML processing: Many various bugfixes, especially with the declarative processing.

  • XML processing: the namespace_uri built-in, the xmlnsuri header parameter, and the TemplateNodeModel.getNodeNamespace method were renamed to node_namespace and getNodeNamespace respectively.

  • XML processing: Better documentation. Especially, note: XML处理指南

  • A new header parameter, strip_text, that removes all top-level text from a template. See ftl directive

  • Support for a variable number of macro parameters. If the last parameter in a macro declaration ends with ..., all extra parameters passed to the macro will be available via that parameter. For macros called with positional parameters, the parameter will be a sequence. For named parameters, the parameter will be a hash.

  • For BeansWrapper generated models, you can now use the ${obj.method(args)} syntax to invoke methods whose return type is void. void methods now return TemplateModel.NOTHING as their return value.

Differences between the Preview 2 and Preview 1 releases

  • The freemarker.ext.dom.NodeModel API changed slightly. The setDocumentBuilder() method was changed to setDocumentBuilderFactory() because the older scheme was not thread-safe. The stripComments and stripPIs methods are renamed to The removeComments and removePIs, and are fixed now. A new method, simplify has been added.

  • The expressions as, in, and using are now keywords in the template language and cannot be used as top-level variable names without square-bracket syntax (as .vars["in"]). If, by some chance, you have top-level variables that use one of these names, you will have to rename them (or use the square-bracket syntax). Sorry for the inconvenience.

  • The ?new built-in, as it was implemented, was a security hole. Now, it only allows you to instantiate a java object that implements the freemarker.template.TemplateModel interface. If you want the functionality of the ?new built-in as it existed in prior versions, make available an instance of the new freemarker.template.utility.ObjectConstructor class to your template.

  • The <#recurse> directive was broken. It did not work with a using clause. This is now fixed.