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
andauto_esc
to override theoutput_format
andauto_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
, returnstrue
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
andautoesc
, 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 currentoutput_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. LikesomeMarkup + somePlainText
will result in markup wheresomePlainText
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 theincompatible_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 theDecimalFormat
pattern syntax. -
Added new special variable:
.incompatible_improvements
, which returns theincompatible_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 thatTemplateDateFormat.parse
returns, instead of the tricky multi-type object that just using?date
returns. Because customTemplateDateFormat
implementations may return customTemplateDateModel
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 returntrue
for Java methods wrapped byBeansWrapper
and its subclasses (most notablyDefaultObjectWrapper
) 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 sharedConfiguration
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 aTemplateMarkupOutputModel
instead of aString
. 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
. Whentrue
, templates whose source name ends with".ftlh"
will getHTML
output_format
, and those whose name ends with".ftlx"
getXML
output_format
, in both cases with auto-escaping on. If theincompatible_improvements
setting is set to 2.3.24 (or higher) then this setting defaults totrue
. Otherwise it's default isfalse
, but enabling it is highly recommended. -
Added new configuration setting:
output_format
. This specifies the output format object to use (such asHTMLOutputFormat.INSTANCE
,XMLOutputFormat.INSTANCE
, etc.) that governs auto-escaping. The output format can be different for different templates, using thetemplate_configurations
setting (see here how...). -
Added new configuration setting:
registered_custom_output_formats
. With this you can add newOutputFormat
-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 anyjava.text
formatters). Furthermore these formatters get theTemplateModel
instead of a the barejava.lang.Number
orjava.util.Date
, which lets you use the extra application-specific meta information that you may pack into theTemplateModel
-s, such as physical unit, preferred precision, and so on. -
Added
custom_number_formats
andcustom_date_formats
settings (Configurable.setCustomNumberFormats(Map<String, TemplateNumberFormatFactory>)
andConfigurable.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 theMap<String, ...>
parameter of the earlier shown methods, and the parameters (if any) are interpreted by theTemplateXxxFormatFactory
implementation that you provide. Like, you can issuecfg.setNumberFormat("@foo params")
, or<#setting number_format='@foo params'>
, or${n?string.@foo_params}
, similarly as you can issuecfg.setNumberFormat("0.##")
, etc. For backward compatibility, the initial@
only has this special meaning if either you have any custom formats or theincompatible_improvements
setting is at least 2.3.24. Note that thecustom_number_formats
andcustom_date_formats
settings can be set per-template (via the newtemplate_configurations
settings) or per-Environment
too, thus@foo
can mean something different in different templates. -
Added new
Environment
methods returningTemplateNumberFormat
andTemplateDateFormat
objects. See thegetTemplateNumberFormat(...)
andgetTemplateDateFormat(...)
variations in the API. -
Added
freemarker.core.AliasTemplateNumberFormatFactory
andAliasTemplateDateFormatFactory
, 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 aTemplateMarkupOutputModel
instead of aString
; 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 JavaDecimalFormat
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 theFreemarkerSerlvet
API documentation for details):-
OverrideResponseContentType
: Specifies when should we override thecontentType
that's already set (i.e., non-null
) in theHttpServletResponse
. 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 thecontentType
you have specified before forwarding toFreemarkerServlet
matters. -
OverrideResponseLocale
: Specifies if we should override thelocale
that's already set (i.e., non-null
) in theHttpServletResponse
. 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 theContentType
init-param after the MIME type, otherwise falling back to the template file charset. The possible values arelegacy
(the default for backward compatibility),fromTemplate
(which islegacy
without quirks, and is aware of theoutputEncoding
setting),doNotSet
(keeps what the caller has already set in theServletRespone
) andforce
followed by a charset name (forces a specific output charset).
-
-
Added
freemarker.cache.ByteArrayTemplateLoader
, which is similar toStringTemplateLoader
, but stores the templates asbyte[]
-s instead of asString
-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 likeTimeZone("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
, orBigInteger
, depending on the size of the number. Earlier all numbers were parsed toBigDecimal
-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
), plusbd
forBigDecimal
andbi
forBigInteger
. -
Public static fields can be referred, like
com.example.MyClass.MY_CONSTANT
orConfiguration.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)
andMultiTemplateLoader.isSticky()
, with which you can disable the default behavior, where once a template was found in a childTemplateLoader
, it will be searched there first next time (typically, when the template update delay is expired). With thesticky
property set tofalse
, the childTemplateLoader
-s will be always searched in the order as they were added to theMultiTemplateLoader
. -
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 usedincompatibleImprovements
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
withemulateCaseSensitiveFileSystem
set totrue
(used for development) wasn't properly synchronized, leading to randomNullPointerException
-s or other misbehavior. -
Bug fixed: It wasn't well defined when a Java
Iterator
counts as empty. Depending on whatObjectWrapper
you are using, one of these fixes apply:-
DefaultObjectWrapper
(fix is always active): Operations on theIterator
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 byDefaultObjectWrapper
), if it'sincompatibleImprovements
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 anIterator
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 existingConfiguration
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), likee['following-sibling::foo']
, were interpreted as literal element names (giving 0 hits) rather than as XPath expressions. Note that there were no such problem withe['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, usingincompatible_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 withD:
, 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-generatedxmlns
prefix (usually "a"). Now they will get "a", "b", "c", etc. prefixes.
-
-
JSP TLD loading now quotes the location of
jar
-s (and otherzip
-s) which can't be loaded due to zip format errors in the error message. -
Added an overload to
Configuration.getSupportedBuiltInNames
andConfiguration.getSupportedBuiltInDirectiveNames
that has anamingConvention
parameter. This is useful for tooling as since 2.3.23 we support both camel case naming convention (likes?upperCase
) and the legacy one (likes?upper_case
). Furthermore the old 0 argument overload will now utilizeConfiguration.getNamingConvention()
to only return the relevant names if it's notAUTO_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 thatTemplateElement
-s now almost never has aMixedContent
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 aMixedContent
first whose parent was the#list
). Note that when you have moved downwards, i.e., towards the child elements, theseMixedContent
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()
andfreemarker.core.TextBlock.accept()
has changed fromvoid
toTemplateElement[]
. This again is highly unlikely to affect anyone, and these meant to be internal API-s anyway, but as these twoaccept
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 areString
-s andInterpolation
-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 theREADME
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)
andMultiTemplateLoader.isSticky()
, with which you can disable the default behavior, where once a template was found in a childTemplateLoader
, it will be searched there first next time (typically, when the template update delay is expired). With thesticky
property set tofalse
, the childTemplateLoader
-s will be always searched in the order as they were added to theMultiTemplateLoader
. -
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.
-