Release date: 2017-11-03
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.
Changes on the FTL side
-
New directive:
continue
(sf.net #79, FREEMARKER-37). This can be used inside thelist
directive to skip to the next iteration (similarly as in Java). See more... -
Added alternative syntaxes for the
&&
(logical "and") operator:\and
and&&
. These are to work around issues in applications where the template must be valid XML (&&
is not valid XML/HTML, at most places), or where the template entered is stored after XML or HTML escaping. Note that lonely&
, andand
without\
is not recognized for backward compatibility. -
New built-in,
sequence
(FREEMARKER-73). This can be used to work around situations where a listable value lacks some features that you need in the template (like it can't be listed twice, it can't tell its size, etc.), and you can't modify the data-model to fix the problem. See more... -
Bug fixed (FREEMARKER-70): The usage of loop variable built-ins, like
loopVar?index
, was disallowed by the parser inside interpolations that are inside a string literal expression (as in<#list 1..3 as loopVar>${'${loopVar?index}'}</#list>
), saying that there's no loop variable in scope withloopVar
name. -
Bug fixed: Comments were not allowed by the parser between the
switch
tag and the firstcase
tag. -
Bug fixed (FREEMARKER-71): When using
exp?eval
, if the expression inside the evaluated string throws an exception, the cause exception of that exception was lost.
Changes on the Java side
-
Added new configuration setting (FREEMARKER-48),
wrap_unchecked_exceptions
(Configurable.setWrapUncheckedExceptions(boolean)
). When this istrue
, unchecked exceptions thrown during evaluating an expression or during executing a custom directive will be wrapped into aTemplateException
-s. The advantage of that is that thus the exception will include the location in the template (not just the Java stack trace), and theTemplateExceptionHandler
will be invoked for it as well. When this setting isfalse
(which is the default for backward compatibility), the the unchecked exception will bubble up and thrown byTemplate.process
, just as in earlier versions. (Note that plain Java methods called from templates have always wrapped the thrown exception intoTemplateException
, regardless of this setting.) -
Added new configuration setting,
attempt_exception_reporter
(Configurable.setAttemptExceptionReporter(AttemptExceptionReporter)
), to allow the customization of how the exceptions handled (and thus suppressed) by theattempt
directive are reported. The defaultAttemptExceptionReporter
logs the exception as an error, just as it was in earlier versions, though now the error message will indicate that the exception was thrown inside anattempt
directive block. -
Added new
BeansWrapper
setting,preferIndexedReadMethod
. This was added to address a Java 8 compatibility problem; see the bug fix entry below for more information. -
When
incomplatible_improvements
is set to 2.3.27 (or higher), the following unchecked exceptions (but not their subclasses) will be wrapped intoTemplateException
-s when thrown during evaluating expressions or calling directives:NullPointerException
,ClassCastException
,IndexOutOfBoundsException
, andInvocationTargetException
. The goal of this is the same as of setting thewrap_unchecked_exceptions
setting totrue
(see that earlier), but this is more backward compatible, as it avoids wrapping unchecked exceptions that some application is likely to catch specifically (like application-specific unchecked exceptions). (This is related to FREEMARKER-48.) -
Bug fixed: Starting from Java 8, when the same JavaBeans property has both non-indexed read method (like
String[] getFoos()
) and indexed read method (likeString getFoos(int index)
),BeansWrapper
andDefaultObjectWrapper
have mistakenly used the indexed read method to access the property. This is a problem because then the array size was unknown, and thus the property has suddenly become unlistable on Java 8 (that is,<#list myObject.foos as foo>
fails). To enable the fix (where it will use the non-indexed read method), you should increase the value of theincompatibleImprovements
constructor argument of the usedDefaultObjectWrapper
orBeansWrapper
to 2.3.27. Note that if you leave theobject_wrapper
setting of theConfiguration
on its default, it's enough to increase theincompatibleImprovements
setting of theConfiguration
to 2.3.27, as that's inherited by the defaultobject_wrapper
. In case increasing theincompatibleImprovements
is not an option (because of the other changes it brings), you can instead set thepreferIndexedReadMethod
property of the object wrapper tofalse
. Note that this bug haven't surfaced before Java 8, as thenjava.beans.Inrospector
has only exposed the non-indexed method when both kind of read method was present. -
Bug fixed (affects Java 8 and later): Regardless of the value of the
preferIndexedReadMethod
setting (see previous point), if one of the indexed read method and the non-indexed read method is inaccessible (i.e., it's declared in a non-public type, and wasn't inherited by a public type), while the other read method is accessible, we will use the accessible one. Earlier, if there was an indexed read method but it was inaccessible, we have given up, and that bean property wasn't visible. Such properties will now be visible again, just as before Java 8. (Before Java 8java.beans.Inrospector
has only exposed the non-indexed read method in this case, so we didn't have this problem.) -
Bug fixed: On OpenJDK 9 (but not on earlier versions, nor on Oracle Java 9 (tested with "build 9+181")), when you try to use the DOM-based XML support (
freemarker.ext.dom.NodeModel
), unless you happen to have Apache Xalan in the class path, theNodeModel
constructor will fail withIllegalAccessError
because "java.xml does not export com.sun.org.apache.xml.internal.utils". Note that while the exception is not thrown anymore in 2.3.27, FreeMarker can't use the XPath support included in OpenJDK 9, and so templates that try to use XPath expressions (likedoc['//foo']
) will still fail, unless 3rd party XPath support is present. -
Bug fixed: When the
TemplateExceptionHandler
suppresses (i.e., doesn't re-throw) an exception, theattempt
directive won't log it anymore. (To be precise, theAttemptExceptionReporter
won't be invoked for it anymore; the default one logs as error.) -
Bug fixed (part of FREEMARKER-48): When an arithmetic exception has occurred in an expression (typically division by zero), the template processing has thrown the
ArithmeticException
as is, without packaging it into aTemplateException
. Thus, the error location in the template wasn't visible in the exception. -
When logging error due to an error in an
attempt
directive block, the log message now indicates that the error was inside anattempt
block. -
Bug fixed (FREEMARKER-52): When setting the
output_format
fromProperties
or thesetSetting(String, String)
API, theXHTMLOutputFormat
abbreviation wasn't recognized (for example in a.properties
file,output_format=XHTMLOutputFormat
didn't work, onlyoutput_format=freemarker.core.XHTMLOutputFormat()
did). -
Bug fixed: When setting the
new_builtin_resolver
fromProperties
or thesetSetting(String, String)
API, it didn't recognize the camel case form of theallowed_classes
andtrusted_templates
keywords, and throw exception for them. NowallowedClasses
andtrustedTemplates
can be used as well. -
Bug fixed: JSP support haven't tried using the thread context class-loader to load the TLD, instead, it has only used the defining class loader of the FreeMarker classes. This can cause problem in the rare case where
freemarker.jar
is installed on higher scope than the web application (like on the Servlet container level), but the web application contains the TLD. -
Constants.EMPTY_HASH
andGeneralPurposeNothing
(the value ofmissingVar!
) now implementsTemplateHashModelEx2
. Earlier they were only aTemplateHashModelEx
-s. -
Added
Constants.EMPTY_KEY_VALUE_PAIR_ITERATOR
-
Somewhat less synchronization when accessing JavaBean properties (FREEMARKER-80). The problem was that the
java.beans.PropertyDescriptor.getReadMethod
method is synchronized, andfreemarer.ext.beans.BeanModel
has called it each time a property was read. Now that method is only called when the class is first introspected. -
Improved/fixed
TemplateTransformModel
behavior (this is a legacy interface that's not used much in user code):-
Writer TemplateTransformModel.getWriter(Writer out, Map args)
can now return theout
parameter as is, as FreeMarker now recognizes that it's the same object and so won't callclose()
on it after the end tag. -
When
incomplatible_improvements
is set to 2.3.27 (or higher), and the returnedWriter
implementsTransformControl
, exceptions that are used internally for flow control (for<#return>
,<#break>
, etc.) won't be passed toTransformControl.onError(Throwable)
anymore. Earlier, ifonError
didn't rethrow the exception (though almost all implementation does), you couldn't use said directives inside the transformed block.
-
-
Added workaround against "IllegalStateException: zip file closed" and "ZipException: ZipFile closed" issues (caused by bugs outside of FreeMarker) when loading resources included in the FreeMarker jar (see
freemarker.template.utility.ClassUtil.loadProperties
).