Release date: 2019-08-17
Changes on the FTL side
-
Added new built-ins:
?filter(predicate)
,?map(mapper)
,?take_while(predicate)
,?drop_while(predicate)
. These allow using lambda expressions, likeusers?filter(user -> user.superuser)
orusers?map(user -> user.name)
, or accept a function/method as parameter. Lambda expressions are also new in this release, but they can only be used in said built-ins, so they aren't like in Java for example, and also, unlike the similar Java methods, these built-ins aren't lazy in general, only in specific cases (see more here). The main goal of adding these built-ins was to allow conditionally skipping elements in thelist
directive without nestedif
-s that interfere with thesep
directive, and the loop variable built-ins (see examples here). -
Added new built-ins for truncating text.
string?truncate(length)
truncates the text to the given length, and by default adds[...]
at the end if truncation has happened. Truncation happens at word boundaries, unless the result is too short that way, in which case it falls back to truncation mid word. There's also?truncate_w
to force Word Boundary truncation, and?truncate_c
(for Character Boundary) that doesn't care about word boundaries. The truncation algorithm is pluggable in the FreeMarker configuration. See the reference for more details. -
?sequence
now collaborates withseq?size
,seq[index]
,seq[range]
, and with some other built-ins (filter
,map
,join
, etc.) to spare collecting all the elements into the memory when possible. For exampleanIterator?sequence[1]
will now just fetch the first 2 items, while earlier it has built a sequence that contains all the elements, only to get the 2nd element from that. Or,anIterator?sequence?size
will now just count the elements, without collecting them into the memory. See the reference for more details. -
Extended decimal format parameter "multiplier" was incorrectly written as "multipier". Now both words are recognized.
-
?min
and?max
will now immediately stop with error when applied on a right unbounded numerical range (like1..
), as that would run forever anyway.
Changes on the Java side
-
FREEMARKER-109: In JSP TLD-s, line breaks inside function parameter lists have caused
IllegalArgumentException
"Invalid function signature". -
FREEMARKER-104: More helpful log and error messages (especially, no
NullPointerException
cause exception logged during FreeMarker XPath support initialization) if no XPath implementation is available because Java 9 modules don't allow accessing the internal Xalan that's stored undercom.sun
packages. (The messages now recommend adding Apache Xalan or Jaxen as dependency if you need XPath support.) -
The
boolean_format
configuration setting now can be set to"c"
. Then${aBoolean}
will behave as${aBoolean?c}
. This should only be used if you are generating output for non-human (computer) consumption only. If your output has pieces for human audience too, it's still recommended to use${aBoolean?c}
wheretrue
/false
output is needed, and either not set theboolean_format
at all, or set it to something that's appropriate for everyday users (like"yes,no"
). -
New configuration setting,
fallback_on_null_loop_variable
: Specifies the behavior when reading a loop variable (likei
in<#list items as i>
, or in<@myMacro items; i>
) that'snull
(missing); iftrue
, FreeMarker will look for a variable with the same name in higher variable scopes, or iffalse
the variable will be simplynull
(missing). For backward compatibility the default istrue
. The recommended value for new projects isfalse
, as otherwise adding new variables to higher scopes (typically to the data-model) can unintentionally change the behavior of templates. -
If the result of
seq?size
is compared to an integer literal in a template, like inseq?size != 0
, orseq?size < 1
, and to decide the answer it's enough to know ifseq
is empty or not (i.e., the exact size isn't needed), andseq
implementsTemplateCollectionModelEx
, FreeMarker will callTemplateCollectionModelEx.isEmpty()
instead ofsize()
. Furthermore, ifseq
is the result of?filter
, or of a similar built-ins that can provide lazily generated result, it will do counting to figure out the size (rather than constructing the whole sequence in memory), and will limit how far it counts based on what literal the result of?size
is compared with. -
Added
TemplateModelUtils.wrapAsHashUnion(ObjectWrapper, List<?>)
andwrapAsHashUnion(ObjectWrapper, Object...)
, which is useful when you want to compose the data-model from multiple objects in a way so that their entries (Map
key-value pairs, bean properties, etc.) appear together on the top level of the data-model. -
HTMLOutputFormat
,XMLOutputFormat
,XHTMLOutputFormat
aren't final classes anymore, furthermoreXHTMLOutputFormat
now extendsXMLOutputFormat
. Same applies to the respectiveTemplateOutputModel
-s (TemplateHTMLOutputModel
is not final anymore, etc.). This allows defining new custom markup output format classes that will work with program logic that's only prepared for the standard markup output formats, becauseinstanceof SomeStandardOutputFromat
will returntrue
for them. -
When configuring FreeMarker with string values (like with a
.properties
file), in the settings that support the "object builder" syntax, now you can create aTemplateMarkupOutputModel
value with the newmarkup
function, likemarkup(HTMLOutputFormat(), "<p>Example</p>")
. -
BeansWrapper.clearClassIntrospecitonCache
was deprecated as there's a typo in the method name; useclearClassIntrospectionCache
instead.