2.3.21 - FreeMarker Manual

- Home
- Manual
- Java API

- Contribute
- Report a Bug
- Download

Manual
Previous Next

# 2.3.21

Date of release: 2014-10-12

Note that since 2.3.21 is designed to be fully backward compatible with the previous 2.3.x releases, some of the improvements and fixes described below are only activated when you specifically ask for 2.3.21 "incompatible improvements", because they could, with very small chance, break existing applications. If the dependent project is still actively developed, allowing 2.3.21 "incompatible improvements" is highly recommended. See how to set "incomplatible improvements" here.

Note that we have changed our proprietary BSD-style license to Apache License, Version 2.0. See the new license here.

Note that the minimum required Java version was increased from 1.2 to 1.4.

## Changes on the FTL side

- Improved ranges:

  - Added ranges with exclusive end: `start..<end` (also can be written as `start..!end`). More...

  - Added length limited ranges: `start..*length`: For example, `10..*4` gives `[10, 11, 12, 13]`, `10..*-4` gives `[10, 9, 8, 7]`, and `10..*0` gives `[]`. When these kind of ranges are used for slicing, the slice will end without error if the end of the sliced sequence or string is reached before the specified range length was reached. Thus, for example, to take the first 10 characters from the string `s`, or less if `s` is shorter than 10 characters, you can use `s[0..*10]`. More...

  - Square bracket now accepts range values from any source, like `<#assign r = 1..3> ${'foobar'[r]}` will print `"oob"`. Earlier it has only supported ranges that were specified directly inside the square brackets, like `'foobar'[1..3]`.

  - When slicing a sequence with a right-unbounded range, it's now allowed to have a range start index that's one higher than the last index of the sliced sequence. For example, `['x', 'y'][2..]` is not an error anymore, but an empty sequence. (Of course, `['x', 'y'][3..]` is still an error.)

  - `someString?substring(from, toExclusive)` and `someString?substring(from)` are now deprecated; use this slicing expression instead: `someString[from..<toExclusive]` and `someString[from..]`. A warning if you are processing XML: Since slicing expressions work both for sequences and strings, and XML nodes in FTL are typically both sequences and strings at the same time, there the equivalent expression is `someXmlNode?string[from..<toExclusive]` and `exp?string[from..]`, because without the `?string` it would slice the node sequence instead of the text value of the node.

  - If the `incompatible_improvements` in the FreeMarker configuration is set to at least 2.3.21, right-unbounded ranges become readable (like `#list`-able). Earlier they could only be used for slicing, and behaved like empty sequences otherwise.

- New built-in, `?url_path`: This is the same as the `url` built-in, except that it doesn't escape slash (`/`) characters. This meant to be used for converting paths (like paths coming from the OS or some content repository) that use slash (not backslash!) to a path the can be inserted into the path part of an URL.

- New built-ins for string manipulation:

  - `someString?keep_before(substring[, flags])`: More...

  - `someString?keep_after(substring[, flags])`: More...

  - `someString?remove_beginning(substring)`: More...

  - `someString?remove_ending(substring)`: More...

  - `someString?ensure_starts_with(substring[, substitution[, flags]])`: More...

  - `someString?ensure_ends_with(substring)`: More...

- `someString?number` now recognizes all XML Schema number formats, like `NaN`, `INF`, `-INF`, plus the Java-native formats `Infinity` and `-Infinity`.

- If `incompatible_improvements` in the FreeMarker configuration is set to at least 2.3.21, `someNumber?c` will return `"INF"`, `"-INF"` and `"NaN"` for positive/negative infinity and IEEE floating point Not-a-Number, respectively. These are the XML Schema compatible representations of these special values. Earlier it has returned what `java.text.DecimalFormat` did with US locale, none of which was understood by any (common) computer language.

- New built-in: `someString?boolean`. This is for example useful for converting "true" and "false" strings coming from XML to real boolean values. More...

- Date/time/date-time related changes:

  - Added new kind of `date_format`/`datetime_format`/`time_format` setting values: XML Schema formats, starting with `"xs"` and ISO 8601:2004 formats, starting with `"iso"`. The format string can be continued with various space (or `_`) separated options, like `h` or `m` or `s` or `ms` for setting shown accuracy, `nz` or `fz` for setting time zone offset visibility, and `u` or, `fu` for using UTC time zone . For example, to use ISO 8601 with minute precision and without the zone offset being shown, set the `datetime_format` setting to `"iso m nz"`, so then the output will be like `2014-09-03T20:56`. More...

  - Because anything that's accepted as `date_format`/`datetime_format`/`time_format` setting value can also be used with the `?string` and `?date`/`?time`/`?datetime` build-ins, you can use the new formats like `someDate?string.xs` and `someString?date.xs`. (For the `"xs"` and `"iso"` formats, `_` can be used instead of space, which means that, for example, you can write `lastModified?string.iso_m_u` instead of the more verbose `lastModified?string["iso m u"]`.)

  - That `"iso"` and `"xs"` are now possible `date_format`/`datetime_format`/`time_format` setting values also means that such values can now be parsed too via `?date`/`?time`/`?datetime`. The main application is with processing XML DOM-s, as there values are coming in as strings, and now you can do something like `order.confirmDate?date.xs` to convert them to real dates.

  - The `?iso_...` built-ins are now deprecated in favor of the new setting values described above. They can be set as the default date/time/date-time format, seamlessly fit into the formatting architecture (and thus can parse strings too), and has more/better options (`ms` always shows 3 millisecond digits, `fz` for forcing showing time zone offset).

  - If the "incompatible improvements" configuration setting is at least 2.3.21, the `?iso_...` built-ins won't show time zone offset for `java.sql.Time` values anymore. Most databases store time values that aren't in any time zone, but just store hour, minute, second, and decimal second field values, so showing the time zone doesn't make sense. (Notable exceptions are PostgreSQL "time with time zone" columns, where `mzTime?string.iso_fz` could be used.)

  - Added `?is_time`, `?is_datetime`, `?is_date_only` (should be called `?is_date`, but that was already taken) and `?is_unknown_date_like` to check the exact type of a date-like value.

  - `?is_date` is now a deprecated name, use `?is_date_like` instead. This is because `?is_date` sounds like it checks if the value is a date without time part, but actually it also returns `true` for time, date-time, and unknown date-like values.

  - Added `?date_if_unknown`, `?time_if_unknown` and `?datetime_if_unknown` built-ins, which mark a date-like value with some of the sub-types: date without time, time, or date-time, respectively. However, if the value already holds this information, the built-in has no effect. That is, it will never convert the sub-type of a value, it only adds the sub-type if it was unknown.

  - Bug fixed: ISO 8601 dates (via `?iso_...` and `"iso"` format settings) now use proleptic Gregorian calendar for the years before 1582, rather than Julian calendar. This is (indirectly) required by the standard, and it's also how the default Sun/Oracle Java XML Schema date/time/dateTime parser works.

- Error message quality improvements (targeting frequent support requests and some error message bugs):

  - Fixed glitch where if an `#if` had and `#else` or `#elseif`, the `#if`/`#else`/`#elseif` wasn't hidden in the FTL stack trace when the error was inside its nested block.

  - Some new context sensitive hints in undefined variable exception error messages.

  - Fixed unclosed directive error messages at end of file where the wrong unclosed directive name was reported

  - Better type error messages when accessing XML data (applies when wrapped with `freemarker.ext.dom`):

    - Trying to use `node.noSuchChildNodes` on a place where scalar value is expected will explain that the problem is that you had no matches in the constructing XML query.

    - Trying to use `node.multipleSuchChildNodes` on a place where scalar value is expected will explain that the problem is that you had multiple matches in the constructing XML query.

    - Trying to use `node.exactlyOneChildNode` as number, date/time/date-time or boolean will explain that values coming from XML are always strings (text), and must be converted explicitly via `?number`, `?boolean`, `?date.xs`, etc.

  - Trying to use `obj.someMethod` without `()` on a place where method value is not expected will recommend calling the method.

  - Trying to use methods like `obj.getFoo` or `obj.isFoo` without `()`on a place where method value is not expected will recommend using the `obj.foo` form.

  - Messages are now much more readable when rendered in environments that don't obey to line-breaks. (This often happens in improperly implemented HTML error pages and logs viewers.)

  - Better FTL instruction stack traces:

    - Error messages now contain up to 10 lines of FTL stack trace (unless it's on the top of a full FTL stack trace), because the FTL stack trace wasn't printed at all when the exception was a cause exception in a Java stack trace, or when only the value of `getMessage()` was printed instead of a stack trace.

    - The FTL stack trace is now more self explanatory as it contains more text labels.

    - Stack frames that belong to nestings are now marked differently, and are filtered out when the stack trace wouldn't fit into the error message otherwise.

  - Bug fixed: `?substring` has thrown low level `java.lang.IndexOutOfBoundsException`-s instead of more descriptive `TemplateModelException`-s with FTL stack trace.

  - Bug fixed: Slicing with ranges sometimes thrown low level `java.lang.IndexOutOfBoundsException`-s instead of more descriptive `TemplateModelException`-s with FTL stack trace.

  - Bug fixed [402]: Fixed misleading parser error message when a directive called without its required parameters (like `<#list>`) was reported as unknown directive.

  - Bug fixed [222]: Poor quality error message when `someString[someIndex]` fails with string index out of bounds.

  - Bug fixed [27]: Not very good quality error messages when `#import`-ing a template whose parsing fails.

- New `include` directive option, `ignore_missing=boolean`. When this is set to `true`, and the template to include is missing, the error will be silently ignored, and nothing will be included.

- The `setting` directive can now set the `output_encoding` setting.

- New special variable: `.locale_object`. This is like `.locale`, except that it's a `java.util.Locale` object, not a string. This is handy if you want to pass the current locale to Java methods.

- If `incompatible_improvements` in the FreeMarker configuration is set to at least 2.3.21, hash literals that repeat keys now only have the key once with `?keys`, and only has the last value associated to that key with `?values`. This is consistent with the behavior of `hash[key]` and how maps work in Java.

- Bug fixed: `?is_enumerable` has returned `true` for Java methods get from Java objects, despite that those values aren't `<#list ...>`-able. (This is actually a historical quirk of `BeansWrapper`, not a bug in `?is_enumerable`, but now `?is_enumerable` is aware of this exceptional case.)

- Bug fixed [257]: The result value of `?matches` wasn't "reentrant". For example, you couldn't list the matches inside another listing where you are also listing exactly the same result value (stored in a common variable), as they would consume from the same iterator. Most importantly, even accessing the `?size` of the same result value has terminated the outer listing of the same value.

- Bug fixed [229]: If you set `incompatible_improvements` to 2.3.21 (or higher), unclosed comments (`<#-- ...`) and `#noparse`-s won't be silently closed at the end of template anymore, but cause a parsing error instead.

## Changes on the Java side

- Added new `Configuration` constructor, `Configuration(Version incompatibleImprovements)`. This deprecates the vague `Configuration()` constructor, and makes using `setIncompatibleImprovements(Version)` needless in most cases. See an example here...

- When setting the `incompatible_improvements` setting (like with the constructor above) to 2.3.21, two setting defaults change:

  - The default of the `object_wrapper` setting (`Configuration.getObjectWrapper()`) changes from `ObjectWrapper.DEFAULT_WRAPPER` to another almost identical `DefaultObjectWrapper` singleton, returned by `new DefaultObjectWrapperBuilder(Version).build()`. The new default object wrapper's "incompatible improvements" version is set to the same as of the `Configuration`. (See later regarding the 2.3.21 "incompatible improvements" of `BeansWrapper` and `DefaultObjectWrapper`). Furthermore, the new default object wrapper doesn't allow changing its settings; setter methods will throw `IllegalStateException`. (If anything tries to call setters on the old default in your application, that's a dangerous bug that won't remain hidden now. As the old default is a singleton too, potentially shared by independently developed components, most of them expects the out-of-the-box behavior from it (and the others are necessarily buggy). Also, then concurrency glitches can occur (and even pollute the class introspection cache) because the singleton is modified after publishing.)

  - The default of the `template_loader` setting (`Configuration.getTemplateLoader()`}) changes to `null`, which means that FreeMarker will not find any templates. Earlier the default was a `FileTemplateLoader` that used the current directory as the root. This was dangerous and fragile as you usually don't have good control over what the current directory will be. Luckily, the old default almost never looked for the templates at the right place anyway, so pretty much all applications had to set `template_loader`, so it's unlikely that changing the default breaks your application.

- New `BeansWrapper`, `DefaultObjectWrapper` and `SimpleObjectWrapper` constructor that takes a `Version` `incompatibleImprovements` argument. This has the same role as the `incompatible_improvements` setting of the `Configuration`, but it applies to the `ObjectWrapper` instead. (As `ObjectWrapper`-s are often shared among multiple `Configuration`-s, so they can't use that setting of the `Configuration`.) In new or actively developed projects it's recommended to use `Configuration.VERSION_2_3_21` now. The constructor without the `Version` parameter is now deprecated.

- Safer and more memory-efficient way of managing singletons of `DefaultObjectWrapper`-s and `BeansWrapper`-s that are possibly shared by independently developed subsystems:

  - Instead of `new DefaultObjectWrapper(...)` and `new BeansWrapper(...)`, from now on you should use `new DefaultObjectWrapperBuilder(version).build()` and `new BeansWrapperBuilder(version).build()`. (The builder objects have properties (configuration settings) like `BeansWrapper` has, which specify the properties of the objects created.) The created objects are singletons (VM-wide, or at least Web-Application-wide) and read-only (means, non-configurable, hence safe to share). The main benefit of using these factories instead of creating new instances is that it allows FreeMarker to share the class introspection caches (an internal part of `BeansWrapper`-s/`DefaultObjectWrapper`-s that is expensive to populate) among the returned instances. This allow sharing the caches (and the object wrappers) between components that aren't aware of each other and use FreeMarker internally.

  - Deprecated the static fields `ObjectWrapper.DEFAULT_WRAPPER`, `BEANS_WRAPPER` and `SIMPLE_WRAPPER`, because these `ObjectWrapper`-s are configurable (not read-only), and thus dangerous to use as singletons (a badly behaving 3rd party component can mess them up). Use the factories described above instead. They are also more flexible, as you can specify the desired incompatible-improvements version for them and various other `BeansWrapper` settings.

  - Deprecated all `SimpleHash`, `SimpleCollection` and `SimpleSequence` constructors that didn't take an `ObjectWrapper` argument, as they have usually used `ObjectWrapper.DEFAULT_WRAPPER` as the default, which itself is deprecated.

  - `BeansWrapper`, `DefaultObjectWrapper` and `SimpleObjectWrapper` now implements the `freemarker.template.utility.WriteProtectable` interface with which the configuration properties of the object wrapper can be set permanently to read-only by calling `writeProtect()`. An attempt to call a setter on a such `ObjectWrapper` will immediately cause `IllegalStateException`. (This is what's used for the singletons returned by the `getInstance` methods too; see earlier).

- The value of the `time_zone` setting, when you specify it with a `String` (in a `java.util.Properties` object, or via `<#setting ...>`) can now be `"JVM default"` to use the JVM default time zone. The JVM default is the default value of that setting anyway, but now you can state this explicitly, or restore this value if it was overridden earlier.

- Added new configuration setting, `sql_date_and_time_time_zone` (`Configurable.setSQLDateAndTimeTimeZone(TimeZone)`). When this is set to non-`null`, the time zone used when dealing with `java.sql.Date` and `java.sql.Time` values will be this time zone instead of the value of the `time_zone` FreeMarker configuration setting. This is useful because JDBC will, usually, construct the Java `Date` objects so that they will show the year-month-day and hour-minute-seconds values from the database "as is" if you render them using the JVM default time zone. As time zone conversions for SQL date-only and SQL time-only values doesn't make much sense (unlike for SQL timestamps), you should certainly set this setting to the JVM default time zone (`TimeZone.getDefault()`, or if you configure FreeMarker via `java.util.Properties`, as property value "JVM default"). The default value is `null` for backward compatibility. For more details see the JavaDoc of `Configurable.setSQLDateAndTimeTimeZone(TimeZone)`.

- When configuring FreeMarker with `java.util.Properties` (typically, when the configuration is stored in a `.properties` file), for the settings where you could specify a fully qualified class name (most notably for the `object_wrapper` setting) now you can also specify constructor arguments and JavaBean property assignments. For example, now you can write `object_wrapper=com.example.MyObjectWrapper(1, 2, exposeFields=true, cacheSize=5000)`that's nearly equivalent with this Java code: `obj = new com.example.MyObjectWrapper(1, 2); obj.setExposeFields(true); obj.setCacheSize(5000); object_wrapper = obj;`. If you are using this new syntax (i.e., if you have parentheses after the class name, even if they are empty), and there's a builder class for the requested class, that will be automatically used. For example, `object_wrapper=DefaultObjectWrapper(2.3.21)` will create a `DefaultObjectWrapperBuilder` to build the final instance, thus the object wrapper will be a singleton instead of a new instance. The new syntax will also look for a public static `INSTANCE` field if there are 0 arguments and property assignments. For more details see the Java API documentation of `Configuration.setSetting`.

- Template not found exceptions now explain that the template path is interpreted by a template loader, and show the `toString` of the `TemplateLoader`. The out-of-the-box `TemplateLoader` implementations now have an overridden `toString` to show the actual base directory and such details. Custom `TemplateLoader` implementations are encouraged to override `toString`.

- Added `Configuration.setSharedVariables(Map/*<String, Object>*/)` for setting the shared variables from Spring IoC and other IoC solutions. The already existing `Configuration.setSharedVariable(String, Object)` isn't a JavaBean property so it was hard to use for that. Furthermore, the order in which `Configuration.setObjectWrapper` and `Configuration.setSharedVariables` are called doesn't mater (unlike in the case of `Configuration.setSharedVariable`), which is essential in most IoC solutions.

- Mostly concerning tool (like IDE plugin) authors:

  - `ParseException`-s now also store the end-location of the error, not just its start-location. This is useful if you want to underline the error in the source code, not just point at it.

  - `Configuration.getSupportedBuiltInDirectiveNames()` can be used to return the names of directives supported by FreeMarker.

  - `TemplateExceptions` now expose the position of the error (template name, line, column, end line, end column) similarly to `ParseException`-s. Where applicable, they also expose the blamed expression in its canonical FTL source form; this is mostly useful for `InvalidReferenceException`-s.

- The concurrent performance of overloaded method lookups (from the cache) was improved under Java 5 and later.

- The `Version` instances that are "incompatible improvements" break points are now available via constants like: `Configuration.VERSION_2_3_21`.

- From now on, if you try to set the "incompatible improvements" to greater than the current FreeMarker version, or less than 2.3.0, an `IllegalArgumentException` will be thrown. Thus, `new Configuration(someVersion)` not only activates the fixes up to that version, but ensures that the application will not run in an environment with an older FreeMarker version. (On an older FreeMarker version the improvements that you have requested aren't implemented yet, so you should get an exception.)

- Added new configuration setting, `show_error_tips`, defaults to `true`. Sets if tips should be shown in error messages of errors arising during template processing.

- Instead of overriding `BeansWrapper.finetuneMethodAppearance` (now deprecated), now you can use `BeansWrapper.setMethodAppearanceFineTuner(MethodAppearanceFineTuner)`, so you don't need to extend the object wrapper class to customize this aspect.

- Added `Configuration.getCoreDirecticeNames()` which returns the names of all directives that are provided by FreeMarker. This can useful for IDE-s.

- `template_loader` was added as possible configuration setting `Properties` key.

- The standard `CacheStorage` implementations now have a `getSize()` method for monitoring the cache size. `MruCacheStorage` also has `getSoftSize()` and `getStrongSize()`.

- Various smaller improvements in configuration setting errors messages.

- With incompatible improvements 2.3.21 only: Empty ranges return `Constants.EMPTY_SEQUENCE` instead of an empty `SimpleSequence`. This is in theory backward compatible, as the API only promises to give something that implements `TemplateSequenceModel`.

- FreeMarker now requires Java version has changed from 1.2 to 1.4.

- Bugs fixed and improvements in overloaded method selection/invocation, but only if you create the `BeansWrapper`/`DefaultObjectWrapper` with constructor parameter `Configuration.VERSION_2_3_21` (or if you are using `Properties` to configure FreeMarker, you can do that like `object_wrapper=BeansWrapper(2.3.21)`), or if you have a `Configuration` with similar `incompatible_improvements` 2.3.21 and you leave the `object_wrapper` setting on its default value. There's a little chance that because of these changes, a different overloaded method will be chosen than before, or even that ambiguity errors will arise where earlier they didn't (although the opposite is far more frequent), hence the fixes aren't automatically activated. But the fix mostly only effect calls that were failing or have chosen then wrong method earlier, so it's recommended to activate it for projects that are still actively developed. This fix includes numerous changes:

  - Earlier, `null` argument values has only matched overloaded methods where the corresponding parameter had `Object` type, not a subclass of it. That's clearly a bug. Now it considers all overloads where the parameter type is non-primitive, and just like the Java language, it choses the one with the most specific type among them. This is the most important fix, and also the most risky one regarding backward-compatibility. Like if you have `m(Object o)` and `m(String s)` in a Java class, earlier for a `m(null)` call in the template it has chosen `m(Object o)`, but now it will choose `m(String s)` instead (because `String` is also `null`-able and is more specific than `Object`). Furthermore, if you also had `m(File f)` in the same class, now it will cause an ambiguity exception, since the specificity of `File` and `String` can't be compared (same rule as under Java language), while earlier that wasn't a problem as only `m(Object o)` was seen as applicable.

  - The behavior of numbers with overloaded method selection was heavily reworked:

    - If possible, it now always choses the overload where overflow and truncation to integer (like 1.5 to 1) is avoided. Among the methods where no such critical loss occurs, it choses the overload with the least risk of precision loss (unless other conditions with higher priority suggest otherwise). Earlier, the method selection was prone to do choices that led to overflow or precision loss, especially when the parameter was a literal with decimals.

    - Overloaded method call can now convert to non-primitive numerical types, like a `Byte` or `byte` value is automatically converted to `Integer` if the parameter type is `Integer`. (This has always worked for non-overloaded methods.) Earlier where such conversion was needed, the method wasn't seen seen applicable.

    - Method selection is now not only based on the type of the wrapped number, but also on its value. For example, a `Long` with value `1` is now seen as compatible with a method with parameter type `int` or `short` or `byte`, as `1` can be stored in those without loss. This is important as unlike in Java language, in FTL you doesn't have strict control over the numerical types (the type of the wrapped number, actually), as FTL has no type declarations. (If multiple compatible methods are available, it will still try to chose the one with the same or bigger numerical type.)

    - Conversion from/to `BigInteger` is now supported.

  - Method choice ambiguity errors now occur much less often. Ambiguities was and are resolved by selecting the compatible methods then choosing the one with the most specific parameter types among them. The changes are:

    - When comparing the overall specificity of two parameter lists: Earlier the parameter list seen as more specific was the one that had some parameters that won in specificity, and if both had such parameters then it was an ambiguity. Now it's enough if a method has more such parameters where it's a better match than the other has, or if the two methods are still equal, if it has the first better matching parameter. This can lead to choices that seem arbitrary (but are still deterministic), but as there's no automated way of discovering method selection ambiguities in templates (unlike in Java source code, where they will be detected during compilation), especially as overloaded selection has to rely on the runtime type of the values which even make proper testing hard, this was considered to be a better compromise than throwing an exception whenever the choice of the method is not obvious. Also note that in fact this mechanism is more complicated than just counting the "winner" parameter positions for each methods, as certain kind of wins are stronger than any number of the others: wins where the other possibility is risking of substantial mantissa precision loss are the strongest (like dropping decimals versus not to), wins where the primitive type wins over the boxed class is the weakest (like `int` versus `Integer`), subclassing wins (like `String` versus `Object`) are between these two.

    - When comparing the specificity of two parameters types at the same parameter position: The algorithm now considers a primitive type as more specific that its corresponding boxing class (like `int` is considered to be more specific than `Integer`).

    - There was a bug with overloaded varargs methods of different parameter counts, where sometimes the last parameters of the compared methods was ignored, which is taking away a potential deciding factor and thus can lead to ambiguity error. Whether this happened depends on the order in which the Java reflection API has returned the methods, which is undocumented and known to change at least after some Java updates, breaking the application.

    - When comparing the specificity of two array types, until now they were seen as equal. Now the component types are compared, and then that with the less specific component type is preferred. For example, among `f(String[])` and `f(Object[])`, the last will always win. This might sounds controversial, but as we can't efficiently tell the common type of all the items in a sequence or `List`, an so we don't know if both arrays are indeed valid targets, we go for the safest choice.

  - FTL sequence values (like Java `List`-s or FTL `[x, y, ...]` constants) were not seen as applicable to a parameter with array type if there were multiple overloaded methods with the same number of parameters but with different types on the position of the array parameter. That is, if you had `f(String[])` and `f(String)` in Java, then `f(['foo', 'bar'])` in the template reported no compatible overloads. Now it will choose `f(String[])`. Note that if there's also an `f(List)` or even an `f(Collection)`, it will prefer those over arrays. (For consistency, this conversion will work even if the argument is a `List` that come directly from Java (as opposed to be created inside FTL), i.e., when it was wrapped then unwrapped to the original `List` object.) For a multidimensional array parameter type, this conversion works recursively, so you can pass in a sequence-of-sequences as the argument.

  - FTL sequence values that wrapped a Java array (when FreeMarker was also aware of that via `AdapterTemplateModel` or `WrapperTemplateModel`) were not seen as applicable to a parameter with `List` type if there were multiple overloaded methods with the same number of parameters but with different types on the position of the array parameter. So this is pretty much like the issue described in the previous point, but for array to `List` conversion. The array to `List` conversion will be avoided if possible, but it will be attempted if there's no other alternative. Note that unlike with `List` to array conversions, here FreeMarker can't cope with multi-dimensional lists, that is, an array-of-arrays won't be converted to a `List`-of-`List`-s.

  - FTL string to Java `char`/`Character` conversion now works for overloaded method parameters; earlier it has worked for non-overloaded methods only. If the string length is 1, it will be seen as compatible with parameters with `char` or `Character` type.

  - Decreased the chance of choosing the wrong target Java type when unwrapping multi-typed FTL values: When unwrapping a parameter value that implements multiple FTL types (e.g. string and hash) but doesn't implement `AdapterTemplateModel` or `WrapperTemplateModel`, a decision has to be made if to what Java type the value should be unwrapped to (e.g. to `String` or to `Map`). In earlier versions that decision was made based on the most specific common super type of the parameters types of the given parameter position. However, it's quite common that the common super type is too generic, usually `Object`. Now `BeansWrapper` stores "type flags" for each parameter position of overloaded methods, from which it can tell whether a potential target Java type occurs in any of the overloads on the given parameter position.

  - In many cases, less specific hint class was used for unwrapping than that was possible within the limitations of the applied hint generation algorithm. (The unwrapping hint has influence when there's an ambiguity regarding how to create a Java object form an FTL value. In the vast majority of the cases, a too generic hint has no effect.) (This is a highly technical topic. The way it works is that a single common unwrapping hint class is chosen for a given argument position shared by the overloads that has the same number of parameters, and that hint class has to be as specific as possible while it must fit all those parameter types. The issue with the too generic hints had several instances: (a) When the most specific common class/interface of two same-position parameter types was searched, if there was multiple common classes/interfaces that had no relationship (this is always at most one class and one or more unrelated interfaces), due to the ambiguity it has felt back to using `Object` as the unwrapping hint. Now if there's a non-`Object` class among them in such case, it will be chosen as the hint (i.e., we ignore the common interfaces). Otherwise if only a single interface remains by removing `Cloneable`, `Serializable`, and `Comparable` (in that order), that will be chosen. Only then it falls back to `Object`. (b) The common most specific class of a primitive type and the corresponding boxing class was sometimes `Object` instead of the boxing class. This has depended on Java's internal ordering of the methods, and so were quite unpredictable, like the result could change after upgrading Java under the application. (c) The common superclass of a numerical primitive value and a numerical non-primitive value was always `Object`, now if they are a primitive-boxing class pair, then it's the boxing class, otherwise it's `Number`. (d) If the varags parameter position was not the same in all the overloaded varargs methods, sometimes some varargs arguments where unwrapped with too generic hints. When this happened was unpredictable as it depended on Java's internal method ordering again.)

  - When unwrapping method call arguments before calling a Java method, if the argument was an `AdapterTemplateModel` and the target parameter type was primitive, `AdapterTemplateModel.getAdaptedObject(Class hint)` has received the primitive type of the target parameter (like `int` instead of `Integer`) as the hint. This did not make sense since `getAdaptedObject` can only return `Object`-s, not primitive values. Yet, `BeansWrapper` has expected the returned value to be of the primitive type, otherwise it has discarded it. Exactly the same problem occurs with `WrapperTemplateModel`. Thus, ultimately, if the target parameter type was primitive and some of these interfaces were implemented, their return value was always discarded and FreeMarker has felt back to other means of unwrapping. Now `BeansWrapper` always passes in and expects the boxing type (like `Integer`) instead of the primitive type.

- Bug fixed [373]: These are three bugs actually, which can cause problems when FreeMarker re-loads a template because of a charset override with `<#ftl encoding="...">`: First, if the template loader was a `URLTemplateLoader`, when `TemplateLoader.getReader()` was called for the second time, and the `Reader` returned for the first time was already used, it might returned an empty or corrupted template, depending on the backing URL implementation. Secondly, when FreeMarer has decided if a template file has to be re-loaded because its encoding specified with `<#ftl encoding="...">` differs from the encoding used for loading the template first, it has used case-sensitive comparison, thus often re-loaded needlessly (like "UTF-8" and "utf-8" mean the same). Now this comparison is case-insensitive. Last not least, when retrying with the second charset, the `TemplateCache` has forgotten to close the first `Reader`, which can be a handle leak.

- Bug fixed [411]: Invalid and redundant execution environment names from the OSGi bundle manifest were removed. It looks like this now: `Bundle-RequiredExecutionEnvironment: J2SE-1.5, J2SE-1.4`. That is, we prefer (and compile against) 1.5, but only require 1.4.

- Bug fixed [409]: `SimpleHash`'s internal `Map` is concurrently modified on a non-safe way when getting length-1 `String` key that exists but maps to `null`. This operation will accidentally add a `Character` key to the internal map, which is not a thread-safe operation.

- Bug fixed [273]: `TemplateLoader`-s that use `java.net.URLConnection`-s should set `URLConnection.useCaches` to `false`, or else it won't detect template caches on certain configurations.

  - `URLTemplateLoader` and its subclasses and `WebApplicationTemplateLoader` now has a `setURLConnectionUsesCaches(Boolean)` method. It's recommended to set this property to `false` from its default backward compatible value, `null`. As FreeMarker has its own template cache with its own update delay setting (`template_update_delay`, `Configuration.setTemplateUpdateDelay(int)`), it shouldn't cause performance problems. The `null` value will leave the caching of the `java.net.URLConnection` on its default, which is usually `true`.

  - If `incompatible_improvements` is set to 2.3.21 (or higher) and templates are loaded through `Configuration.getTemplate`, and the `TemplateLoader` in use has `URLConnectionUsesCaches` left on `null`, it will behave as if it was set to `false`. Note that this `incompatible_improvements` trick only works if the template is loaded through `Configuration.getTemplate` (or `TemplateCache`).

- Bug fixed: When changing the properties of `DefaultObjectWrapper` or `BeansWrapper` that influenced class introspection results (like `exposureLevel` or `exposeFields`), the introspection cache wasn't cleared, and thus returned stale information for the classes that were introspected before those properties were changed. Now changing such properties always clears the introspection caches.

- Bug fixed: Constants used for empty sequence, empty hash, empty collection and empty iterator weren't `Serializable`.

- Bug fixed [300]: Logger class availability check was incorrect in that it has checked the availability of logger libraries with the thread context class loader, then later it tried to link to them with the defining class loader of the FreeMarker classes. With some class loader setups (notably under Netbeans sometimes) this led to `ClassDefNotFoundError`-s that made FreeMarker unusable. (The check itself was also not very durable, as it didn't expected `LinakeError`-s, only `ClassNotFoundException`.)

- Bug fixed: `ClassUtil.forName`, used inside FreeMarker everywhere to resolve class names to classes, if the thread context class loader is `null`, no longer tries to load with the bootstrap class loader before loading with the defining class loader of FreeMarker.

- Bug fixed [311]: `TemplateBooleanModel.TRUE` and `FALSE` are now serializable

- Bug fixed: Various issues in `Version` class, such as wrong `hashCode`, possible concurrency glitches, and acceptance of some malformed version strings.

- Bug fixed [414]: Eclipse debug mode running was suspended during FreeMarker static initialization on the JRebel availability checked if JRebel wasn't available.

## Other changes

- The license has changed from our proprietary BSD-Style license to the well know "Apache License, Version 2.0". Furthermore, the copyright owner has changed from "Visigoth Software Society" (which was founded by Jonathan Revusky) to the three main FreeMarker 2 developers/contributors, "Attila Szegedi, Daniel Dekany, and Jonathan Revusky". See the new license here.

- The required minimum Java version was raised from 1.2 to 1.4. FreeMarker will not work on Java 1.2 or 1.3.

- Many smaller improvements and fixes in the Manual and API JavaDocs.

Previous Next