| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| Because the Manual won't be updated for a good while, we will lead |
| the FreeMarker 3 changelog here. |
| |
| To understand the purpose of FreeMarker 3 (FM3 from now on), please see: |
| https://cwiki.apache.org/confluence/display/FREEMARKER/FreeMarker+3 |
| |
| |
| Template language changes |
| ========================= |
| |
| Note that the template converter tool (freemarker-converter) can automatically apply many of these changes on FM2 |
| templates. But changes that aren't purely syntactical (but behavioral) often can't be treated with 100% safety or at |
| all, in which case it's always noted for that change as "Converter note:". |
| |
| Major template language changes / features |
| ------------------------------------------ |
| |
| - Switched to camel case as the only supported naming convention. This is as if in FM2 you set the "namingConvention" |
| configuration setting to "camelCase", however the "namingConvention" setting was removed, as no other convention will |
| be supported (for the default dialect at least). Also, configuration setting names and values must use camel case |
| too (FM2 was forgiving there). Also, in XML processing, the @@ names were converted to camel case. This means |
| `#elseif` becomes ``#elseIf`, ``?upper_case` becomes `?upperCase`, and if you configure FreeMarker with Properties, |
| then `template_loader` becomes `templateLoader`, and if you use the XML features, then `node.@@nested_markup` |
| becomes `node.@@nestedMarkup`. |
| Note that the template converter tool takes care of this conversion. |
| - Parameters passed by position (as opposed to by name) must be separated by comma. Earlier the comma was optional. |
| (This is needed to allow passing parameters both by-position and by-name in the same invocation, which is not yet |
| implemented though.) |
| Examples: |
| `<@x x + 1 2 3 />` must now be written as `<@x x + 1, 2, 3 />` |
| `<#nested x y>` must now be written as `<#nested x, y>` |
| - #macro-s and #function |
| - Both #macro-s and #function-s can now define parameters that are passed by position, and parameters that are passed by name. |
| Function parameters are by default positional, which can be changed by adding `{named}` after the parameter name. |
| Macro parameters are by default named, which can be changed by adding `{positional}` after the parameter name. |
| Positional parameters always precede the named ones. There can be both a positional and a named varargs parameter; |
| the first is always a sequnce, the later is always a hash. |
| Examples: |
| - All named: `<#macro heading title icon>...</#macro>` `<@heading title="Test" icon="foo.jpg" />` |
| - Mixed: `<#macro heading title{positional} icon>...</#macro>` `<@heading "Test" icon="foo.jpg" />` |
| - All positional: `<#function f(x, y, r=0)>...</#function>` `${f(1, 2)} ${f(1, 2, 10)}` |
| - Mixed: `<#function f(x, y, r{named}=0)>...</#function>` `${f(1, 2)} ${f(1, 2, r=10)}` |
| - Positional varargs: `<#function sum(xs... abs{named}=false)>...</#function>` `${sum(1, 2, 3, abs=true)} |
| - Positional and named varargs: `<#function f(xs..., props{named}...)>...</#function>` `${f(1, 2, 3, x=1, y=2)}` |
| - In FM2, the same macro could be called with specifying all parameters by position, or by specifying all parameters |
| by name. In FM3 that won't work anymore, as now a parameter is either strictly positional or strictly named. |
| - Operator for handing null/missing values were reworked: |
| - The right-side operator precedence of the `exp!defaultExp` (and `exp!`) operator is now the same precedence on |
| both sides, which is lower than the precedence of `.`, but higher than the precedence of `+`. The converter takes |
| care of cases where this would change the meaning of the expression (like `x!y+1` is converted to `x!(y+1)`.) |
| - The value of `missing!` can now be used as boolean `false`, and as a function that returns `null` and accepts |
| any arguments, and as a directive that does nothing and allows any arguments (not only as "", empty sequence, |
| and empty hash). |
| - [TODO] Deeper changes are supposed to happen here later. (Some of the above changes will be meaningless then.) |
| |
| |
| Smaller template language changes |
| --------------------------------- |
| |
| Node: Changes already mentioned above aren't repeated here! |
| |
| - Removed support for all old glitches that you could turn on/off with `incompatibleImprovements` in FM2 (see |
| them in the JavaDoc of FM2 `Configuration`). |
| Converter note: The otherwise very low risk behavioral changes here aren't covered by the converter tool. |
| - Removed the following operator aliases: |
| - `=` for comparison (it can only be used for assignment now). Use `==` instead. |
| - `&` for logical "and". Use `&&` instead. |
| - `\and`, `&&`. Use `and` instead. (HTML entity support meant to be re-added, but "globally") |
| - `|` for logical "or". Use `||` instead. |
| - `\lt`, `<`. Use "lt" instead. |
| - `lte`, `\lte`, `<=`. Use "le" instead (syntax from XSLT). |
| - `\gt`, `>`. Use "gt" instead. |
| - `gte`, `\gte`, `>=`. Use "ge" instead (syntax from XSLT). |
| - New keywords (can't be used as identifier): `and`, `or`, `le`, `ge` |
| - Removed some long deprecated template language directives: |
| - <#call ...> (deprecated by <@... />) |
| - <#comment>...</#comment> (deprecated by <#-- ... -->) |
| - <#transform ...>...</#transform> (deprecated by <@...>...</@...>) |
| - <#foreach x in xs>...</#foreach> (deprecated by <#list xs as x>...</#list>) |
| - Removed long deprecated `#{}` interpolations. They are treated as plain static text now. |
| Converter note: The template converter tool translates these to `${}` interpolations. For example `#{x}` is simply |
| translated to `${x}`, while `#{x; m1M3}` is translated to `${x?string('0.0##')}`). The output should remain the same. |
| - In `#macro` and `#function` the comma must only be used between by-position parameters (earlier the comma was |
| optional). |
| - In `#function`, parentheses are now required around parameter list (as in `<#function f(a, b)>`), even if there are |
| zero parameters (as in `<#function f()>`). In `#macro`, parentheses are not allowed around parameter list anymore |
| (so `#macro m(a b)` becomes to `#macro m a b`). This is to remain more consistent with the look-and-feel of the |
| invocation of the function or macro. |
| - Removed some long deprecated built-ins: |
| - `webSafe` (converted to `html`) |
| - `exists` (`foo?exists` is converted `foo??`) |
| - `default` (`foo?default(bar)` is converted to `foo!bar`). |
| - `if_exists` and `ifExists` (`foo?if_exists` is converted to `foo!`). (There's a slight difference though that |
| the return value can be called as directive (which does nothing), while with `?ifExists` that wasn't possible.) |
| - Comma is now required between sequence literal items (such as `[a, b, c]`). It's not well known, but in FM2 the comma |
| could be omitted. |
| - #include has no "encoding" and "parse" parameter anymore (as now only the Configuration is responsible for deciding those) |
| - You can't close #attempt/#recover with `</#recover>` anymore, only with `<#attempt>`. This was the |
| standard form in FM2 as well, and is consistent with how #if/#else works. (The template converter |
| tool does this conversion.) |
| - Inside a #switch, #case can't be after #default anymore (this is actually a bug in FM2) |
| (The template converter can't fix this automatically, but reports it as an error.) |
| - #else and #elseIf tags must be ended without "/", for example, <#else/> is illegal now, <#else> is legal. |
| - ${someBoolean?string} with the default booleanFormat setting value will not convert the boolean to true/false anymore, |
| instead it will fail just like ${someBoolean} would. Use ${someBoolean?c} instead - it's preferable in FM2 as well. |
| - Renamed `?datetime` and `?datetimeIfUnknown` and the `datetimeFormat` setting to |
| `?dateTime` and `?dateTimeIfUnknown` and `dateTimeFormat`. (In general, it's `dateTime`, not `datetime` everywhere.) |
| assertConverted("${.outputFormat}","${.output_format}"); |
| - Removed the `.currentNode` (`.current_node`) special variable, which was a deprecated alias to `.node` |
| - Removed the `.templateName` (`.template_name`) special variable, which was deprecated by `.currentTemplateName` |
| since 2.3.23. |
| Converter note: This conversion is done, but note that in the rare case where a template has no name (when |
| creating a `Template` directly with its constructor using `null` as the `name` parameter) `.templateName` was an |
| empty string, while `.currentTemplateName` will be null. |
| - Refactoring of callable TemplateModel interfaces and related classes: |
| - TemplateDirectiveModel was redesigned (see in the major changes section) |
| - Removed `TemplateTransformModel`; `TemplateDirectiveModel` can do the same things, and more. |
| - Renamed `DirectiveCallPlace` to `CallPlace` |
| - Removed Environment.getDirectiveCallPlace(), as TemplateDirectiveModel-s now get the CallPlace as the |
| parameter of the `execute` method. |
| - `?isTransform` was removed (as there are no transforms anymore); use `?isDirective` instead. |
| - `?isMacro` was removed; use `?isDirective` instead, which returns `true` both for macros and directives defined otherwise. |
| - `?isMethod` was removed; use `?isFunction` instead, which returns `true` both for Java methods and functions defined |
| otherwise (such as with `#function`). |
| - The FM2 `?isCollection` and `?isEnumerable` was replaced by `?isIterable`. `?isCollectionEx` was renamed to |
| `?isCollection`. (These follows the similar nomenclature change in the TemplateModel API-s) |
| `?isIndexable` was removed, and can be replaced with `?isSequence`. |
| - The directive returned by `?interpret` doesn't allow nested content anymore. (It wasn't useful earlier either; |
| the nested content was simply executed after the interpreted string.) |
| - Changes in #macro/#functions |
| - See major changes first, in the earlier chapter |
| - It's not tolerated anymore if the caller of a macro has declared more nested content parameters than |
| what `#nested` passes to it (like in `<#macro m><#nested 1, 2></#macro> <@m ; i, j, k>...</@>`, where `k` has |
| no corresponding value in `#nested`). |
| (The template converter tool can't do this conversion.) |
| - In `#macro` (and `function`) named parameters with default values need not be at the end of the parameter list |
| anymore. (Positional parameters with default values need to be at the end of the list of positional parameters |
| only.) |
| - When parameter default expressions are evaluated, only the parameters defined earlier are already set. |
| So `<#macro m a b=a>` works, but `<#macro m a=b b>` won't work anymore (unless there's `b` outside the |
| parameter list), as `b` is not yet set when the default of `a` is calculated. |
| (The template converter tool can't do this conversion.) |
| - Built-ins don't convert their parameters to string anymore; in FM some (not all) of them did, because they |
| were based on the TemplateMethod interface (deprecated even in FM2) that required String paramteters and |
| was auto-converted by FM2. (The template converter tool can't do this conversion.) |
| - The string ranges like `someString[1..0]` (that is, where the end is one less than the beginning) aren't |
| tolerated anymore, and are errors. (The template converter tool can't do this conversion.) |
| - Added `?sequence`, which converts an iterable value into a sequence. This is to be used with care, as iterables |
| that are not also sequences sometimes contain a large number of items, and the resulting sequence will have to |
| store all of them. |
| - `?keys` and `?values` (used to return the keys and values in a hash) now returns a collection, not a sequence. |
| Note that for FM3 collections ?size works, but not accessing by index. This is to be more aligned with the |
| capabilities of java.util.Map. In case you know that you won't have a too large number of entries, and you need |
| a sequence of the keys or values, use `myMap?keys?sequence` or `myMap?values?sequence`. |
| (The template converter tool can't do this conversion. Because `?sequence` is a relatively expensive operation, |
| it shouldn't be invoked for multiple times on the same value, instead the result should be extracted into a |
| variable, like: `<#assign keySeq = keys?sequence>[... Do multiple things with keySeq here ...]`. |
| |
| |
| Java API changes |
| ================ |
| |
| Major changes / features |
| ------------------------ |
| |
| - Modularized the project. Now we have these published jar-s: |
| - org.apache.freemarker:freemarker-core |
| - org.apache.freemarker:freemarker-servlet |
| - org.apache.freemarker:freemarker-dom |
| - org.apache.freemarker:freemarker-spring |
| There are several other internal modules related to testing and such; these aren't published. |
| - Reorganized package structure: Everything starts with org.apache.freemarker, and continues with |
| subpackage that corresponds to the module (see modularization above). So we have |
| org.apache.freemarker.core (has nothing to do with the old freemarker.core), org.apache.freemarker.servlet (this |
| replaced freemarker.ext.servlet and freemarker.ext.jsp), org.apache.freemarker.dom (replaces freemarker.ext.dom), etc. |
| Directly inside org.apache.freemarker.core we have most of the classes that were in freemarker.template and |
| freemarker.core, however, model related classes (and object wrappers) were moved out to |
| org.apache.freemarker.core.model, and template loading and caching related classes to |
| org.apache.freemarker.core.templateresolver (we have a class called TemplateResolver; see later). |
| OutputFormat related classes were moved to org.apache.freemarker.core.outputformat. |
| ValueFormat related classes were moved to org.apache.freemarker.core.valueformat. |
| ArithmeticEngine related classes were moved to org.apache.freemarker.core.arithmetic. |
| - Added the org.apache.freemarker.core.templateresolver.TemplateResolver class and the `templateResolver` Configuration |
| setting. This allows replacing the whole template lookup, loading and caching logic with a custom implementation, |
| giving total control over this aspect of FreeMarker, in case replacing Configuration settings like `templateLoader` |
| or `templateCacheStorage` wasn't enough. The `TemplateResolver` implementation declares which of the template resolution |
| related Configuration settings it supports (for example, it may still want to rely on the `templateLoader`, but |
| doesn't use the other settings). It's an error to set a template resolution related settings that the TemplateResolver |
| doesn't support. The default implementation, `DefaultTemplateResolver`, supports all of them of course. Note that the |
| `TemplateCache` class was removed, and was basically replaced by `DefaultTemplateResolver`. |
| - Totally redesigned TemplateLoader interface. The FM2 TemplateLoader can't be adapted (wrapped) to it, but usually |
| it's fairly trivial to "rearrange" an old custom TemplateLoader for the new interface. The new TemplateLoader comes |
| with several advantages, such as: |
| - It can work more efficiently with sophisticated storage mechanisms like a database, as it's now possible to pack |
| together the existence check, the last modification change check, and reading operations into less storage level |
| operations (like you can do all of them with a single SQL statement). |
| - The new TemplateLoader allows returning the template content either as an InputStream or as a Reader. Almost all |
| TemplateLoader-s should return InputStream, and FreeMarker takes care of charset issues transparently (as a result, |
| TemplateLoader-s don't have to support re-reading a template anymore, as we solve charset detection misses in |
| memory). TemplateLoader-s that are inherently backed by text (String-s), such as templates stored in a varchar or |
| CLOB column, should return a Reader. Note that templates created from a Reader will have template.getEncoding() |
| null (logically, as no charset was involved), which was impossible in FreeMarker 2. |
| - The change detection of the template doesn't have to rely on a millisecond resolution timestamp anymore; you can |
| use what's most appropriate for the storage mechanism, such as a cryptographic hash or a revision number. |
| - Template lookups (where you try multiple names until you find the best template) can now be transactional and/or |
| atomic if the backing storage mechanism supports that, by utilizing the TemplateLoaderSession interface. |
| - TemplateLoader can now return template-level settings like the output format (MIME type basically) of the loaded |
| template, in case the backing storage stores such extra information. This mechanism can be used together with |
| the TemplateConfiguration mechanism (already familiar from FreeMarker 2), and overrides the individual settings |
| coming from there. |
| - Configuration is now immutable. You should use Configuration.Builder to set up the setting values, then create |
| the Configuration with the builder's build() method. |
| - Configuration defaults were changed to follow the current best practices (like default charset is UTF-8 everywhere) |
| - Reworked TemplateModel interfaces (see more details in the later sections): |
| - Callable `TemplateModel`-s (i.e., models that can be called like `foo(...)` or as `<@foo .../>`) were replaced by |
| `TemplateFunctionModel` and the reworked `TemplateDirectiveModel` interface. Both of these support padding arguments |
| by position and by name, even in the same call (e.g., `<@heading "Some title" icon="foo.jpg" />`, `sum(1, 2, 3, abs=true)`). |
| Because of the extended capabilities of this interface, callables defined inside templates (via `#function` and `#macro`) |
| are now just create `TemplateFunctionModel` and `TemplateDirectiveModel` objects. |
| - Listable TemplateModel-s and their intheriance hierarchy are now much more similar the Java collection API: |
| TemplateIterableModel > TemplateCollectionModel > TemplateSequenceModel [TODO: This last will be TemplateListModel]. |
| - Removed freemarker.ext.log, our log abstraction layer from the times when there was no clear winner on this field. |
| Added org.slf4j:slf4j-api as required dependency instead. |
| - Added Spring support to the FreeMarker project (freemarker-spring module), instead of relying Spring developers |
| [Note: This is in very early stage, as of 2017-07-06.] |
| - Added `Configuration.templateLanguage` and the `TemplateLanguage` class, which encapsulate the syntax and some of the |
| semantics, most importantly the `outputFormat`. |
| - Each `TemplateLanguage` has an associated file extension, which should be sufficient for editors (IDE-s) to chose the |
| proper syntax highlighting. Syntax auto-detection was removed, as editors couldn't cope with it. Thus, the new file |
| extensions are somewhat complex, but serve tooling well. They are put together from 3 parts: |
| 1. "f3" for FreeMarker 3. (Extensions starting with "f" are reserved for the FreeMarker project.) |
| 2. Syntax: "a" for `ANGLE_BRACKET` `tagSyntax` and `DOLLAR` `interpolatonSyntax`, or "s" for `SQUARE_BRACKET` |
| `tagSyntax` and `SQUARE_BRACKET` `interpolationSyntax`. (Other permutations are possible, but has no standard |
| file extension reserved for them.) |
| 3. Output format: Currently "h" for HTML, "x" for XML, "u" for undefined, "c" for configured (i.e., coming from |
| the `Configuration` or other kind of `ParsingConfiguration`). This is important for syntax highlighting of the |
| static parts, hence it's encoded into the file extension too. It's also important for security reasons, |
| So a common file extensions will be "f3ah". |
| The FM2 file extensions, "ftl", "ftlh", and "ftlx" by default give error (FM 2 templates not supported) to |
| prevent confusion. |
| |
| |
| Smaller Java API changes (categorized) |
| -------------------------------------- |
| |
| Node: Changes already mentioned above aren't repeated here! |
| |
| Core / Configuration |
| .................... |
| |
| - Configuration is now immutable (see earlier), so `Configuration.Builder` was added, which extends |
| `Configuration.ExtendableBuilder`. It's now possible to change the `Configuration` setting defaults by using a custom |
| subclass instead of `Configuration.Builder`. (`FreeMarkerServlet` has switched to this approach, using its own |
| builder subclass to provide defaults that makes the sense in that particular application.) |
| - setClassForTemplateLoader, setDirectoryForTemplateLoading and the like were removed, instead there's just |
| setTemplateLoader. So for example. instead of setClassForTemplateLoader(Foo.class, "templates") now you have |
| to write setTemplateLoader(new ClassTemplateLoader(Foo.class, "templates")). While it's a bit longer, it shows |
| more clearly what's happening, and always supports all TemplateLoader constructor overloads. |
| - setSetting (and the like) doesn't throw ParseException (the same exception used when parsing templates) anymore, |
| but ConfigurationException. Also, on the places where ParseException was used for other than template parsing, |
| o.a.f.core.util.GenericParseException is used now instead, which doesn't have the template parsing related fields |
| that we can't fill. |
| - Removed `String Configurable.getSetting(String)` and `Properties getSettings()`. It has never worked well, |
| and is impossible to implement properly. |
| - Added ProcessingConfiguration interface for the read-only access of template processing settings. This is similar to |
| the FM2 ParserConfiguration interface. |
| - Renamed Configurable to MutableProcessingAndParserConfiguration. Made it abstract too. |
| - Made Template immutable (via public API-s). Template-specific settings now can only come from the |
| TemplateConfiguration associated to the template, or from the #ftl header for some settings (most notably for |
| custom attributes). |
| - Renamed ParserConfiguration to ParsingConfiguration, so that the name is more consistent with the new |
| ProcessingConfiguration. |
| - Changed the defaults of some Configuration settings: |
| - Changed the default of sourceEncoding ("encoding" earlier) to UTF-8 from the platform default charset. |
| Using the platform default charset was proven to be fragile in practice, |
| like applications could break when moved to another server if the application |
| was unwillingly relying on the default. |
| - Changed the default of templateExceptionHandler (template_exception_hander) to |
| TemplateExceptionHandler.RETHROW from DEBUG |
| - Changed the default of sqlDateAndTimeTimeZone (sqlDateAndTimeTimeZone) to |
| TimeZone.default() from null (where null meant falling back to the timeZone setting value) |
| - Changed the default of templateNameFormat (templateNameFormat) to what's equivalent to |
| FM2 DefaultTemplateNameFormat24. The old DefaultTemplateNameFormat was removed, and |
| DefaultTemplateNameFormat24 was renamed to DefaultTemplateNameFormat. |
| - Removed the logTemplateExceptions (log_template_exceptions) setting. FreeMarker now behaves as if it was false. |
| When a FreeMarker method throws an exception, the caller is responsible for either logging it or letting it bubble up. |
| - Removed the wrapUncheckedExceptions setting. FreeMarker now behaves as if it was true. |
| - Removed the strictSyntax setting, and so also the support for FTL tags without #. This was a FreeMarker 1.x |
| compatibility option. |
| - The `tagSyntax` setting doesn't support the `autoDetect` value anymore. It was removed mostly because tools (editors) |
| could almost never implement it. Instead, there will be ([TODO]) separate file extensions for each syntax variation. |
| - Renamed the `cacheStorage` Configuration setting to `templateCacheStorage`. |
| - Renamed the `localizedLookup` Configuration setting to `localizedTemplateLookup`. |
| - Renamed the `datetimeFormat` Configuration setting to `dateTimeFormat` (following Java 8 convention). |
| - Renamed the String key for the historically incorrect `autoInclude` Configuration setting to `autoIncludes`. |
| - Renamed the String key for the historically incorrect `autoImport` Configuration setting to `autoImports`. |
| - TemplateClassResolver.UNRESTRICTED_RESOLVER and ALLOWS_NOTHING_RESOLVER was renamed |
| to UNRESTRICTED and ALLOW_NOTHING. Also the String setting name "allows_nothing" and |
| "allowsNothing" were renamed to "allowNothing". |
| - TemplateExceptionHandler.IGNORE_HANDLER, RETHROW_HANDLER, DEBUG_HANDLER and |
| HTML_DEBUG_HANDLER was renamed to IGNORE, RETHROW, DEBUG and HTML_DEBUG |
| - AttemptExceptionReporter.LOG_ERROR_REPORTER and LOG_WARN_REPORTER was renamed to |
| LOG_ERROR and LOG_WARN (to be consistent with the new TemplateExceptionHandler names) |
| - Removed TemplateClassResolver.SAFER_RESOLVER, because the classes it has blocked were removed from FreeMarker, so it's |
| the same as UNRESTRICTED_RESOLVER |
| - When specifying the templateUpdateDelay configuration setting with a String (with Properties), the time unit is |
| required, unless the value is 0. |
| - Even for setting values that are class names without following `()` or other argument list, the INSTANCE field and |
| the builder class will be searched now, and used instead of the constructor of the class. Earlier they weren't for |
| backward compatibility. |
| - Removed the static default Configuration instance. (It's not possible to create a template with null Configuration |
| constructor argument anymore.) |
| - The strict_bean_models configuration setting was removed, as it should be set on the BeansWrapper itself |
| - When looking for a builder class in builder expressions used in setting values like `com.example.Foo()`, now we first |
| look for com.example.Foo.Builder, and only then com.example.FooBuilder. |
| - Removed Configuration.Builder.setEncoding(java.util.Locale, String) and the related other methods. Because of the new |
| logic of template encodings, the locale to encoding mapping doesn't make much sense anymore. |
| - As "attributes" can't be modifiable now that Configuration is immutable, and hence didn't fit into the new system, |
| the "attributes" setting was removed. In place of that, two new concepts were introduced, targeting two different |
| "attributes" use-cases: |
| - Custom states: CustomStateKey class and the CustomStateScope interface was introduced, which |
| is somewhat similar to the now removed CustomAttribute. CustomStateScope contains one method, Object |
| `getCustomState(CustomStateKey)``, which may calls `CustomStateKey.create()` to lazily create the state object |
| for the key. `Configuration`, `Template` and `Environment` implements `CustomStateScope`, so you can store state |
| in any of these scopes. |
| - Custom settings: These have the same mutability rules as normal settings, that is, you can't modify them except in |
| builder objects and in the `Environment`. You can get their values with `getCustomSetting(Serializble key[, Object |
| defaultValue])`. If no default is specified, and the custom setting is not set, a `CustomSettingNotSetException` |
| is thrown. Just like standard settings, custom settings automatically inherited from higher scopes. |
| - In the `#ftl` header the `attributes` parameter name was changed to `customSettings` |
| (The template converter tool takes care of this conversion.) |
| - Renamed Configuration.defaultEncoding to sourceEncoding, also added sourceEncoding to ParserConfiguration, and renamed |
| TemplateConfiguration.encoding and Template.encoding to sourceEncoding. (Before this, defaultEncoding was exclusive |
| to Configuration, but now it's like any other ParserConfiguration setting that can be overridden on the 3 levels.) |
| - Settings that have contained a charset name (sourceEncoding, outputEncoding, URLEscapingCharset) are now of type Charset, |
| not String. For string based configuration sources (such as .properties files) this means that: |
| - Unrecognized charset names are now errors |
| - For recognized names the charset name will be normalized (like "latin1" becomes to "ISO-8859-1"). |
| - In "object builder expressions" Charset values can now be constructed like `Charset("ISO-8859-5")`. |
| Note that as the type of the settings have changed, now you can't just write something like |
| `TemplateConfiguration(sourceEncoding = "UTF-8")`, but `TemplateConfiguration(sourceEncoding = Charset("UTF-8"))`. |
| - Configuration-related int constants were replaced with enums: |
| - FM2 Configuration.${c}_TAG_SYNTAX with TagSyntax.${c} |
| - FM2 Configuration.${c}_INTERPOLATION_SYNTAX with InterpolationSyntax.${c} |
| - FM2 Configuration.${c}_AUTO_ESCAPING_POLICY with AutoEscapingPolicy.${c} |
| - Removed hasCustomFormats() from configuration related API-s (we don't need it anymore) |
| - The tagSyntax and interpolationSyntax settings were moved inside the templateLanguage setting, as they are only |
| applicable if the templateLanguage is a DefaultTemplateLanguage instance. |
| - Removed Configuration.fallbackOnNullLoopVariable, FM3 never falls back on such loop variables (as if the FM2 |
| setting was set to false) |
| |
| |
| Core / Models and Object wrapping |
| ................................. |
| |
| - DefaultObjectWrapper is now immutable (has no setter methods), so most of the mutator methods (like setters) were |
| moved rom Configuration to Configuration.Builder. |
| - `DefaultObjectWrapper` now has a configuration setting, `extensions`, to add `DefaultObjectWrapperExtension`-s, which |
| meant to be used for wrapping application-specific objects specially. Along with this, `DefaultObjectWrapper` now has |
| two protected methods to customze the wrapping logic, `wrapSpecialObject(Object)` and `wrapGenericObject(Object)`; the |
| last replaces the `handleUnknownType(Object)` method from FM2. `DefaultObjectWrapperExtension`-s are applied before or |
| after `wrapSpecialObject`, depending on what `DefaultObjectWrapperExtension.getPhase()` returns. See the JavaDoc of |
| `DefaultObjectWrapper.wrap(Object)` for more on wrapping phases. |
| - `DefaultObjectWrapper` doesn't wrap W3C DOM nodes (XML) specially anymore, as DOM wrapping was factored out to a |
| separate jar (freemarker-dom) as part of modularizing FreeMarker. To ensure that DOM nodes are wrapped specially as |
| in FM2, the `extensions` setting of the `DefaultObjectWrapper` has to be so that it contains |
| `DOMDefaultObjectWrapperExtension.INSTANCE`. For example: |
| cfgBuilder.objectWrapper( |
| new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0) |
| .extensions(DOMDefaultObjectWrapperExtension.INSTANCE) |
| .build()) |
| - Moved the all the static final ObjectWrapper-s to the new _StaticObjectWrappers class, and made them |
| write protected (non-configurable). Also now they come from the pool that ObjectWrapper builders use. |
| - WrappingTemplateModel.objectWrapper is now final, and its statically stored default value can't be set anymore. |
| - Removed SimpleObjectWrapper deprecated parameterless constructor |
| - Removed the deprecated BeansWrapper.nullModel setting. So null is always wrapped to null now. |
| - Removed the overridable BeansWrapper.finetuneMethodAppearance method, which was deprecated by the |
| finetuneMethodAppearance setting (BeansWrapper.setFinetuneMethodAppearance). |
| - Removed BeansWrapper, which was the superclass of DefaultObjectWrapper, but wasn't recommended to be used as is. |
| Removed many BeansWrapper-related classes that DefaultObjectWrapper doesn't use. This includes ModelCache and |
| related classes, because DefaultObjectWrapper has only used the cache for "generic" classes (because that's where it |
| has fallen back to BeansWrapper.wrap), which is inconsistent and doesn't worth the caching overhead and complexity. |
| - Removed parameterless DefaultObjectWrapper and BeansWrapper constructors. Now specifying the |
| incomplatibleImprovement version is required. |
| - Removed DefaultObjectWrapper settings that only exist so that you can set backward compatible behavior instead of |
| the recommended value: useAdaptersForContainers, forceLegacyNonListCollections, iterableSupport, simpleMapWrapper |
| - Java methods (when using DefaultObjectWrapper) won't be accessible as sequences anyore. That is, earlier, instead of |
| obj.m(1), you could write obj.m[1]. This strange feature has led to some tricky cases, while almost nobody has |
| utilized it. |
| - SimpleObjectWrapper was renamed to RestrictedObjectWrapper. When configuring with properties, the `simple` setting |
| value for the `objectWrapper` (`object_wrapper`) setting is not supported anymore, instead `RestrictedObjectWrapper(3.0.0)` |
| can be written. |
| - Removed the global static final ObjectWrapper-s. It had a "few" consequences: |
| - Standard TemplateModel implementations that can have an ObjectWrapper contrucor parameter don't allow null there anymore. |
| Also, any constructor overloads where you cold omit the ObjectWrapper were removed (these were deprecated in FM2 too). |
| In FM2, such overloads has used the global static default DefaltObjectWrapper, but that was removed. |
| - If the ObjectWrapper is not a DefaultObjectWrapper (or a subclass of it), `className?new(args)` will only accept 0 arguments. |
| (Earlier we have fallen back to using the global static default DefaultObjectWrapper instance to handle argument unwrapping |
| and overloaded constructors.) Note that ?new is only used to instantiate TemplateModel-s, typically, template language |
| functions/directives implemented in Java, and so they hardly ever has an argument. |
| - FreemarkerServlet now requires that the ObjectWrapper it uses implements ObjectWrapperAndUnwrapper. (Thus, the return type |
| of FreemarerServlet.createDefaultObjectWrapper() has changed to ObjectWrapperAndUnwrapper.) The unwrapping functionality is |
| required when calling JSP custom tags/functions, and in FreeMarker 2 this was worked around with using the |
| global static default DefaultObjectWrapper when the ObjectWrapper wasn't an ObjectWrapperAndUnwrapper. |
| - If for an indexed JavaBean property there's both an indexed read method (like `Foo getFoo(int index)`) and a normal read method |
| (like Foo[] getFoo()), we prefer the normal read method, and so the result will be a clean FTL sequence (not a multi-type value |
| with sequence+method type). If there's only an indexed read method, then we don't expose the property anymore, but the indexed |
| read method can still be called as an usual method (as `myObj.getFoo(index)`). These changes were made because building on the |
| indexed read method we can't create a proper sequence (which the value of the property should be), since sequences are required |
| to support returning their size. (In FreeMarker 2 such sequences has thrown exception on calling size(), which caused more |
| problems and confusion than it solved.) |
| - Removed DefaultObjectWrapper.methodsShadowItems setting, in effect defaulting it to true. This has decided if the generic |
| get method (`get(String)`) had priority over methods of similar name. The generic get method is only recognized from its |
| name and parameter type, so it's a quite consfusing feature, and might will be removed alltogether. |
| - Renamed TemplateDateModel.DATETIME to DATE_TIME (to be consistent with "dateTime" used elsewhere). |
| - `TemplateMethod` and `TemplateMethodEx` was removed, taken over by `TemplateFunctionModel`. `TemplateFunctionModel` is |
| the common interface bith for wrapped Java methods and functions defined in the templates, or on any other ways. |
| `OverloadedMethodsModel` and `SimpleMethodModel` were renamed to `OverloadJavaMethodModel` and `SimpleJavaMethodModel`, |
| which of course extend `TemplateFunctionModel`, but allow inocations without `Environment` parameter. |
| - `org.apache.freemarker.core.util.CallableUtils` was added to help implementing function and directives in Java. |
| - `TemplateModelException` was removed, replaced with `TemplateException` on all places, except for |
| `ObjectWrapper.wrap(Object)` and `wrapAsAPI(Object)`, which now throws `ObjectWrappingException` instead (that extends |
| `TemplateException`). |
| In FM2 it `TemplateModelException` has extended `TemplateException` and was thrown by `TemplateModel` methods. As it |
| has turned out over time, some models call into FreeMarker functionality that can throw `TemplateException`, but the |
| method of the model couldn't throw that as `TemplateModelException` is more specific. Now it can. Also it's not very |
| useful in practice to catch `TemplateModelException` and the more generic `TemplateException` separately, so this |
| simplification was made. |
| - Reworked TemplateModel interfaces: |
| - Reworked callable `TemplateModel`-s (i.e., models that can be called like `foo(...)` or as `<@foo .../>`) |
| - Earlier there were several callable `TemplateModel` internfaces (`TemplateMethodModel`, `TemplateMethodModelEx`, |
| `TemplateDirectiveModel`, `TemplateTransformModel`). FM3 replaces them with only two new interfaces, |
| `TemplateDirectiveModel` (differs from the interface with identical name in FM2) and `TemplateFunctionModel`. |
| (These are both the subinterfaces of another new interface `TemplateCallableModel`.) |
| - All callable TemplateModel-s support passing parameters by position and by name, even in the same call |
| (e.g., `<@heading "Some title" icon="foo.jpg" />`, `sum(1, 2, 3, abs=true)`) |
| - `#macro` now produces a `TemplateDirectiveModel` and `#function` produces a `TemplateFunctionModel`. (Earlier, the |
| product was just a generic `TemplateModel` that could only be invoked using internal API-s, and had capabilities |
| that the callable TemplateModel-s coulnd't have.) |
| - Renamed `TemplateScalarModel` to `TemplateStringModel`. (The `TemplateScalarModel` name come from the early FM, |
| where strings, numbers, booleans, etc. weren't separated.) |
| - Reworked the list-like TemplateModel interfaces: |
| - Renamed `TemplateCollectionModel` to `TemplateIterableModel`, and `TemplateCollectionModelEx` to |
| `TemplateCollectionModel`. (Since java.util.Iterable was added to Java, the TemplateCollectionModel |
| has become an unfortunate name, especailly as later TemplateCollectionModelEx was added, that was closer |
| to java.util.Collection than TemplateCollectionModel.) |
| - `TemplateSequenceModel` now extends `TemplateCollecitonModel`, and `#list` and other built-in mechanims prefer |
| using `iterator()` instead of an index loop. |
| - `TemplateModelIterator.next()` isn't required to handle anymore the case when there's no next item. If someone |
| doesn't check that with `hasNext()` before calling `next()`, anything can happen. This is to allow more efficient |
| implementations, which has become important now that `#list` and such prefers iterators over index loops. |
| - `isEmpty` of FM2 `TemplateCollectionModelEx` (now `TemplateCollectionModel`) and FM2 `TemplateHashModel` was renamed |
| to `isEmptyCollection` and `isEmptyHash`, so that for multi-typed values can give different results depending on the |
| type. Also, for collections `size()` was renamed to `getCollectionSize()`, and for hashes `getHashSize()`. |
| - `TemplateSequenceModel.get(int)` is now expected to actually return `null` for any invalid index. In FM2 this was |
| the documented expectation, but many implementaitons throw exception instead of returning `null`, but FreeMarker |
| has tolerated that. |
| - `TemplateHashModelEx.keys()` and `values()` returns `TemplateCollectoinModel`, just as in FM2, but in FM3 |
| `TemplateCollectoinModel` has `getCollectionSize()` and `isEmptyCollection` method. So this affects |
| `TemplateHashModelEx` implementations as well. |
| - Map-like interfaces: |
| - `TemplateHashModelEx2` was removed, as the `keyValuePairIterator()` method was moved to `TemplateHashModelEx`, |
| so now the two interfaces would be the same. |
| - `TemplateHashModel` doesn't have `isEmpty()` method anymore. (As the point of a pure `TemplateHashModel` is that |
| it's not able to list its keys, almost all `isEmpty()` implementations in FM2 were just dummies returning `false`.) |
| Note that `?hasContent` now returns `true` for `TemplateHashModel` that aren't also `TemplateHashModelEx2`-s, |
| based on the idea that for some `key` (which you may don't know) `get(key)` might return something. |
| - `TemplateModel.NOTHING` was removed without replacement. |
| - BeanModel.keys() and values() are now final methods. Override BeanModel.keySet() and/or get(String) instead. |
| - Methods that return void now return an empty string instead of `TemplateModel.NOTHING` (which was removed). |
| Thus, `${obj.voidReturningMethod()}` still works (it prints nothing, just as in FM2), but things like |
| `x + obj.voidReturningMethod()` now fail (unlike in FM2), as they are probably oversights. This all applies to |
| Java methods wrapped by the DefaultObjectWrapper (which, in FM3, is also used in place of the FM2 BeansWrapper). |
| - Added `null` literal (so null is now a keyword), and TemplateNullModel (it wasn't public in FM2). |
| [TODO] This change is incomplete, and eventually it will mean that the only legal way of representing a |
| Java null where a TemplateModel is expected will be TemplateNullModel.INSTANCE, not a Java null. |
| - Whem listing something that contains a null, reading the loop variable will never fall back to higher scopes |
| (like when configuration.fallbackOnNullLoopVariable was set to false in FM2) |
| |
| Core / Template loading and caching |
| ................................... |
| |
| - Template constructors won't close the Reader passed in as argument anymore (because a Reader should be closed |
| by who has created it). This avoids some surprises from the past, such as the unablility to reset a Reader to a mark |
| after parsing. If you call those constructors, be sure that you close the Reader yourself. (Obviously, it doesn't |
| mater for StringReader-s.) |
| - All CacheStorage-s must be thread safe from now on (removed ConcurrentCacheStorage marker interface) |
| - Configuration.getTemplate has no "parse" parameter anymore. Similarly #include has no "parse" parameter anymore. Whether a |
| template is parsed can be specified via Configuration.templateConfigurations, for example based on the file extension. Thus, |
| a certain template is either always parsed or never parsed, and whoever gets or include it need not know about that. |
| Also added a new setting, "templateLanguage", which decides this; the two available values are |
| TemplateLanguage.FTL and TemplateLanguage.STATIC_TEXT. |
| - Configuration.getTemplate has no "encoding" parameter anymore. (Similarly #include has no "encoding" parameter |
| either). The charset of templates can be specified via Configuration.sourceEncoding and Configuration |
| .templateConfigurations (for example based on the directory it is in), or with the #ftl directive inside the |
| template. Thus, a given template always has the same charset, no mater how it's accessed. |
| - Require customLookupCondition-s to be Serializable. |
| - BeansWrapper.clearClassIntrospecitonCache was renamed to clearClassIntrospectionCache (note the typo) |
| |
| DOM (XML) |
| ......... |
| |
| - Removed NodeModel static utility classes dealing with parsing XML to DOM. How it's best to do that is environment |
| and application dependent, and it has security implications. Since XML loading/parsing is not the topic of the |
| project, these were removed. Static methods that simplify an already loaded DOM have remained, because that's |
| FreeMarker-specific functionality. |
| |
| Servlet |
| ....... |
| |
| - `FreeMarkerServlet` now use a `Configuration.ExtendableBuilder` to provide configuration defaults that makes for it. |
| Its API-s which were used for customizing `FreeMarkerServlet` has bean changed accordingly. |
| |
| Spring |
| ....... |
| |
| This is about the Spring Framework Support (freemarker-spring): FREEMARKER-54, FREEMARKER-55 |
| |
| - ConfigurationFactoryBean, a new Spring Framework's FactoryBean to create Configuration, using Builder. |
| - SpringResourceTemplateLoader, a new TemplateLoader to load templates from Spring Framework's Resources. |
| - New FreeMarkerView and FreeMarkerViewResolver for MVC support. FreeMarkerView supports TaglibFactory and other |
| models by default like FreemarkerServlet does. |
| - Directives and Functions Support to replace Spring JSP Tag Libraries in spring.tld: |
| - <spring:htmlEscape ... /> : No need since FreeMarker Built-In's and escaping directives are better. |
| - <spring:escapeBody ... /> : No need since FreeMarker Built-In's and escaping directives are better. |
| - <spring:message ... /> : Replaced by spring.message function. e.g, ${spring.message(...)} |
| - <spring:theme ... /> : Replaced by spring.theme function. e.g, ${spring.theme(...)} |
| - <spring:argument ... /> : No need since spring.message(...) and spring.theme(...) functions support |
| positional varargs for variable length arguments. |
| - <spring:hasBindErrors ... /> : Replaced by <@spring.hasBindErrors ... /> directive. |
| - <spring:nestedPath ... /> : Replaced by <@spring.nestedPath ... /> directive. |
| - <spring:bind ... /> : Replaced by <@spring.bind ... /> directive. |
| - <spring:transform ... /> : Replaced by spring.transform(...) function. |
| - <spring:url ... /> : Replaced by spring.url(...) function. |
| - <spring:param ... /> : No need since spring.url(...) function supports named vargs for variable length parameters. |
| - <spring:eval /> : Replaced by spring.eval(...) function. |
| - Directives Support to replace Spring Form JSP Tag Libraries in spring-form.tld: |
| - <form:form ... /> : Replaced by <@form.form ... /> directive. |
| - <form:input ... /> : Replaced by <@form.input ... /> directive. |
| - <form:password ... /> : Replaced by <@form.password ... /> directive. |
| - <form:textarea ... /> : Replaced by <@form.textarea ... /> directive. |
| - <form:hidden ... /> : Replaced by <@form.hidden ... /> directive. |
| - <form:button ... /> : Replaced by <@form.button ... /> directive. |
| - <form:label ... /> : Replaced by <@form.label ... /> directive. |
| - <form:errors ... /> : Replaced by <@form.errors ... /> directive. |
| - <form:select ... /> : Replaced by <@form.select ... /> directive. |
| - <form:option ... /> : Replaced by <@form.option ... /> directive. |
| - <form:options ... /> : Replaced by <@form.options ... /> directive. |
| - <form:checkbox ... /> : Replaced by <@form.checkbox ... /> directive. |
| - <form:checkboxes ... /> : Replaced by <@form.checkboxes ... /> directive. |
| - <form:radiobutton ... /> : Replaced by <@form.radiobutton ... /> directive. |
| - <form:radiobuttons ... /> : Replaced by <@form.radiobuttons ... /> directive. |
| |
| Core / Miscellaneous |
| .................... |
| |
| - Minimum Java version increased to 17 |
| - Removed support for incompatibleImprovements before 3.0.0. So currently 3.0.0 is the only support value. |
| - Removed legacy extensions (so these have no module): rhino, jython, xml (not to be confused with dom), jdom, ant. |
| - Servlet 3.1 and JSP 2.3 and is the minimum requirement now (if Serlvet/JSP features are used at all). |
| - Log categories are now simply the full qualified class name of the logging classes. There are no predefined log |
| categories (such as "freemarker.runtime", etc.) anymore. This is to follow the common practices in logging. |
| - #include-d/#import-ed templates don't inherit the charset (encoding) of the #include-ing/#import-ing template. |
| (Because, the charset of a template file is now independent of how you access it; see in template loading changes.) |
| - #attempt doesn't create an additional debug level log entry when an exception is catched. It only |
| log an error level log (by default at least; see the `attemptExceptionReporter` setting) |
| - Marked most static utility classes as internal, and renamed them to start with "_" (for example StringUtils was |
| renamed to _StringUtil, thus people won't accidentally use it when they wanted to autocomplete to Apache Commons |
| StringUtil). Created published static utility class, o.a.f.core.util.FTLUtil, which contains some methods moved |
| over from the now internal utility classes. |
| - Template.sourceEncoding was renamed to Template.actualSourceEncoding, to emphasize that it's not the template-layer |
| equivalent of the sourceEncoding ParserConfiguration setting. This is in line with Template.actualTagSyntax and the |
| other "actual" properties. (Just as in FM2, Template.getParserConfiguration() still can be used get the |
| sourceEncoding used during parsing.) |
| - Template.name (getName()) was renamed to Template.lookupName (getLookupName()), and Template.sourceName (Template.getSourceName()) |
| doesn't fall back to the lookup name anymore when it's null (however, Template.getSourceOrLookupName() was added for that). There's |
| no Template.name anymore, because since sourceName was introduced, and hence the concept of template name was split into the |
| lookup and the source name, its meaning wasn't clean (but it meant the lookup name). TemplateException and ParseException |
| now also have the same properites: getTemplateSourceName(), getTemplateLookupName(), and even getSourceOrLookupName(). |
| Location information in error messages show getTemplateSourceOrLookupName(). |
| - Removed all classes with "main" methods that were part of freemarker.jar. Such tools should be separate artifacts, |
| not part of the library, and they are often classified as CWE-489 "Leftover Debug Code". The removed classes are: |
| freemarker.core.CommandLine, freemarker.ext.dom.Transform, freemarker.template.utility.ToCanonical |
| - Removed classic_compatible (classicCompatible) setting, which was used to emulate some of the FreeMarker 1.x behavior |
| - Removed utility TemplateModel-s that can very easily mean a security problem: freemarker.template.utility.Execute and |
| freemarker.template.utility.ObjectConstructor |
| - Removed ResourceBundleLocalizedString and LocalizedString: Hardly anybody has discovered these, and they had no |
| JUnit coverage. |
| - Deleted o.a.f.core.util.DOMNodeModel (it has noting to do with the standard XML support, o.a.f.core.model.dom) |
| - Removed deprecated FMParser constructors. |
| - Removed Template.templateLanguageVersion, as we solely rely on incompatibleImprovements instead. |
| - Made TemplateModel classes used by the parser for literals Serializable. (Without this attribute values set in the |
| `#ftl` header wouldn't be always Serializable, which in turn will sabotage making Template-s Serializable in the |
| future.) |
| - util.ObjectFactory was renamed to CommonSupplier, and its createObject() method was renamed to |
| get(), to be more similar to the Java 8 API. |
| - Removed the legacy predefined shared variables: "html_escape", "normalize_newlines", "xml_escape", "capture_output", |
| "compress" |
| - Removed `NestedContentNotSupportedException`, as `TemplateDirectiveModel.isNestedContentSupported()` now takes care |
| of that problem. |
| - CallPlaceCustomDataInitializationException is not a checked exception anymore (now it extends RuntimeException) |
| - Renamed `FTLUtil` to `TemplateLanguageUtils` (as the FTL name will be abandoned in FM3, and supporting multiple |
| languages are planned in the future) |
| - Removed `UnexpectedTypeException` (a `TemplateException` subclass) and its subclasses (`NonStringException`, etc.), |
| using simple `TemplateException` instead. Catching these exceptions specifically wasn't very useful, while they |
| have bloated the public API (and the code). |
| - Added `org.apache.freemarker.core.util.CallableUtils`, to help in implementing (and invoking) `TemplateCallableModel`-s. |
| - Renamed `Environment.getDataModel()` to `getDataModelWithSharedVariableFallback()` |
| Renamed `Environment.getGlobalVariables()` to `getGloballyVisibleVariables()()` |
| - Removed `Template.createPlainTextTemplate`, as this convenience methods was hardly ever used. |
| - The extended BigDecimal format parser doesn't accept the "multipier" parameter name anymore. It has to be written with |
| correct spelling, as "multiplier". |
| - The booleanFormat setting now defaults to "", just like numberFormat, etc. It's not possible to format a boolean with |
| that setting value, it will give an error. On the other hand, "true,false" is now a legit setting value (although the |
| better practice is to set the format to "c", if you generate computer language output), but it's hardly a good practice |
| to use. |