2.3.30

Release date: 2020-02-16 + release process

Please note that with this version the minimum required Java version was increased from Java 5 to Java 7.

Changes on the FTL side

  • FREEMARKER-107: Added ?with_args(dynamicArguments) and ?with_args_last(dynamicArguments) to add parameters dynamically to directive (like macro), function and method calls. Actually, this built-in returns a directive or macro or function that has different parameter defaults. See more here...

  • FREEMARKER-107: Added new special variable, .args. This evaluates to a hash in macros, and to a sequence in functions, which contains all the arguments. This is useful for operations that act on all the arguments uniformly, like for example to pass the arguments to ?with_args(...).

  • Macro catch-all parameters (aka. varargs parameters), when capture arguments passed by name (as opposed to by position), now keep the original order of arguments. Earlier the order wasn't predictable.

  • Bug fixed: In <#escape placeholder as escExpression>, the placeholder wasn't substituted inside lambda expressions inside escExpression. Fortunately it's very unlikely that anyone wanted to use lambdas there (given the few built-ins that accept lambdas).

Changes on the Java side

  • The minimum required Java version was increased from Java 5 to Java 7.

  • FREEMARKER-124: Made the default filtering of class members more restrictive (when you are using BeansWrapper, or its subclasses like DefaultObjectWrapper). This is not strictly backward compatible, but unlikely to break any real-world applications; see src/main/resources/freemarker/ext/beans/DefaultMemberAccessPolicy-rules to see what was changed. This change was made for security reasons, but the default behavior will never be safe enough if untrusted users will edit templates; see in the FAQ. In the unlikely case this change breaks your application, then you can still use the old behavior by setting the memberAccessPolicy property of the object wrapper to LegacyDefaultMemberAccessPolicy.INSTANCE.

  • Added freemarker.ext.beans.MemberAccessPolicy interface, and the memberAccessPolicy property to BeansWrapper, and subclasses like DefaultObjectWrapper. This allows users to implement their own program logic to decide what members of classes will be exposed to the templates. See See the FreeMarker Java API documentation for more details.

  • Added freemarker.ext.beans.WhitelistMemberAccessPolicy, which is a MemberAccessPolicy for use cases where you want to allow editing templates to users who shouldn't have the same rights as the developers (the same rights as the Java application). Earlier, the only out of the box solution for that was SimpleObjectWrapper, but that's too restrictive for most applications where FreeMarker is used. WhitelistMemberAccessPolicy works with DefaultObjectWrapper (or any other BeansWrapper), allowing you to use all features of it, but it will only allow accessing members that were explicitly listed by the developers, or was annotated with @TemplateAccessible.

  • FREEMARKER-125: FreeMarker now picks up DecimalFormatSymbols provided by the DecimalFormatSymbolsProvider SPI. This is useful if you need to change the decimal format symbols provided for a locale by Java.

  • FREEMARKER-120: BeansWrapper (and it's subclasses like DefaultObjectWrapper) now has two protected methods that can be overridden to monitor the accessing of members: invokeMethod and readField.

  • Setting incompatibleImprovements to the instance returned by Configuration.getVersion() will now be logged as an error, but for backward compatibility it will still work. This applies to said setting of Configuration, DefaultObjectWrapper, and BeansWrapper. The typical bad pattern is this: new Configuration(Configuration.getVersion()). Doing that defeats the purpose of incompatibleImprovements, and makes upgrading FreeMarker a potentially breaking change. Furthermore, doing this probably won't be allowed starting from 2.4.0, and will throw exception. So if above mistake is present in your application, it should be fixed by setting incompatibleImprovements to the highest concrete version that's known to be compatible with the application.

  • Added Environment.getDataModelOrSharedVariable(String).

  • Bug fixed: AST traversal API now can properly traverse the inside of lambda expressions (such as the parameter list)

  • Added a new SimpleHash constructor, where the caller can provide the Map instance used as the backing storage, thus allows controlling the ordering, and other technical aspects (like the initial capacity) of it.