Release date: 2018-04-04
Changes on the FTL side
-
Added new special variable,
get_optional_template(FREEMARKER-84). It can be used when you need to include or import a template that's possibly missing, and you need to handle that case on some special way. See the details here... -
Added new special variable,
caller_template_name(FREEMARKER-83), which returns the name (path) of the template from which the current macro or function was called. It's mostly useful if you want to resolve paths relative to the caller template. -
Added new built-in,
templateName?absolute_template_nameortemplateName?absolute_template_name(baseName), which can be used to convert a relative template name to an absolute template name. See more here... -
Added new built-ins:
sequence?minandsequence?max(FREEMARKER-86), which return the smallest and greatest item from a list of numbers or date/time/date-times. See more here... -
The template language can now be configured to use
[=expression]instead of${expression}and#{expression}, which is very useful if you have a lot of${...}or#{...}in the text that you are generating, and so they should be static text. See more about the square bracket interpolation syntax here. The template language can also be configured to only use${expression}, and treat#{expression}as static text. (See theinterpolation_syntaxconfiguration setting, or theConfiguration.setInterpolationSyntax(int)method.) -
In string literals,
\=is now a valid escape sequence, resulting in a=. This is useful when you are using the new[=exp]interpolation syntax, which can be escaped in a string literal like"Literal [\=x]". -
Bug fixed (FREEMARKER-83); this fix is only active when
incomplatible_improvementsis set to 2.3.28 (or higher). When calling a macro or function (things defined in a template, not directly in Java) and the argument list contains.current_template_name, now it will correctly evaluate to the template that contains the call, rather than to the template that contains the macro or function definition. (Of course, the parameter default value expression is still evaluated in the context of the called macro or function.) -
Bug fixed: When
string?split(separator)is called with""as the argument, the string will be split to characters now. Earlier it has thrown anIllegalArgumentException(unless therflag was specified).
Changes on the Java side
-
Added new
ParserConfiguration(such asConfigurationandTemplateConfiguration) setting,interpolation_syntax. It has 3 possible values:-
legacy(the default): Interpolations look like${...}or#{...}. Note that#{...}is deprecated for a long time now. -
dollar: Interpolations look like${...}. With this syntax,#{...}will be just static text. -
square_bracket: Interpolations look like[=...]. With this syntax${...}and#{...}will be just static text. So it's useful if you generate output in a format where those (typically${...}) are already used, such as to generate JSP pages, or to generate FreeMarker templates that use the default syntax.
-
-
When specifying the
output_formatconfiguration setting withString-Stringkey-value pairs (like withConfiguration.setSetting(String, String)or in a.propertiesfile), it's now possible to specify the standard output formats by short name (likeoutput_format=HTML) rather than by class name. (Custom formats still has to be referred by class name, as FreeMarker can't discover what their names are, since it's not aware of the custom classes.) -
Added a new
Configuration.removeTemplateFromCacheoverload that has aObject customLookupConditionparameter. This is useful to manually evacuate a template from the cache that was get with a non-nullcustom lookup condition. -
Added new property to
BeansWrapper.MethodAppearanceDecision:replaceExistingProperty. This is useful when a method likesize()is exposed as a JavaBean property viaMethodAppearanceDecision.exposeAsProperty, but there's also a "real" JavaBean property (likegetSize()) with identical name. By default the real property isn't replaced, but now withreplaceExistingPropertyit can be. -
DirectiveCallPlacenow has aTemplate getTemplate()method, so you can query if from which template was yourTemplateDirectiveModelcalled. (This has similar role as.caller_template_namefor macros/functions.) -
Added
Environment.rootBasedToAbsoluteTemplateName(String), which converts the root based names typically used for the FreeMarker Java API-s (such asConfiguration.getTemplate(name)) to an absolute path, which can be safely passed to<#include path>and such, as it won't be misinterpreted to be relative to the directory of the template. -
Fixes in exception handling when calling JSP tags:
-
Bug fixed (FREEMARKER-88): If a
TemplateExceptionthat's not aTemplateModelExceptoinhas occurred in the body (nested content) of a JSPSimpleTag(typically, anInvalidReferenceException), that has caused aClassCastExceptionin the exception handling code, thus the template processing has thrown that instead of the original exception. -
Bug fixed: For JSP Tag based custom tags, if an exception has occurred in the body (nested content), an
IndexOutOfBoundsExceptionmight have occurred, replacing the original exception. -
Wrapping of non-
TemplateModelExceptionTemplateException-s (typicallyInvalidReferenceException-s) intoTemplateModelException-s is now avoided when theTemplateExceptionoccurs in the body of a JSP tag.
-
-
The default arithmetic engine (
ArithmeticEngine.BIGDECIMAL_ENGINE) can now compare infinite (both positive and negative) to any other standard numerical type. Earlier, sinceBigDecimalcan't represent infinite, it was only working in certain special cases. Also there were some performance optimizations to slightly decrease the impact and number of conversions toBigDecimal. -
Avoided possible performance bottleneck when executing templates on many threads, caused by that
java.beans.PropertyDescriptor.getReadMethod()is synchronized (FREEMARKER-80). -
Added
TemplateModelUtils.getKeyValuePairIterator(TemplateHashModelEx)static utility class, which can be used to get aTemplateHashModelEx2.KeyValuePairIteratoreven for a non-TemplateHashModelEx2object. This simplifies Java code that iterates through key-value pairs. -
freemarker.template.utility.DeepUnwrap(a rarely used utility) now utilizes when the unwrappedTemplateModelimplementsTemplateHashModelEx2.getKeyValuePairIterator(), and thus can unwrap such a hash value even if it has non-string keys. Also, it nows keeps the iteration order of the hashes, as it unwraps into aLinkedHashMapinstead of into a plainHashMap. -
freemarker.ext.beans.HashAdapter.size()was overridden for better performance. -
When the
incompatible_improvementssetting is set to 2.3.28 (or greater): Fixed legacy parser glitch where a tag can be closed with an illegal](when it's not part of an expression) despite that the tag syntax is set to angle brackets. For example<#if x]worked just like<#if x>. Note that this legacy glitch didn't affect the legal usage of], like<#if x[0]>has always worked correctly. -
Fixed parser bug that disallowed using
>as the top-level expression inside an interpolation (${...}). It had the same reason why<#if x > y>doesn't work as naively expected, but there's no real ambiguity in${x > y}, so now it's allowed. Note that${(x > y)?c}and${(x > y)?string('y', 'n')}, which are how booleans are commonly printed, have always worked, as the>operation is not on the top-level inside the interpolation. -
Fixed incorrect listing of valid
roundingMode-s in extended Java decimal format parsing error message
Other changes
-
FreeMarker has graduated from the Apache Incubator (as of 2018-03-21), and now is a normal top-level project at Apache. Therefore, the version number doesn't contain "-incubating" anymore.
