Release date: 2023-01-12

Changes on the FTL side

  • Improved outputting values for computer/parser consumption (such as for generating JSON, JavaScript values, values encoded into URL-s):

    • Added new configuration setting, c_format (also settable via the setting directive). This specifies what syntax to use when formatting values for computer consumption/parser, like "JSON". Most prominently, this affects the c built-in, hence the name. See valid setting values, and their meaning here: Template Author's Guide/Miscellaneous/Formatting for humans, or for computers.

      If you set the incompatible_improvements setting to 2.3.32, the default of c_format changes from "legacy" to "JavaScript or JSON", which is a format that most targets can parse (because we just format simple values, not lists and maps). With lower incompatible_improvements, the default value is "legacy" that emulates the old behavior of ?c (where you can lose numerical precision, etc.), so it's recommended to set it to something else.

    • ?c now formats string values to string literals (with quotation marks and escaping), according the language specified in the c_format setting, such as JSON, Java, etc. Earlier, ?c only allowed numbers, and booleans.

      To generate JSON, you can now write a piece of template like this:

      "fullName": ${user.fullName?c},

      Then the output will be like:

      "fullName": "John Doe",

      Note that the quotation marks were added by ?c, and weren't typed into the template.

    • Added ?cn, which is like ?c, except if the value is null/missing, it will output a null literal, according the language specified in the new c_format setting.

      Let's say, in the previous example user.fullName is expected to be null sometimes. Then you can just use ?cn instead if ?c:

      "fullName": ${user.fullName?cn},

      If said variable is null, the output will be like this (otherwise it will be a quoted string like earlier):

      "fullName": null,

      Note that with this approach you don't complicate the template anymore to avoid printing quotation marks. Of course, ?cn works on numerical and boolean values as well (and of course those won't be quoted, only strings).

    • c_format-s other than "legacy" use slightly different number formatting than ?c did in earlier versions. The change affects some non-whole numbers, and whole numbers with over 100 digits. The goal of this change is to make the formatting lossless, and also to avoiding huge output with exponents of high magnitude. See details at the documentation of the c built-in.

      Setting the incompatible_improvements setting to 2.3.32 will change the default of c_format for "legacy" to "JavaScript or JSON", and therefore changes number formatting too.

      Of course, all this only affects number formatting done with ?c, ?cn, and with "c" (or "computer") number_format, and not number formatting in general.

    • For consistency, when setting the number_format setting (also when formatting with ?string(format)), now "c" can be used instead of "computer". Both has the same effect on formatting, but "c" is preferred from now on.

  • FREEMARKER-208: Added ?c_lower_case, and ?c_upper_case, which are the non-localized (computer language) variants of ?lower_case, and ?upper_case. The primary problem people run into with the localized versions is that with Turkish locale the letter i, and I has different conversions than in most languages, which causes problem if the conversion was for computer consumption (for technical purposes), and not for humans.

  • In freemarker.ext.xml, which is the old, long deprecated XML wrapper, that almost nobody uses anymore (the commonly used one is freemarker.ext.dom), the _registerNamespace key now works, doing what the documentation always stated. Before this fix it just behaved as if it was the name of an element you are looking for.

Changes on the Java side

  • Added Configurable.setCFormat(CFormat), with the usual accompanying setting API methods/constants. See the c_format-, and the ?c-related changes earlier in the FTL section.

  • Added Environment.getCTemplateNumberFormat() that returns a freemarker.core.TemplateNumberFormat, and deprecated getCNumberFormat() that returns a java.text.NumberFormat. The behavior defined in the CFormat (see earlier) is only reflected exactly by the return value of the new method. The deprecated method returns a format that's a best effort approximation.

  • Added freemarker.core.MarkupOutputFormat.outputForeign(MO2 mo, Writer out) method, which for a MarkupOutputFormat where isOutputFormatMixingAllowed() returns true, allows full control over how to print a different markup into it. This can check what other markup is allowed, and do conversion if necessary. (GitHub PR 83)

  • Fixed performance bug with XML processing (freemarker.ext.dom) when converting an XML element that contains lots of text nodes (instead of a single big text node) to a string. (GitHub PR 82)

  • Improved StringUtil.jsStringEnc and javaSctringEnc to support quoting. Also jsStringEnc now have a mode that targets both JavaScript and JSON, and doesn't give up apostrophe escaping.

  • FREEMARKER-198: Fixed possible deadlock when the Configuration, and DefaultObjectWrapper class static initialization is triggered in different threads around the same time. (In the very unlikely case your application can run into this, this will hang the code that initializes FreeMarker before it has processed any templates, and it can't happen anymore if any template processing managed to start.)

  • FREEMARKER-190: Updated dom4j version used during FreeMarker project compilation from 1.3 to 2.1.3. Users can still use FreeMarker with dom4j 1.3 (mostly just luck, but it works). FreeMarker's dom4j support is long deprecated anyway, and almost nobody uses it anyway. We were forced to do this change because old dom4j versions have security vulnerabilities, and although FreeMarker is not affected by them (like we do not pull in dom4j as dependency into the projects of our users), we were flagged as vulnerable at certain places for merely supporting 1.3.

  • Slightly improved DefaultMemberAccessPolicy-rules (used by default), and unsafeMethods.properties (long deprecated, not used by default). Note that no matter how much we tweak these, they will never provide proper security if you have untrusted templates! See this in the FAQ!