2.3.27 (incubating at Apache) - Apache FreeMarker Manual

Unsupported web browser - Use a modern browser to view this website!

- Home
- Manual
- Java API

- Contribute
- Report a Bug
- Download

Manual
Previous Next

# 2.3.27 (incubating at Apache)

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 the `list` directive to skip to the next iteration (similarly as in Java). See more...

- Added alternative syntaxes for the `&&` (logical "and") operator: `\and` and `&amp;&amp;`. 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 `&amp;`, and `and` 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 with `loopVar` name.

- Bug fixed: Comments were not allowed by the parser between the `switch` tag and the first `case` 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 is `true`, unchecked exceptions thrown during evaluating an expression or during executing a custom directive will be wrapped into a `TemplateException`-s. The advantage of that is that thus the exception will include the location in the template (not just the Java stack trace), and the `TemplateExceptionHandler` will be invoked for it as well. When this setting is `false` (which is the default for backward compatibility), the the unchecked exception will bubble up and thrown by `Template.process`, just as in earlier versions. (Note that plain Java methods called from templates have always wrapped the thrown exception into `TemplateException`, 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 the `attempt` directive are reported. The default `AttemptExceptionReporter` 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 an `attempt` 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 into `TemplateException`-s when thrown during evaluating expressions or calling directives: `NullPointerException`, `ClassCastException`, `IndexOutOfBoundsException`, and `InvocationTargetException`. The goal of this is the same as of setting the `wrap_unchecked_exceptions` setting to `true` (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 (like `String getFoos(int index)`), `BeansWrapper` and `DefaultObjectWrapper` 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 the `incompatibleImprovements` constructor argument of the used `DefaultObjectWrapper` or `BeansWrapper` to 2.3.27. Note that if you leave the `object_wrapper` setting of the `Configuration` on its default, it's enough to increase the `incompatibleImprovements` setting of the `Configuration` to 2.3.27, as that's inherited by the default `object_wrapper`. In case increasing the `incompatibleImprovements` is not an option (because of the other changes it brings), you can instead set the `preferIndexedReadMethod` property of the object wrapper to `false`. Note that this bug haven't surfaced before Java 8, as then `java.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 8 `java.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, the `NodeModel` constructor will fail with `IllegalAccessError` 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 (like `doc['//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, the `attempt` directive won't log it anymore. (To be precise, the `AttemptExceptionReporter` 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 a `TemplateException`. 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 an `attempt` block.

- Bug fixed (FREEMARKER-52): When setting the `output_format` from `Properties` or the `setSetting(String, String)` API, the `XHTMLOutputFormat` abbreviation wasn't recognized (for example in a `.properties` file, `output_format=XHTMLOutputFormat` didn't work, only `output_format=freemarker.core.XHTMLOutputFormat()` did).

- Bug fixed: When setting the `new_builtin_resolver` from `Properties` or the `setSetting(String, String)` API, it didn't recognize the camel case form of the `allowed_classes` and `trusted_templates` keywords, and throw exception for them. Now `allowedClasses` and `trustedTemplates` 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` and `GeneralPurposeNothing` (the value of `missingVar!`) now implements `TemplateHashModelEx2`. Earlier they were only a `TemplateHashModelEx`-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, and `freemarer.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 the `out` parameter as is, as FreeMarker now recognizes that it's the same object and so won't call `close()` on it after the end tag.

  - When `incomplatible_improvements` is set to 2.3.27 (or higher), and the returned `Writer` implements `TransformControl`, exceptions that are used internally for flow control (for `<#return>`, `<#break>`, etc.) won't be passed to `TransformControl.onError(Throwable)` anymore. Earlier, if `onError` 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`).

Previous Next