2.3.24 (incubating at Apache)

Release date: 2016-03-28

This is a stable, final release. The "incubating" suffix is required by the Apache Software Foundation until the project becomes a fully accepted (graduated) Apache project. See disclaimer below.

Legal changes

The owner of FreeMarker is now the Apache Software Foundation. The license is still Apache License Version 2.0, just like earlier, but the owner is different. The official full product name has changed to Apache FreeMarker.

Changes on the FTL side

  • The most important new feature of this release is the auto-escaping and output formats mechanism, which deprecates escaping with the escape directive. These are the changes related to this new mechanism (see earlier link for a guide):

    • New ftl header options, ouput_format and auto_esc to override the output_format and auto_escaping settings of the template, like <#ftl output_format='HTML' auto_esc=false>.

    • New built-in: no_esc. Used to prevent auto-escaping, like ${descriptionInHtml?no_esc}. This doesn't work with <#escape ...>, only with the new auto-escaping mechanism.

    • New FTL type, "markup output". This is somewhat similar to string, but values of this type aren't auto-escaped by the new escaping mechanism, because they are known to already hold markup. (For example, ?esc and ?no_esc returns a value of this type, hence their results are protected from double-escaping problems.)

    • New built-in: esc. Used for escaping with the current output format when auto-escaping is disabled.

    • New built-in: markup_string. This returns the markup of a markup output value as string.

    • New built-in: is_markup_output, returns true if the value is of type "markup output".

    • New directive: outputformat, used to change the output format for a section of a template, like <#outputformat "XML">...</#outputformat>

    • New directives: noautoesc and autoesc, used to turn auto-escaping off and on for a section of a template, like <#noautoesc>...</#noautoesc>.

    • New built-in variable, .output_format, returns the current output format at the place of invocation.

    • New built-in variable, .auto_esc, returns the boolean that tells if auto-escaping is active at the place of invocation.

    • Block assignments, like <#assign captured>...</#assign>, when the current output_format is some kind of markup (like HTML), will store the captured output not with string type, but with "markup output" type. Thus ${captured} will not get unwanted escaping.

    • The + operator (concatenation) works with the new "markup output" type as well. Like someMarkup + somePlainText will result in markup where somePlainText is escaped automatically before it's appended to the markup.

    • The has_content built-in now supports "markup output" values, considering 0 length markup as empty.

  • You can now define custom number and date/time/datetime formatters. These are defined by the programmers (and thus can implement any kind of exotic formatting rules) when configuring FreeMarker, and can be referred with strings starting with "@", like in <#setting number_format='@foo'>, or ${n?string.@foo_params}, <#setting number_format='@foo params'>, or ${n?string.@foo}, ${n?string.@foo_params}. For backward compatibility, the initial @ only has this special meaning if either you have any custom formats or the incompatible_improvements setting is at lest 2.3.24.

  • Everywhere where Java DecimalFormat patterns are used (like in ?string('0.##') or <#setting number_format="0.##">), now it's possible to specify options like rounding mode or the symbols used, with a FreeMarker-specific extension to the DecimalFormat pattern syntax.

  • Added new special variable: .incompatible_improvements, which returns the incompatible_improvements setting of the current FreeMarker configuration, as a string.

  • ?date, ?time and ?datetime now can be called as 0 argument method, like ?date(), etc., which returns the exact object that TemplateDateFormat.parse returns, instead of the tricky multi-type object that just using ?date returns. Because custom TemplateDateFormat implementations may return custom TemplateDateModel implementations, keeping the exact class can be important in some applications.

  • <@ and </@ is now allowed in string literals that contain ${exp}, and will be part of the literal as is. Earlier it was a syntactical error.

  • Bug fixed: With incompatible_improvements set to 2.3.24 (see how here...), m?is_sequence doesn't return true for Java methods wrapped by BeansWrapper and its subclasses (most notably DefaultObjectWrapper) anymore, as they only implement the [index] operator, but not ?size, which causes <#list ...> to fail, among others.

Changes on the Java side

  • Attention! FreeMarker now requires at least Java 1.5 (aka. Java 5). 2.3.24 has only required Java 1.4. (Reason: Without this, new public API-s couldn't use generics, which affect negatively the majority of users, while old installations that are still using 1.4 are unlikely to update FreeMarker anyway.)

  • Attention! FreeMarker's JSP support (if it's used) now requires at least JSP 2.0. Earlier it only required JSP 1.1. (Reason: The jsp-api dependency for JSP 1.x, which was needed for building, can't be legally present in the Maven Central Repository, nor be provided by freemarker.org.)

  • Added new configuration setting: template_configurations. This allows overriding the settings coming from the shared Configuration object for individual templates, based on template name patterns. See more here...

  • Related to the new auto-escaping mechanism:

    • As FTL has now a new type, "markup output", there's also a corresponding new model interface, TemplateMarkupOutputModel. This also means that you can prevent the auto-escaping of values coming from the data-model by returning a TemplateMarkupOutputModel instead of a String. Like the template author can just write ${messages.foo}, and it will be auto-escaped or not depending on if the message is known to be markup or not.

    • Added new configuration setting: recognize_standard_file_extensions. When true, templates whose source name ends with ".ftlh" will get HTML output_format, and those whose name ends with ".ftlx" get XML output_format, in both cases with auto-escaping on. If the incompatible_improvements setting is set to 2.3.24 (or higher) then this setting defaults to true. Otherwise it's default is false, but enabling it is highly recommended.

    • Added new configuration setting: output_format. This specifies the output format object to use (such as HTMLOutputFormat.INSTANCE, XMLOutputFormat.INSTANCE, etc.) that governs auto-escaping. The output format can be different for different templates, using the template_configurations setting (see here how...).

    • Added new configuration setting: registered_custom_output_formats. With this you can add new OutputFormat-s that templates can refer to by name (like in <#ftl output_format="foo">).

    • Added new configuration setting: auto_escaping_policy. This decides when auto-escaping should be enabled depending on the current output format.

  • Changes related to the custom number and date/time/datetime formating feature:

    • Added new classes for implementing custom formatters: freemarker.core.TemplateNumberFormat, TemplateNumberFormatFactory, TemplateDateFormat, TemplateDateFormatFactory, also the exceptions these can throw. These allow implementing any kind of formatting rule that's doable in Java (i.e., they aren't restricted to any java.text formatters). Furthermore these formatters get the TemplateModel instead of a the bare java.lang.Number or java.util.Date, which lets you use the extra application-specific meta information that you may pack into the TemplateModel-s, such as physical unit, preferred precision, and so on.

    • Added custom_number_formats and custom_date_formats settings (Configurable.setCustomNumberFormats(Map<String, TemplateNumberFormatFactory>) and Configurable.setCustomDateFormats(Map<String, TemplateDateFormatFactory>)) with which you can register your own formats. These formats can be referred from everywhere where you can use a string to define a format, with a format string like "@foo" or "@foo params", where "foo" is the key in the Map<String, ...> parameter of the earlier shown methods, and the parameters (if any) are interpreted by the TemplateXxxFormatFactory implementation that you provide. Like, you can issue cfg.setNumberFormat("@foo params"), or <#setting number_format='@foo params'>, or ${n?string.@foo_params}, similarly as you can issue cfg.setNumberFormat("0.##"), etc. For backward compatibility, the initial @ only has this special meaning if either you have any custom formats or the incompatible_improvements setting is at least 2.3.24. Note that the custom_number_formats and custom_date_formats settings can be set per-template (via the new template_configurations settings) or per-Environment too, thus @foo can mean something different in different templates.

    • Added new Environment methods returning TemplateNumberFormat and TemplateDateFormat objects. See the getTemplateNumberFormat(...) and getTemplateDateFormat(...) variations in the API.

    • Added freemarker.core.AliasTemplateNumberFormatFactory and AliasTemplateDateFormatFactory, which can be used to create custom formats that are aliases to other formats. For example, instead of writing ${n?string["0.00"]} again and again, you can define the custom format "price" as the alias to the format string "0.00" in the configuration, and then use ${n?string.@price}. Thus, you can control at a central place how prices look. Furthermore, the alias can chose a different target format string depending on the current locale; this is especially useful for dates, where conventions can significantly differ in different countries.

    • It's now possible to have HTML or other markup in number and date/time/datetime formatting results, like 1.23*10<sup>6</sup>, which won't be accidentally auto-escaped, as FreeMarker knows that it's already HTML. This is done by returning a TemplateMarkupOutputModel instead of a String; see the new auto-escaping mechanism earlier. Note that no out-of-the-box format utilizes this (at the moment), but you could write such custom format.

    • The internal format object caching architecture has been reworked, so that it can handle custom formats too. This reworking also fixes some bottlenecks under highly concurrent load, and some (otherwise unlikely) memory leak possibilities.

  • In the number_format configuration setting, when it holds a Java DecimalFormat pattern (like "0.##"), it's now possible to specify options like rounding mode or the symbols used, with a FreeMarker-specific extension to the pattern syntax.

  • New FreemarkerServlet init-params (see the FreemarkerSerlvet API documentation for details):

    • OverrideResponseContentType: Specifies when should we override the contentType that's already set (i.e., non-null) in the HttpServletResponse. Earlier, we have always set it, and that's still the default behavior. But now that this init-param exists, you can change that behavior, so that the contentType you have specified before forwarding to FreemarkerServlet matters.

    • OverrideResponseLocale: Specifies if we should override the locale that's already set (i.e., non-null) in the HttpServletResponse. Earlier, we have always set it, but now this behavior can be changed so that we only set it if it wasn't already set.

    • ResponseCharacterEncoding: Deprecates the old (and quirky) logic of specifying the output charset, which is putting it into the ContentType init-param after the MIME type, otherwise falling back to the template file charset. The possible values are legacy (the default for backward compatibility), fromTemplate (which is legacy without quirks, and is aware of the outputEncoding setting), doNotSet (keeps what the caller has already set in the ServletRespone) and force followed by a charset name (forces a specific output charset).

  • Added freemarker.cache.ByteArrayTemplateLoader, which is similar to StringTemplateLoader, but stores the templates as byte[]-s instead of as String-s.

  • Upgraded JavaCC (used during build to generate the FTL parser) from 3.2 to 6.1.2.

  • Added Configurable.getSettingNames(boolean camelCase), which returns the set of valid setting names. This can be useful for auto-completion and such.

  • Fixes and improvements in the "object builder" mini-language used for configuring FreeMarker from java.util.Properties or other string-only sources (not used in templates). This is not to be confused with the template language syntax, which has nothing to do with the "object builder" syntax we are writing about here. The improvements are:

    • Bug fixed: For nested builder expressions, the top-level result class restriction were applied accidentally.

    • When resolving an expression like com.example.Foo(), if there's a builder class (com.example.FooBuilder), the non-builder class (com.example.Foo) need not exist anymore. After all, FooBuilder.build() instantiates from any class it wants to anyway.

    • TimeZone objects can be created like TimeZone("UTC"), despite that there's no a such constructor.

    • Added support for creating lists with [ item1, item2, ... itemN ] syntax.

    • Added support for creating maps with { key1: value1, key2: value2, ... keyN: valueN } syntax.

    • A number without decimal point will now be parsed to Integer, Long, or BigInteger, depending on the size of the number. Earlier all numbers were parsed to BigDecimal-s, but that had little importance before lists and maps were added, as the number was converted to the constructor or setter parameter type anyway.

    • Number literals can have Java type suffixes (f, d, l), plus bd for BigDecimal and bi for BigInteger.

    • Public static fields can be referred, like com.example.MyClass.MY_CONSTANT or Configuration.AUTO_DETECT_TAG_SYNTAX.

  • Decreased the stack usage of template execution, which can have importance if you have very very deeply nested templates.

  • Added MultiTemplateLoader.setSticky(boolean) and MultiTemplateLoader.isSticky(), with which you can disable the default behavior, where once a template was found in a child TemplateLoader, it will be searched there first next time (typically, when the template update delay is expired). With the sticky property set to false, the child TemplateLoader-s will be always searched in the order as they were added to the MultiTemplateLoader.

  • Added StringTemplateLoader.removeTemplate(String) method.

  • Bug fixed, only with incompatible_improvements set to 2.3.24 (see how here...): Expressions inside interpolations that were inside string literal expressions (not ${...}-s in general), like in <#assign s="Hello ${name}!">, always used incompatibleImprovements 0 (2.3.0 in effect). This means that expressions inside string literals had missed the ?html, ?iso_..., ?is_enumerable, ?c, etc. fixes/improvements.

  • Bug fixed [439]: FileTemplateLoader with emulateCaseSensitiveFileSystem set to true (used for development) wasn't properly synchronized, leading to random NullPointerException-s or other misbehavior.

  • Bug fixed: It wasn't well defined when a Java Iterator counts as empty. Depending on what ObjectWrapper you are using, one of these fixes apply:

    • DefaultObjectWrapper (fix is always active): Operations on the Iterator that only check if it's empty without reading an element from it, such as ?has_content, won't cause a later iteration (or further emptiness check) to fail anymore. Earlier, in certain situations, the second operation has failed saying that the iterator "can be listed only once".

    • BeansWrapper (when it's not extended by DefaultObjectWrapper), if it's incompatibleImprovements property is set to 2.3.24 (or higher): Iterator-s were always said to be non-empty when using ?has_content and such (i.e., operators that check emptiness without reading any elements). Now an Iterator counts as empty exactly if it has no elements left. (Note that this bug has never affected basic functionality, like <#list ...>.)

  • Bug fixed: The (rarely used) cause exception of ParseException-s wasn't set

  • Bug fixed: When the incomaptible_improvements setting of an existing Configuration was changed, the template cache sometimes wasn't recreated, hence old templates could survive.

  • Bug fixed, with incompatible_improvements set to 2.3.24 (see how here...): The #import directive meant to copy the library variable into a global variable if it's executed in the main namespace, but that haven't happened when the imported template was already imported earlier in another namespace.

  • Fixes in the XML processing feature (freemarker.ext.dom):

    • Bug fixed: XPath queries that has only contained characters that are valid in XML element names and has also contained :: (which is valid in names in namespace-unware documents), like e['following-sibling::foo'], were interpreted as literal element names (giving 0 hits) rather than as XPath expressions. Note that there were no such problem with e['following-sibling::*'] for example, as it's not a valid XML element name according the XML specification. This fix can actually break applications that has processed namespace unaware XML that use :: as part of element or attribute names, but such an application is highly unlikely, unlike running into the fixed problem. (Unfortunately, using incompatible_improvements wasn't technically possible here.)

    • Bug fixed: The @@qname of elements that belong to the XML namespace declared as the default via <#ftl ns_prefixes={'D':'...', ... }> no longer starts with D:, instead they just start with no name space prefix.

    • Bug fixed: In the markup returned by the @@markup key, when there were multiple namespaces for which there was no prefix associated with via <#ftl ns_prefixes=...>, all those namespaces were assigned to the same auto-generated xmlns prefix (usually "a"). Now they will get "a", "b", "c", etc. prefixes.

  • JSP TLD loading now quotes the location of jar-s (and other zip-s) which can't be loaded due to zip format errors in the error message.

  • Added an overload to Configuration.getSupportedBuiltInNames and Configuration.getSupportedBuiltInDirectiveNames that has a namingConvention parameter. This is useful for tooling as since 2.3.23 we support both camel case naming convention (like s?upperCase) and the legacy one (like s?upper_case). Furthermore the old 0 argument overload will now utilize Configuration.getNamingConvention() to only return the relevant names if it's not AUTO_DETECT_NAMING_CONVENTION.

  • Internal reworking to simplify the AST (the TemplateElement structure). The related technically public API was marked as internal for a good while. For those who still use that API, the visible change is that TemplateElement-s now almost never has a MixedContent parent, instead, the parent is directly whatever element the child element indeed belongs under when you look at the source code (like the enclosing #list for example, while earlier you often had to go through a MixedContent first whose parent was the #list). Note that when you have moved downwards, i.e., towards the child elements, these MixedContent parents weren't visible and were silently skipped, so the tree traversal API was inconsistent. Now it's consistent.

  • Due to the above change again, the return type of freemarker.core.DebugBreak.accept() and freemarker.core.TextBlock.accept() has changed from void to TemplateElement[]. This again is highly unlikely to affect anyone, and these meant to be internal API-s anyway, but as these two accept methods has wider than package visibility for historical reasons, we mention this change.

  • The non-public AST API of freemarker.core.StringLiteral-s has been changed. In principle it doesn't mater as it isn't a public API, but some might used these regardless to introspect templates. Earlier it had an "embedded template" parameter inside, now it has 0 (for purely static string literals), one or more "value part"-s, which are String-s and Interpolation-s.

  • Internal code cleanup: Mostly for consistent source code formatting, also many parser construction/setup cleanup

  • Source code changes to conform to Apache source release policy, such as adding copyright headers and getting rid of test jar-s committed into the source code. Eclipse project files were also removed, instead the README describes how to set up the project.

  • Build script and distribution artifact changes to conform to Apache release policy, most notably it produces separate source and binary releases.

Changes compared to 2.3.24 Release Candidate 1

  • Added MultiTemplateLoader.setSticky(boolean) and MultiTemplateLoader.isSticky(), with which you can disable the default behavior, where once a template was found in a child TemplateLoader, it will be searched there first next time (typically, when the template update delay is expired). With the sticky property set to false, the child TemplateLoader-s will be always searched in the order as they were added to the MultiTemplateLoader.

  • Added StringTemplateLoader.removeTemplate(String) method.

  • Source code changes to conform to Apache release policy and recommendations:

    • No more binary test jar-s committed into the source code (instead, they are generated on-the-fly)

    • Eclipse project files were removed, instead, the README describes how to set up the project.