Date of release: 2015-07-05

Changes on the FTL side

  • Listing (#list) has received some specialized convenience features that target typical tasks people do again and again in templates.

    • New list directive child directives. There are else and items to deal with special cases with 0-length lists, and sep for inserting separators between items. For more details, see the list directive in the Reference.

    • New built-ins that act on loop variables: var?index (deprecates var_index), var?counter (1-based index), var?has_next (deprecates var_has_next), var?is_first, var?is_last, var?item_parity (returns "odd" or "even"), var?item_parity_cap, var?item_cycle(...), etc.

  • Added convenience assignment operators, which can be used in assignment directives (#assign, #global and #local currently) only:

    • ++ and --: For example, <#assign counter++> is equivalent to <#assign counter = counter + 1>.

    • +=, -=, *=, /= and %=: For example, <#assign counter += 2> is equivalent to <#assign counter = counter + 2>.

  • Added the then built-in, which can be used like a ternary operator: someBoolean?then(whenTrue, whenFalse). Just like with the ternary operator of most other languages, only one of the parameter expressions will be evaluated. More details...

  • Added the switch built-in, which can be used like an in-line (expression) switch-case-default statement: someValue?switch(case1, result1, case2, result2, ... caseN, resultN, defaultResult), where defaultResult can be omitted (then it will be error if none of the cases matches). More details...

  • Added camel case support for the identifiers that are part of the template language (user defined names aren't affected). For example, now <#noEscape>${x?upperCase}</#noEscape> or <#setting numberFormat="0.0"> or <#ftl stripText=true> are valid. However, within the same template, FreeMarker will require you to use the same naming convention consistently for all identifiers that are part of the template language. It's also possible to enforce the same naming convention on all templates from Java via Configuration.setNamingConvention(int). It's certain that camel case will be the recommended convention starting from some future version, because the Java API-s users call from templates use that too.

  • Added new special variables, .current_template_name and .main_template_name. These deprecate .template_name, which was always broken when it comes to macro calls. The new .current_template_name always returns the name of the template that contains the reference to the special variable, and .main_template_name always returns the name of the topmost template.

  • Smaller error message improvements. Like, added tip in the error message for the frequent issue when someMap[someNumber] complains that someMap is not a sequence nor is coercible to string.

  • Bug fixed, activated with setting incompatible_improvements to 2.3.23: There's a long existing parse-time rule that says that #break, in the FTL source code itself, must occur nested inside a breakable directive, such as #list or #switch. This check could be circumvented with #macro or #function, like this: <#list 1..1 as x><#macro callMeLater><#break></#macro></#list><@callMeLater />. After activating this fix, this will be caught as parse time error.

Changes on the Java side

  • Added Configuration.setNamingConvention(int). By default FreeMarker will auto-detect the naming convention (legacy VS camel case) used for the identifiers that are part of the template language, for each template independently. This setting lets you enforce a naming convention instead.

  • Configuration (and in fact any Configurable) setting names now can be written with camel case as well. For example, if you are configuring FreeMarker from properties file, you can have defaultEncoding=utf-8 instead of default_encoding=utf-8. You can use the two naming conventions (camel case, and tradition snake case) mixed, and Configuration.setNamingConvention(int) does not influence this behavior.

  • Added Configuration.setTemplateUpdateDelayMilliseconds(long) and Configuration.getTemplateUpdateDelayMilliseconds(). This deprecates setTemplateUpdateDelay(int), which uses seconds resolution, hence going against Java conventions and often leading to misunderstandings. (Also that couldn't have a getter pair.)

  • The template_update_delay setting, when specified as a string (as inside java.util.Properties), supports time units, like in template_update_delay=500 ms.

  • Added Environment.getCurrentTemplate() method, which return the currently executed template (as opposed to the main template).

  • Added WebappTemplateLoader.setAttemptFileAccess(boolean), which can be used to disable the legacy trick where we try to load templates through direct file access, so that template updating works without restarting. Disabling URL connection caches (someURLBasedTemplateLoader.setURLConnectionUsesCaches(false), which is also the default since incompatible_improvements 2.3.21) probably solves that on modern Servlet containers.

  • In the FreemarkerServlet TemplatePath init-param, paths (like /templates) can have a ?settings(...) postfix, with which you can set the JavaBean properties of the resulting TemplateLoader. For example: <param-value>/templates?settings(attemptFileAccess=false, URLConnectionUsesCaches=false)</param-value>

  • Added FileTemplateLoader.setEmulateCaseSensitiveFileSystem(boolean). This is handy when you are developing on Windows but will deploy to a platform with case sensitive file system. The default is false, and true is only meant for development, not for production installations. The default can be overridden by setting the org.freemarker.emulateCaseSensitiveFileSystem system property to true.

  • Bug fixed [424]: WebappTemplateLoader didn't find templates that are stored in WEB-INF/lib/*.jar/META-INF/resources. Files under that directory are visible as ServletContext resources since Servlet 3.0, yet WebappTemplateLoader has usually failed to see them because of some internal tricks.

  • Bug fixed: If a template "file" was successfully opened for reading, but then there was an IOException during reading its content, the parser (JavaCC) acted like if the template "file" was ended there, and the exception was suppressed. It's actually a JavaCC quirk that affects many other JavaCC-based languages too, but now FreeMarker has added a workaround in the Template constructor, and so now an exception will be thrown as expected.

  • Bug fixed: InvalidReferenceException.FAST_INSTANCE could accidentally store reference to an Environment instance, which hence was never garbage collected.

  • Bug fixed [426]: When setting incompatible_improvements to 2.3.22, the special variable reference .template_name in templates always returns the name of the main (topmost) template, due to an oversight in 2.3.22. Setting incompatible_improvements to 2.3.23 restores the old, backward compatible behavior. (Note that the old behavior that we emulate is itself broken, as it doesn't work well with macro calls; you should use .current_template_name or .main_template_name instead.)

  • Bug fixed [53]: Template parsing was abnormally slow for templates with very high number AST (abstract syntax tree) nodes on the same hierarchy level.

  • Bug fixed: When the template was concurrently replaced on the backing store during its first loading was still ongoing, the older version of the template could get into the cache with the time stamp of the new version, hence it wasn't reloaded after the configured update delay.

  • Bug fixed: The log_template_exceptions setting (added in 2.3.22) couldn't be set through the Configurable.setSetting(String, String) API.

  • Bug fixed: StringUtil.FTLStringLiteralEnc has escaped $ (hence generating an illegal escape) and haven't escaped { after $ and #. While this function is only used for generating error messages by FreeMarker, it's a public methods so anyone could use it.

  • Bugs fixed: Various canonical form glitches (they only affect error messages as far as FreeMarker is concerned).

Other changes

  • Modernized Manual and site design with improved functionality (always visible navigation tree, search inside the Manual, etc.), thanks to Evangelia Dendramis. (Also now the Site uses the same format and HTML generator as the Manual.)

  • Many smaller Manual and site content updates/improvements.


Changes compared to 2.3.23 RC1:

  • .current_name_name and .main_template_name is now missing (null) instead of "" if the template has no name

  • Some minor error message improvements

  • Documentation refinements