| <!doctype html> |
| <!-- Generated by FreeMarker/Docgen from DocBook --> |
| <html lang="en" class="page-type-section"> |
| <head prefix="og: http://ogp.me/ns#"> |
| <meta charset="utf-8"> |
| <title>2.3.22 - Apache FreeMarker Manual</title> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <meta name="format-detection" content="telephone=no"> |
| <meta property="og:site_name" content="Apache FreeMarker Manual"> |
| <meta property="og:title" content="2.3.22"> |
| <meta property="og:locale" content="en_US"> |
| <meta property="og:url" content="https://freemarker.apache.org/docs/versions_2_3_22.html"> |
| <link rel="canonical" href="https://freemarker.apache.org/docs/versions_2_3_22.html"> |
| <link rel="icon" href="favicon.png" type="image/png"> |
| <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto:500,700,400,300|Droid+Sans+Mono"> |
| <link rel="stylesheet" type="text/css" href="docgen-resources/docgen.min.css?1707770044859"> |
| <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/cookie-bar/cookiebar-latest.min.js"></script> |
| </head> |
| <body itemscope itemtype="https://schema.org/Code"> |
| <meta itemprop="url" content="https://freemarker.apache.org/docs/"> |
| <meta itemprop="name" content="Apache FreeMarker Manual"> |
| |
| <!--[if lte IE 9]> |
| <div class="oldBrowserWarning" style="display: block"> |
| Unsupported web browser - Use a modern browser to view this website! |
| </div> |
| <![endif]--> <div class="oldBrowserWarning"> |
| Unsupported web browser - Use a modern browser to view this website! |
| </div> |
| <div class="header-top-bg"><div class="site-width header-top"><div id="hamburger-menu" role="button"></div> <div class="logo"> |
| <a href="https://freemarker.apache.org" role="banner"><img itemprop="image" src="logo.png" alt="FreeMarker"></a> </div> |
| <ul class="tabs"><li><a href="https://freemarker.apache.org/">Home</a></li><li class="current"><a href="index.html">Manual</a></li><li><a class="external" href="api/index.html">Java API</a></li></ul><ul class="secondary-tabs"><li><a class="tab icon-heart" href="https://freemarker.apache.org/contribute.html" title="Contribute"><span>Contribute</span></a></li><li><a class="tab icon-bug" href="https://issues.apache.org/jira/projects/FREEMARKER" title="Report a Bug"><span>Report a Bug</span></a></li><li><a class="tab icon-download" href="https://freemarker.apache.org/freemarkerdownload.html" title="Download"><span>Download</span></a></li></ul></div></div><div class="header-bottom-bg"><div class="site-width search-row"><a href="index.html" class="navigation-header">Manual</a><div class="navigation-header"></div><form method="get" class="search-form" action="search-results.html"><fieldset><legend class="sr-only">Search form</legend><label for="search-field" class="sr-only">Search query</label><input id="search-field" name="q" type="search" class="search-input" placeholder="Search" spellcheck="false" autocorrect="off" autocomplete="off"><button type="submit" class="search-btn"><span class="sr-only">Search</span></button></fieldset></form></div><div class="site-width breadcrumb-row"> <div class="breadcrumbs"> |
| <ul class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList"><li class="step-0" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="index.html"><span itemprop="name">Apache FreeMarker Manual</span></a></li><li class="step-1" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="app.html"><span itemprop="name">Appendixes</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="app_versions.html"><span itemprop="name">Version history</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="versions_2_3_22.html"><span itemprop="name">2.3.22</span></a></li></ul> </div> |
| <div class="bookmarks" title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul><li><a href="alphaidx.html">Alpha. index</a></li><li><a href="gloss.html">Glossary</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions</a></li><li><a href="ref_builtins_alphaidx.html">?builtins</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_specvar.html">.spec_vars</a></li><li><a href="app_faq.html">FAQ</a></li></ul></div></div></div> <div class="main-content site-width"> |
| <div class="content-wrapper"> |
| <div id="table-of-contents-wrapper" class="col-left"> |
| <script>var breadcrumb = ["Apache FreeMarker Manual","Appendixes","Version history","2.3.22"];</script> |
| <script src="toc.js?1707770044859"></script> |
| <script src="docgen-resources/main.min.js?1707770044859"></script> |
| </div> |
| <div class="col-right"><div class="page-content"><div class="page-title"><div class="pagers top"><a class="paging-arrow previous" href="versions_2_3_23.html"><span>Previous</span></a><a class="paging-arrow next" href="versions_2_3_21.html"><span>Next</span></a></div><div class="title-wrapper"> |
| <h1 class="content-header header-section1" id="versions_2_3_22" itemprop="headline">2.3.22</h1> |
| </div></div><div class="page-menu"> |
| <div class="page-menu-title">Page Contents</div> |
| <ul><li><a class="page-menu-link" href="#autoid_176" data-menu-target="autoid_176">Changes on the FTL side</a></li><li><a class="page-menu-link" href="#autoid_177" data-menu-target="autoid_177">Changes on the Java side</a></li><li><a class="page-menu-link" href="#autoid_178" data-menu-target="autoid_178">Notes</a></li></ul> </div><p>Date of release: 2015-03-01</p><p>Note that since 2.3.22 is designed to be fully backward |
| compatible with the previous 2.3.x releases, <em>some of the |
| improvements and fixes described below are only activated when you |
| specifically ask for 2.3.22 "incompatible |
| improvements"</em> (it's always clearly indicated), |
| because they could, with very small chance, break existing |
| applications. For actively maintained applications it's probably |
| better to allow them. See <a href="pgui_config_incompatible_improvements.html#pgui_config_incompatible_improvements_how_to_set">how to set |
| "incomplatible improvements" here</a>.</p> |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_176">Changes on the FTL side</h2> |
| |
| |
| <ul> |
| <li> |
| <p>New built-ins: <code class="inline-code">api</code> and |
| <code class="inline-code">has_api</code>. |
| <code class="inline-code"><em class="code-color">value</em>?api</code> provides |
| access to the API (usually, the Java API) of |
| <code class="inline-code"><em class="code-color">value</em></code>, like |
| <code class="inline-code"><em class="code-color">value</em>?api.<em class="code-color">someJavaMethod()</em></code> |
| or |
| <code class="inline-code"><em class="code-color">value</em>?api.<em class="code-color">someBeanProperty</em></code>), |
| if the value itself supports exposing its API. This meant to be |
| used rarely, when you need to call a Java method of an object, |
| but the by-design simplistic view of the value that FreeMarker |
| exposes to the templates hides that, and there's no equivalent |
| built-in either. For example, when you put a |
| <code class="inline-code">Map</code> into the data-model (and you are using |
| the default object wrapper), <code class="inline-code">myMap.myMethod()</code> |
| in a template basically translates to <code class="inline-code">((Method) |
| myMap.get("myMethod")).invoke(...)</code> in Java, thus you |
| can't call <code class="inline-code">myMethod</code>. If, however, you write |
| <code class="inline-code">myMap?api.myMethod()</code> instead, that means |
| <code class="inline-code">myMap.myMethod()</code> in Java. Similarly, |
| <code class="inline-code">myMap?api.myProperty</code> translates to |
| <code class="inline-code">myMap.getMyProperty()</code> in Java, instead of to |
| <code class="inline-code">myMap.get("myProperty")</code>.</p> |
| |
| <p><em>If you can, rely on the capabilities of the FTL |
| types and the related built-ins as far as possible. Using |
| <code class="inline-code">?api</code> is only the last |
| resort.</em></p> |
| |
| <p>Using <code class="inline-code">?api</code> also happens to offer a |
| workaround for the lack of non-<code class="inline-code">String</code> |
| <code class="inline-code">Map</code> key support in FTL's |
| <code class="inline-code">[]</code> operator (as in |
| <code class="inline-code">myMap[key]</code>), because now you can write |
| <code class="inline-code">myMap?api.get(nonStringKey)</code>.</p> |
| |
| <p><code class="inline-code">?api</code> is not enabled by default and |
| isn't available for all values. <a href="ref_builtins_expert.html#ref_buitin_api_and_has_api">See more |
| here...</a></p> |
| </li> |
| |
| <li> |
| <p>Identifiers (like <code class="inline-code">someVariable</code>) can now |
| contain minus (<code class="inline-code">-</code>), dot |
| (<code class="inline-code">.</code>), and colon (<code class="inline-code">:</code>) at any |
| position, but those characters <em>must be escaped with a |
| preceding backslash</em> (<code class="inline-code">\</code>), or else |
| they would be interpreted as operators. For example, to read the |
| variable whose name is "data-id", the correct |
| expression is <code class="inline-code">data\-id</code>, as |
| <code class="inline-code">data-id</code> would be interpreted as "data |
| minus id". This also works for named macro parameters, |
| which is useful when you want to accept arbitrary HTML |
| attributes in a catch-all parameter, like in <code class="inline-code"><@box |
| class="someCssClass" data\-id=product.id /></code>. (When |
| you enumerate the catch-all parameter names inside the macro, |
| the key string you get is <code class="inline-code">"data-id"</code> without |
| <code class="inline-code">\</code> of course.)</p> |
| </li> |
| |
| <li> |
| <p>Added <code class="inline-code">?lower_abc</code> and |
| <code class="inline-code">?upper_abc</code>. This converts |
| <code class="inline-code">1</code>, <code class="inline-code">2</code>, |
| <code class="inline-code">3</code>, etc., to the string |
| <code class="inline-code">"a"</code>, <code class="inline-code">"b"</code>, |
| <code class="inline-code">"c"</code>, etc. (or for <code class="inline-code">"A"</code>, |
| <code class="inline-code">"B"</code>, <code class="inline-code">"C"</code>, etc.). When |
| reaching <code class="inline-code">"z"</code>, it continues like |
| <code class="inline-code">"aa"</code>, <code class="inline-code">"ab"</code>, etc. This is |
| the same logic that you can see in column labels in spreadsheet |
| applications (like Excel or Calc). <a href="ref_builtins_number.html#ref_builtin_lower_abc">More details...</a></p> |
| </li> |
| |
| <li> |
| <p>Added <code class="inline-code">?keep_before_last</code> and |
| <code class="inline-code">?keep_after_last</code>. Example: |
| <code class="inline-code">"foo.bar.txt"?keep_before_last(".")</code> returns |
| <code class="inline-code">"foo.bar"</code>, |
| <code class="inline-code">"foo.bar.txt"?keep_after_last(".")</code> returns |
| <code class="inline-code">"txt"</code>. (These work like |
| <code class="inline-code">?keep_before</code> and |
| <code class="inline-code">?keep_after</code>, but those look for the first |
| occurrence of the separator.)</p> |
| </li> |
| |
| <li> |
| <p>Added many missing UNICODE letters and digits to the set |
| of legal identifier characters, like Korean letters (bug fixed: |
| [<a href="https://sourceforge.net/p/freemarker/bugs/129/">129</a>])</p> |
| </li> |
| |
| <li> |
| <p>Error message quality improvements:</p> |
| |
| <ul> |
| <li> |
| <p>Several improvements when calling custom JSP tags; see |
| them in its own section later.</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed: When localized lookup or template |
| acquisition has kicked in, error messages have still quoted |
| the name used for requesting the template, rather that the |
| actual template source name (like <code class="inline-code">foo.ftl</code> |
| instead of <code class="inline-code">foo_en.ftl</code>, when the template |
| was get as <code class="inline-code">foo.ftl</code>, but behind the scenes |
| was loaded from <code class="inline-code">foo_en.ftl</code>).</p> |
| </li> |
| |
| <li> |
| <p>"Template not found" errors are now more |
| detailed, giving hints about accidentally using |
| <code class="inline-code">\</code> instead of <code class="inline-code">/</code>, or |
| backing out of the <code class="inline-code">TemplateLoader</code>'s root |
| directory.</p> |
| </li> |
| |
| <li> |
| <p>The <code class="inline-code">#setting</code> directive gives more |
| helpful error message when the setting name is not |
| recognized, and lists the allowed setting names or a |
| correction suggestion.</p> |
| </li> |
| |
| <li> |
| <p>When a bad special variable name |
| (<code class="inline-code">.<em class="code-color">name</em></code>) is |
| encountered, the list of available names is shown in the |
| error message.</p> |
| </li> |
| |
| <li> |
| <p>When <code class="inline-code">Map.get</code> or |
| <code class="inline-code">Map.containsKey</code> of a wrapped |
| <code class="inline-code">Map</code> throws a |
| <code class="inline-code">ClassCastException</code> or |
| <code class="inline-code">NullPointerException</code>, the error will |
| point to the causing FTL expression (with some explanation), |
| rather than bubbling up as low level runtime error.</p> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_177">Changes on the Java side</h2> |
| |
| |
| <ul> |
| <li> |
| <p>Object wrapping improvements:</p> |
| |
| <ul> |
| <li> |
| <p><code class="inline-code">DefaultObjectWrapper</code>, only with its |
| <code class="inline-code">incompatible_improvements</code> set to 2.3.22 |
| (<a href="pgui_datamodel_objectWrapper.html#topic.defaultObjectWrapperIcI">see how |
| here...</a>), or more precisely, with its new |
| <code class="inline-code">useAdaptersForContainers</code> setting set to |
| <code class="inline-code">true</code> (which defaults to |
| <code class="inline-code">true</code> when |
| <code class="inline-code">incompatible_improvements</code> is set to |
| 2.3.22): It doesn't copy <code class="inline-code">Map</code>-s, |
| <code class="inline-code">List</code>-s, and arrays anymore when wrapping |
| them into <code class="inline-code">TemplateModel</code>-s (which is the |
| interface through with templates access all values), just |
| wraps them into thin <code class="inline-code">TemplateModel</code> |
| adapters, that will reach the original object for all |
| operations. The wrapped values will be instances of the new |
| <code class="inline-code">DefaultMapAdapter</code>, |
| <code class="inline-code">DefaultListAdapter</code> and |
| <code class="inline-code">DefaultArrayAdapter</code> classes, instead of |
| the legacy (copying) <code class="inline-code">SimpleHash</code> and |
| <code class="inline-code">SimpleSequence</code> classes. (Note that many |
| projects use pure <code class="inline-code">BeansWrapper</code> instead of |
| <code class="inline-code">DefaultObjectWrapper</code>, which has always |
| used the adapter approach, albeit a different implementation |
| of it. As the shortcomings of |
| <code class="inline-code">DefaultObjectWrapper</code> are fixed now, it's |
| always recommended over <code class="inline-code">BeansWrapper</code>, as |
| <code class="inline-code">BeansWrapper</code> gives quite confusing |
| multi-typed values and is substantially slower.)</p> |
| |
| <p>While keeping backward compatibility as much as |
| possible was an important factor in this change, this is a |
| quite deep change, so you may want to <a href="#topic.defaultObjectWrapperSwitchToAdapters">review |
| the consequences and reasons here...</a> (But again, this |
| change is <em>not</em> active by default, so |
| merely updating FreeMarker wont risk the stability of |
| existing applications)</p> |
| </li> |
| |
| <li> |
| <p>Added <code class="inline-code">TemplateMethodModelEx |
| BeansWrapper.wrap(Object object, Method method)</code> |
| for wrapping methods without wrapping their parent object |
| and without going through overloaded method selection on |
| invocation time.</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed [<a href="http://sourceforge.net/p/freemarker/bugs/372/">372</a>]: |
| <code class="inline-code">ClassCastException</code> when a |
| <code class="inline-code">SortedMap</code> (typically, a |
| <code class="inline-code">TreeMap</code>) is wrapped with |
| <code class="inline-code">DefaultObjectWrapper</code> and then a 1 |
| character long string is get from it that doesn't exist. To |
| fix the issue, if the wrapped <code class="inline-code">Map</code> is a |
| <code class="inline-code">SortedMap</code> and it's wrapped by |
| <code class="inline-code">DefaultObjectWrapper</code>, it won't try to |
| fall back to a <code class="inline-code">Character</code> key after with |
| the <code class="inline-code">String</code> key has got |
| <code class="inline-code">null</code>. (This change should be backward |
| compatible, because when a <code class="inline-code">SortedMap</code> has |
| <code class="inline-code">Character</code> keys, the initial attempt with |
| <code class="inline-code">String</code> key causes |
| <code class="inline-code">ClassCastException</code>, thus, such |
| <code class="inline-code">SortedMap</code>-s were never usable as FTL |
| hashes.)</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed [<a href="http://sourceforge.net/p/freemarker/bugs/368/">368</a>]: |
| Only with <code class="inline-code">incompatible_improvements</code> set |
| to 2.3.22 or with its new |
| <code class="inline-code">useAdaptersForContainers</code> setting set to |
| <code class="inline-code">true</code>: Key order and other behavioral |
| peculiarities of "custom" |
| <code class="inline-code">Map</code> types isn't lost anymore. The same |
| stands for <code class="inline-code">List</code>-s too.</p> |
| </li> |
| |
| <li> |
| <p>Added new setting, |
| <code class="inline-code">forceLegacyNonListCollections</code>. This only |
| matters when <code class="inline-code">useAdaptersForContainers</code> is |
| <code class="inline-code">true</code>. Then, unless you set this to |
| <code class="inline-code">true</code>, |
| <code class="inline-code">java.util.Collection</code>-s that aren't |
| <code class="inline-code">List</code>-s (like <code class="inline-code">Set</code>-s) |
| will continue using <code class="inline-code">SimpleSequence</code> (i.e., |
| the copying approach) instead of the adapter approach. The |
| default is <code class="inline-code">false</code>, at least until |
| <code class="inline-code">incompatible_improvements</code> 2.4.0, because |
| <code class="inline-code">SimpleSequence</code> gave indexed access to |
| these non-<code class="inline-code">List</code>-s, like in |
| <code class="inline-code">mySet[2]</code>, which is strange but some |
| existing templates may utilize this, even if only |
| accidentally. With |
| <code class="inline-code">forceLegacyNonListCollections</code> set to |
| <code class="inline-code">false</code>, indexed access won't be possible |
| for <code class="inline-code">Set</code>-s and such anymore (nor will |
| <code class="inline-code">?first</code> and <code class="inline-code">?last</code> work, |
| but <code class="inline-code">?size</code> will still do), so you may want |
| to retest old templates. On the other hand, you get the |
| advantages of the adapter approach. Hence, in new projects |
| it's highly recommended to set |
| <code class="inline-code">forceLegacyNonListCollections</code> to |
| <code class="inline-code">false</code>. (The adapter approach is |
| implemented by |
| <code class="inline-code">DefaultNonListCollectionAdapter</code>.)</p> |
| </li> |
| |
| <li> |
| <p>Added new, <em>experimental</em> FTL type |
| interface, |
| <code class="inline-code">freemarker.template.TemplateCollectionModelEx</code>, |
| which adds the <code class="inline-code">size()</code>, |
| <code class="inline-code">isEmpty()</code>, and <code class="inline-code">boolean |
| contains(TemplateModel)</code> methods to the |
| <code class="inline-code">TemplateCollectionModel</code> interface. This |
| was added because when wrapping |
| <code class="inline-code">java.util.Collections</code> these extra |
| capabilities area available anyway, but FTL couldn't tap on |
| them till now. While the exact interface details are marked |
| as experimental, the feature itself is already utilized for |
| <code class="inline-code">?size</code> when setting the |
| <code class="inline-code">forceLegacyNonListCollections</code> property of |
| <code class="inline-code">DefaultObjectWrapper</code> to |
| <code class="inline-code">false</code> (see earlier).</p> |
| </li> |
| |
| <li> |
| <p>Added new <em>experimental</em> interface, |
| <code class="inline-code">freemarker.template.ObjectWrapperAndUnwrapper</code>. |
| This extends <code class="inline-code">ObjectWrapper</code> with |
| unwrapping functionality. This functionality has already |
| existed for a long time in <code class="inline-code">BeansWrapper</code> |
| and its subclasses, like in |
| <code class="inline-code">DefaultObjectWrapper</code>, but it wasn't |
| "factored out" into its own published interface |
| that other <code class="inline-code">ObjectWrapper</code>-s could |
| implement. This is useful for |
| <code class="inline-code">TemplateModel</code> implementations that don't |
| want to require a <code class="inline-code">BeansWrapper</code> (or its |
| subclass), only the availability of the unwrapping |
| functionality.</p> |
| </li> |
| |
| <li> |
| <p>Added new <em>experimental</em> interfaces |
| to implement <code class="inline-code">?api</code> (see it in the FTL |
| section): <code class="inline-code">TemplateModelWithAPISupport</code>, |
| <code class="inline-code">ObjectAPIWrapper</code>, |
| <code class="inline-code">RichObjectWrapper</code>. Note that while the |
| interfaces are experimental, <code class="inline-code">?api</code> itself |
| isn't.</p> |
| </li> |
| </ul> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">FreemarkerServlet</code> improvements:</p> |
| |
| <ul> |
| <li> |
| <p><code class="inline-code">FreemarkerServlet</code> now supports |
| custom JSP EL functions (defined in TLD-s with |
| <code class="inline-code">function</code> XML elements). Earlier it has |
| ignored them. The custom EL function can be called like a |
| Java method, for example: <code class="inline-code"><#assign |
| u=JspTaglibs["/WEB-INF/utils.tld"]> ... |
| ${u.truncate(title, 25)}</code>.</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed: Error message was unhelpful when there was |
| a type mismatch between the actual and the expected type of |
| a custom tag parameter. This was a very frequent problem of |
| users who call JSP taglibs from FTL (the typical |
| "java.lang.IllegalArgumentException: argument type |
| mismatch", without any FTL context). Now it's a proper error |
| with explanation, solution tip, and FTL error |
| position/quotation.</p> |
| </li> |
| |
| <li> |
| <p>RFE resolved [<a href="https://sourceforge.net/p/freemarker/feature-requests/113/">113</a>] |
| [<a href="https://sourceforge.net/p/freemarker/feature-requests/114/">114</a>]: |
| <code class="inline-code">FreemarkerServlet</code> can now discover |
| <code class="inline-code">META-INF/**/*.tld</code>-s that are visible for |
| the class loader but aren't in |
| <code class="inline-code">WEB-INF/lib/*.jar</code>-s. For this feature to |
| be active, you must setup the extra TLD lookup with the |
| <code class="inline-code">MetaInfTldSources</code> and/or |
| <code class="inline-code">ClasspathTlds</code> |
| <code class="inline-code">FreemarkerServlet</code> init-params (see the |
| <a href="https://freemarker.apache.org/docs/api/freemarker/ext/servlet/FreemarkerServlet.html">Java |
| API documentation of |
| <code>FreemarkerServlet</code></a> for the |
| description of these). For example, if you run your |
| application from Eclipse with an embedded Servlet container, |
| and thus the tag library jar-s aren't on the standard |
| locations but are in the classpath like any other |
| dependencies, now you can just write:</p> |
| |
| |
| |
| <div class="code-block role-unspecified"> |
| <pre class="code-block-body"><init-param> |
| <param-name>MetaInfTldSources</param-name> |
| <param-value>classpath</param-value> |
| </init-param></pre> </div> |
| |
| |
| <p>and then all the <code class="inline-code">META-INF</code> |
| directories that are visible for the class loader will be |
| searched for TLD-s.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">MetaInfTldSources</code> and |
| <code class="inline-code">ClasspathTlds</code> can also be appended to or |
| replaced by the values of Java system properties |
| <code class="inline-code">org.freemarker.jsp.metaInfTldSources</code> and |
| <code class="inline-code">org.freemarker.jsp.classpathTlds</code>, |
| respectively. Thus one can adjust these in the Eclipse run |
| configuration without modifying the |
| <code class="inline-code">web.xml</code>. (See the <a href="https://freemarker.apache.org/docs/api/freemarker/ext/servlet/FreemarkerServlet.html">Java |
| API documentation of |
| <code>FreemarkerServlet</code></a> for |
| more.)</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">FreemarkerServlet</code> now recognizes |
| the |
| <code class="inline-code">org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</code> |
| servlet context attribute, and adds entries to |
| <code class="inline-code">MetaInfTldSources</code> (introduced above) from |
| it.</p> |
| </li> |
| |
| <li> |
| <p>Added <code class="inline-code">protected |
| FreemarkerServlet.createTaglibFactory()</code> to allow |
| fine tuning the settings of the |
| <code class="inline-code">TaglibFactory</code>. It now have a few setters, |
| like <code class="inline-code">setObjectWrapper</code>, |
| <code class="inline-code">setMetaInfTldSource</code>, etc.</p> |
| </li> |
| |
| <li> |
| <p>Added new servlet init-param, |
| <code class="inline-code">BufferSize</code>. This sets the buffer size via |
| <code class="inline-code">HTTPServletResponse.setBufferSize()</code> if |
| the response state still allows that, ignores it |
| otherwise.</p> |
| </li> |
| |
| <li> |
| <p>The <code class="inline-code">TemplatePath</code> servlet init-param |
| now supports a new kind of path, that looks like |
| <code class="inline-code">classpath:com/example/myapp/templates</code>. |
| This is similar to the old |
| <code class="inline-code">class://com/example/myapp/templates</code>, but |
| it uses the Thread Context Class Loader of the thread that |
| initializes <code class="inline-code">FreemarkerSerlvet</code>, and thus |
| will work even if <code class="inline-code">freemarker.jar</code> is not |
| local to the web application. <code class="inline-code">class://</code> |
| has the problem that it uses the defining class loader of |
| <code class="inline-code">FreemarkerSerlvet</code> itself (or of its |
| subclass).</p> |
| </li> |
| |
| <li> |
| <p>If <code class="inline-code">incompatible_improvements</code> is set |
| to 2.3.22 (or higher), the <code class="inline-code">TemplatePath</code> |
| servlet init-param supports specifying multiple comma |
| separated paths inside |
| <code class="inline-code">[<em class="code-color">...</em>]</code>, like |
| <code class="inline-code"><param-value>[ WEB-INF/templates, |
| classpath:com/example/myapp/templates |
| ]</param-value></code>. This internally creates a |
| <code class="inline-code">freemarker.cache.MultiTemplateLoader</code>.</p> |
| </li> |
| |
| <li> |
| <p>Added new servlet <code class="inline-code">init-param</code>, |
| <code class="inline-code">ExceptionOnMissingTemplate</code>. Setting this |
| to <code class="inline-code">true</code> changes the behavior on |
| template-not-found errors to similar to what you experience |
| with other kind of template exceptions (a HTTP 500 |
| "Internal Server error" response on most |
| setups). When it's <code class="inline-code">false</code> (the legacy |
| behavior), you only get a HTTP 404 "Not found". |
| While that's also how JSP views work, this turns out to be a |
| problem, because some frameworks give 404 to the visitor too |
| if the MVC view gives 404. But to get to the point where you |
| forward to the MVC View, the visitor had to visit a valid |
| URL, only that page misses its View, so its broken on the |
| server side, so it should be a 500.</p> |
| </li> |
| |
| <li> |
| <p>Added new overridable method: |
| <code class="inline-code">FreemarkerServlet.createDefaultObjectWrapper()</code>. |
| This can be used for what |
| <code class="inline-code">createObjectWrapper()</code> is usually |
| overridden for, but without unwillingly disabling the |
| processing of the related init-params (like of |
| <code class="inline-code">object_wrapper</code>).</p> |
| </li> |
| |
| <li> |
| <p>Improved (or fixed) error logging: Now logs will |
| always get into FreeMarker's own log, not only into the |
| servlet container log. Also, earlier template-not-found and |
| template parsing error details logs were sometimes lost, |
| depending on the servlet container.</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed, only active with |
| <code class="inline-code">incompatible_improvements</code> set to 2.3.22 |
| (or higher): Some kind of values, when put into the JSP |
| <em>page</em> scope (via |
| <code class="inline-code">#global</code> or via the JSP |
| <code class="inline-code">PageContext</code> API) and later read back with |
| the JSP <code class="inline-code">PageContext</code> API (typically in a |
| custom JSP tag), might come back as FreeMarker |
| <code class="inline-code">TemplateModel</code> objects instead of as |
| objects with a standard Java type. Other Servlet scopes |
| aren't affected. It's highly unlikely that something expects |
| the presence of this bug. The affected values are of the FTL |
| types listed below, and to trigger the bug, they either had |
| to be created directly in the template (like as an FTL |
| literal or with |
| <code class="inline-code">?date</code>/<code class="inline-code">time</code>/<code class="inline-code">datetime</code>), |
| or you had to use <code class="inline-code">DefaultObjectWrapper</code> or |
| <code class="inline-code">SimpleObjectWrapper</code> (or a subclass of |
| them):</p> |
| |
| <ul> |
| <li> |
| <p>FTL date/time/date-time values may came back as |
| <code class="inline-code">freemarker.template.SimpleDate</code>-s, now |
| they come back as <code class="inline-code">java.util.Date</code>-s |
| instead.</p> |
| </li> |
| |
| <li> |
| <p>FTL sequence values may came back as |
| <code class="inline-code">SimpleSequence</code>-s, now they come back |
| as <code class="inline-code">java.util.List</code>-s as expected. This |
| stands assuming that the |
| <code class="inline-code">object_wrapper</code> configuration setting |
| is a subclass of <code class="inline-code">BeansWrapper</code> (such |
| as <code class="inline-code">DefaultObjectWrapper</code>), but that's |
| practically always the case in applications that use |
| FreeMarker's JSP extension (otherwise it can still work, |
| but it depends on the quality and capabilities of the |
| <code class="inline-code">ObjectWrapper</code> implementation).</p> |
| </li> |
| |
| <li> |
| <p>FTL hash values may came back as |
| <code class="inline-code">SimpleHash</code>-es, now they come back as |
| <code class="inline-code">java.util.Map</code>-s as expected (again, |
| assuming that the object wrapper is a subclass of |
| <code class="inline-code">BeansWrapper</code>).</p> |
| </li> |
| |
| <li> |
| <p>FTL collection values may came back as |
| <code class="inline-code">SimpleCollection</code>-s, now they come |
| back as <code class="inline-code">java.util.Collection</code>-s as |
| expected (again, assuming that the object wrapper is a |
| subclass of <code class="inline-code">BeansWrapper</code>).</p> |
| </li> |
| </ul> |
| </li> |
| |
| <li> |
| <p>Bug fixed: Now <code class="inline-code">*.tld</code> files are |
| searched in <code class="inline-code">WEB-INF/</code> and in all its |
| subdirectories recursively. Earlier they were only searched |
| directly under <code class="inline-code">WEB-INF/</code> and |
| <code class="inline-code">WEB-INF/lib/</code>.</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed: Leading and trailing whitespace in TLD-s |
| inside the <code class="inline-code">name</code> and |
| <code class="inline-code">tag-class</code> elements is now removed.</p> |
| </li> |
| |
| <li> |
| <p>Unwanted behavior fixed: In case multiple TLD-s map to |
| the same tag library URI, now |
| <code class="inline-code">WEB-INF/**/*.tld</code>-s has priority over |
| <code class="inline-code">META-INF/**/*.tld</code>-s coming from jar-s or |
| classpath directories. Earlier, it was the other way around, |
| except that <code class="inline-code">META-INF/lib/*.tld</code>-s could |
| still take precedence randomly. While the JSP specification |
| (2.2) explicitly states that the order is not defined and |
| shouldn't be relied upon, it's just logical that if someone |
| puts a TLD directly under <code class="inline-code">WEB-INF</code>, he |
| meant that to be used in that particular web application, |
| rather than the TLD-s coming from the dependency jars which |
| are often shared by multiple web applications.</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed: Defaults set in an overridden |
| <code class="inline-code">FreemarkerServlet.createConfiguration</code> |
| won't be accidentally overwritten by |
| <code class="inline-code">FreemarkerServlet</code>'s factory defaults |
| anymore. This was a problem with theses settings only: |
| <code class="inline-code">template_exception_handler</code>, |
| <code class="inline-code">log_template_exceptions</code>, |
| <code class="inline-code">object_wrapper</code>, |
| <code class="inline-code">template_loader</code>.</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed: If you had multiple |
| <code class="inline-code">FreemarkerServlet</code>-s with different |
| configuration settings in the same servlet context, that |
| could lead to malfunction. (Normally, you only have one, |
| just like there's only one servlet that processes |
| <code class="inline-code">*.jsp</code>.)</p> |
| </li> |
| |
| <li> |
| <p>Removed all the <code class="inline-code">xsd</code> files |
| (<code class="inline-code">web-app</code> and <code class="inline-code">taglib</code> |
| schemas) from the FreeMarker artifact and from the XML |
| entity resolver, as they were unused during XML |
| parsing.</p> |
| </li> |
| |
| <li> |
| <p>Generally improved implementation quality |
| (maintainability, error messages, performance bug fixes, |
| test coverage) and better API documentation.</p> |
| </li> |
| </ul> |
| </li> |
| |
| <li> |
| <p>Logging facility improvements:</p> |
| |
| <ul> |
| <li> |
| <p>Just like earlier, when auto-selecting the logger |
| library (the default behavior), FreeMarker choses Log4j if |
| it's available. But now, if that turns out to be |
| <code class="inline-code">log4j-over-slf4j</code>, FreeMarker will use |
| SLF4J directly instead. (This fixes the issue where the |
| logged location points to FreeMarker's log adapter class |
| instead of the real call place.)</p> |
| </li> |
| |
| <li> |
| <p>FreeMarker now recognizes the |
| <code class="inline-code">org.freemarker.loggerLibrary</code> system |
| property, which specifies which logger to use, like |
| <code class="inline-code">java <em class="code-color">...</em> |
| -Dorg.freemarker.loggerLibrary=SLF4J</code>. This option |
| deprecates |
| <code class="inline-code">Logger.selectLoggerLibrary(int)</code> as that |
| was inherently unreliable (because you usually can't control |
| class initialization order very well). The system property |
| has precedence over |
| <code class="inline-code">Logger.selectLoggerLibrary</code>.</p> |
| </li> |
| |
| <li> |
| <p>Generally improved implementation quality (more info |
| printed when something fails, etc.).</p> |
| </li> |
| |
| <li> |
| <p>New configuration setting: |
| <code class="inline-code">log_template_exceptions</code> |
| (<code class="inline-code">Configuration.setLogTemplateExceptions(boolean)</code>). |
| This specifies if <code class="inline-code">TemplateException</code>-s |
| thrown by template processing are logged by FreeMarker or |
| not. The default is <code class="inline-code">true</code> for backward |
| compatibility, but that results in logging the exception |
| twice in properly written applications, because there the |
| <code class="inline-code">TemplateException</code> thrown by the public |
| FreeMarker API is also logged by the caller (even if only as |
| the cause exception of a higher level exception). Hence, in |
| modern applications it should be set to |
| <code class="inline-code">false</code>. (Note that this setting has no |
| effect on the logging of exceptions caught by |
| <code class="inline-code">#attempt</code>/<code class="inline-code">#recover</code>; |
| those are always logged.)</p> |
| </li> |
| </ul> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">Environment</code> and custom directive |
| related improvements:</p> |
| |
| <ul> |
| <li> |
| <p>Added |
| <code class="inline-code">Environment.getCurrentDirectiveCallPlace()</code>, |
| which returns a <code class="inline-code">DirectiveCallPlace</code> object |
| when called from a custom directive (i.e., from |
| <code class="inline-code">TemplateDirectiveModel.execute()</code>). The |
| <code class="inline-code">DirectiveCallPlace</code> objects lets you |
| associate an arbitrary object to the directive invocation |
| inside the template, which can be used for call-place-bound |
| caching (like the minification of non-dynamic nested |
| content). See <code class="inline-code">DirectiveCallPlace</code> in the |
| Java API documentation for more.</p> |
| </li> |
| |
| <li> |
| <p>Added |
| <code class="inline-code">Environment.getMainTemplate()</code>. Deprecated |
| the ambiguous (and often broken: [<a href="https://sourceforge.net/p/freemarker/bugs/145/">145</a>]) |
| <code class="inline-code">Environment.getTemplate()</code>.</p> |
| </li> |
| </ul> |
| </li> |
| |
| <li> |
| <p>Template loading:</p> |
| |
| <ul> |
| <li> |
| <p>Added new <code class="inline-code">Configuration</code> setting, |
| <code class="inline-code">template_lookup_strategy</code> |
| (<code class="inline-code">Configuration.setTemplateLookupStrategy(TemplateLookupStrategy)</code>). |
| This allows customizing what |
| <code class="inline-code">TemplateLoader</code>-level names will be tried |
| when a template is requested. With this you can, for |
| example, define a custom localized lookup sequence instead |
| of the default (which looks like: |
| <code class="inline-code">foo_de_LU_MAC.ftl, foo_de_LU.ftl, |
| foo_de.ftl,</code><code class="inline-code"> foo.ftl</code>).</p> |
| </li> |
| |
| <li> |
| <p>Added new |
| <code class="inline-code">Configuration.getTemplate(<em class="code-color">...</em>)</code> |
| parameter, <code class="inline-code">Object customLookupCondition</code>. |
| This parameter can be used by custom a |
| <code class="inline-code">TemplateLookupStrategy</code> to deduce the |
| actual template name(s) from the requested name (similarly |
| to as the default lookup strategy does that based on the |
| locale). For example, on a multi-domain Web site, one may |
| want to define some templates that are specialized to a |
| domain, and thus use the domain name as the custom lookup |
| condition. Then, when <code class="inline-code">foo.ftl</code> is |
| requested, a custom |
| <code class="inline-code">TemplateLookupStrategy</code> could first look |
| for <code class="inline-code">@somedomain.com/foo.ftl</code>, and then for |
| <code class="inline-code">@default/foo.ftl</code>. See the JavaDoc of the |
| relevant |
| <code class="inline-code">Configuration.getTemplate(<em class="code-color">...</em>)</code> |
| overload for more details; note there the requirements |
| regarding the <code class="inline-code">hashCode</code> and |
| <code class="inline-code">equals</code> of the |
| <code class="inline-code">customLookupCondition</code>.</p> |
| </li> |
| |
| <li> |
| <p>Added new <code class="inline-code">Configuration</code> setting, |
| <code class="inline-code">template_name_format</code> |
| (<code class="inline-code">Configuration.setTemplateNameFormat(TemplateNameFormat)</code>). |
| This allows specifying the naming rules used by FreeMarker. |
| For now, custom implementations aren't allowed, and you can |
| only chose between |
| <code class="inline-code">TemplateNameFormat.DEFAULT_2_3_0</code> (the |
| default) and <code class="inline-code">DEFAULT_2_4_0</code> (recommended, |
| at least for new projects). <code class="inline-code">DEFAULT_2_4_0</code> |
| has several advantages, but isn't fully backward compatible |
| (though most applications won't be affected). For typical |
| mistakes like using backslash instead of slash, or backing |
| out of the root, it gives |
| <code class="inline-code">MalformedTemplateNameFormatException</code> |
| instead of <code class="inline-code">TempalteNotFoundException</code>. It |
| allows scheme names to be terminated with |
| <code class="inline-code">:</code> alone, instead of a |
| <code class="inline-code">://</code> (which is also supported), like in |
| <code class="inline-code">classpath:foo/bar.ftl</code>. It fixes numerous |
| legacy glitches (bugs), mostly related to the interpretation |
| of <code class="inline-code">..</code> after special steps like |
| <code class="inline-code">.</code> or <code class="inline-code">*</code>. See the full |
| list of differences in the <a href="https://freemarker.apache.org/docs/api/freemarker/cache/TemplateNameFormat.html#DEFAULT_2_4_0">Java |
| API documentation of |
| <code>TemplateNameFormat.DEFAULT_2_4_0</code></a>.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">ClassTemplateLoader</code> now can be |
| created by specifying a <code class="inline-code">ClassLoader</code> |
| directly, rather than by specifying a base |
| <code class="inline-code">Class</code>. That is, now there's |
| <code class="inline-code">ClassTemplateLoader(ClassLoader, String)</code> |
| constructor, and also a |
| <code class="inline-code">Configuration.setClassLoaderForTemplateLoading(ClassLoader, |
| String)</code> method.</p> |
| </li> |
| |
| <li> |
| <p>Added new exception, |
| <code class="inline-code">TemplateNotFoundException</code>, which is now |
| used instead of <code class="inline-code">TemplateNotFoundException</code> |
| when getting a template. As it extends |
| <code class="inline-code">TemplateNotFoundException</code>, this change is |
| backward compatible. The main goal was to counter the common |
| misunderstanding that template paths are real file paths. |
| However, the new exception also has the benefit that it can |
| give additional FreeMarker-specific information about the |
| error, like right now it has |
| <code class="inline-code">getTemplateName()</code> and |
| <code class="inline-code">getCustomLookupCondition()</code> |
| methods.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">Template</code>-s now have a |
| <code class="inline-code">getSourceName()</code> method, in additionally |
| to <code class="inline-code">getName()</code>. These two return the same |
| as far as no localized lookup or acquisition |
| (<code class="inline-code">*</code> in the name) or other lookup strategy |
| was actively involved. But when it was, |
| <code class="inline-code">getSourceName()</code> gives the name with which |
| the template was actually loaded from the |
| <code class="inline-code">TemplateLoader</code>, while |
| <code class="inline-code">getName()</code> returns (and had always |
| returned) the name with which the template was requested (in |
| canonicalized form). <code class="inline-code">getName()</code> is used |
| for everything (like for relative inclusion resolution), |
| except for location information in error messages, which now |
| uses <code class="inline-code">getSourceName()</code>. Also, |
| <code class="inline-code">TemplateException</code> now has a |
| <code class="inline-code">getSourceName()</code> method.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">Configuration.getTemplate(<em class="code-color">...</em>)</code> |
| overloads now accept <code class="inline-code">null</code> for the |
| <code class="inline-code">locale</code> and <code class="inline-code">encoding</code> |
| parameters, in which case they use the same defaults as the |
| overloads where the parameter is omitted.</p> |
| </li> |
| |
| <li> |
| <p>Debugger SPI implementators, attention: The |
| <code class="inline-code">DebugBreak</code> instruction will now send the |
| <code class="inline-code">sourceName</code> of the template to the |
| <code class="inline-code">suspendEnvironmentSpi</code> callback, rather |
| than its <code class="inline-code">name</code>. You should also use the |
| <code class="inline-code">sourceName</code> in |
| <code class="inline-code">registerTemplateSpi</code> and such, not the |
| <code class="inline-code">name</code>.</p> |
| </li> |
| </ul> |
| </li> |
| |
| <li> |
| <p>Configuration:</p> |
| |
| <ul> |
| <li> |
| <p>Added |
| <code class="inline-code">Configuration.unset<em class="code-color">Xxx</em></code> |
| and |
| <code class="inline-code">is<em class="code-color">Xxx</em>ExplicitlySet</code> |
| methods for several settings. Unsetting a setting makes it |
| behave as if |
| <code class="inline-code">set<em class="code-color">Xxx</em></code> was |
| never called, thus the setting will use the default value |
| that fits the current |
| <code class="inline-code">incompatible_improvements</code> value and will |
| be adjusted as <code class="inline-code">incompatible_improvements</code> |
| is changed later.</p> |
| </li> |
| |
| <li> |
| <p>When configuring FreeMarker from |
| <code class="inline-code">java.util.Properties</code> (or with |
| <code class="inline-code">String</code>-<code class="inline-code">String</code> |
| name-value pairs in general):</p> |
| |
| <ul> |
| <li> |
| <p>The <code class="inline-code">default</code> setting value is |
| now recognized by |
| <code class="inline-code">template_exception_handler</code>, |
| <code class="inline-code">template_storage</code>, |
| <code class="inline-code">template_loader</code> (and by the new |
| <code class="inline-code">template_lookup_strategy</code> and |
| <code class="inline-code">template_name_format</code>) settings, and |
| it causes |
| <code class="inline-code">Configuration.unset<em class="code-color">Xxx</em>()</code> |
| to be called.</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed: When setting |
| <code class="inline-code">object_wrapper</code> to |
| <code class="inline-code">default</code> (as opposed to not specifying |
| it), it has ignored the |
| <code class="inline-code">incompatible_improvements</code> and has |
| always used |
| <code class="inline-code">ObjectWrapper.DEFAULT_WRAPPER</code>. This |
| fix only matters when |
| <code class="inline-code">incompatible_improvements</code> is exactly |
| 2.3.21, as that's when the default object wrapper was |
| changed from |
| <code class="inline-code">ObjectWrapper.DEFAULT_WRAPPER</code> to the |
| result of <code class="inline-code">new |
| DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_21).build()</code>, |
| which is a bit different singleton, as it has read-only |
| configuration settings and bug fixed overloaded method |
| selection rules. To use |
| <code class="inline-code">ObjectWrapper.DEFAULT_WRAPPER</code> |
| regardless of the value of the |
| <code class="inline-code">incompatible_improvements</code> setting, |
| use the new <code class="inline-code">default_2_3_0</code> |
| value.</p> |
| </li> |
| </ul> |
| </li> |
| |
| <li> |
| <p>Bug fixed: Changing the value of the |
| <code class="inline-code">localized_lookup</code> setting now empties the |
| template cache, so that old lookup results won't be reused. |
| (This of course only matters if you change this setting |
| under an already running service, which is very |
| unlikely.)</p> |
| </li> |
| </ul> |
| </li> |
| |
| <li> |
| <p>Miscellaneous:</p> |
| |
| <ul> |
| <li> |
| <p>Bug fixed [<a href="https://sourceforge.net/p/freemarker/bugs/145/">145</a>], |
| active only with |
| <code class="inline-code">incompatible_improvements</code> set to 2.3.22 |
| (or higher): <code class="inline-code">#include</code> and |
| <code class="inline-code">#nested</code> doesn't change the parent |
| <code class="inline-code">Template</code> (see |
| <code class="inline-code">Configurable.getParent()</code>) of the |
| <code class="inline-code">Environment</code> anymore to the |
| <code class="inline-code">Template</code> that's included or where |
| <code class="inline-code">#nested</code> "returns" to. Thus, |
| the parent of <code class="inline-code">Environment</code> will be now |
| always the main <code class="inline-code">Template</code>. (The main |
| <code class="inline-code">Template</code> is the |
| <code class="inline-code">Template</code> whose <code class="inline-code">process</code> |
| or <code class="inline-code">createProcessingEnvironment</code> method was |
| called to initiate the output generation.) Note that this |
| only matters if you have set settings directly on |
| <code class="inline-code">Template</code> objects (not to be confused with |
| setting settings in templates via |
| <code class="inline-code">#setting</code>, which just modifies the |
| <code class="inline-code">Environment</code>, and so isn't affected by |
| this fix), and almost nobody does that. Also note that macro |
| calls have never changed the <code class="inline-code">Environment</code> |
| parent to the <code class="inline-code">Template</code> that contains the |
| macro definition, so there's no change there now.</p> |
| </li> |
| |
| <li> |
| <p>Bug fixed [<a href="https://sourceforge.net/p/freemarker/bugs/419/">419</a>]: |
| FreeMarker doesn't fail anymore when it has no permission to |
| read Java system properties, like when used in unsigned |
| applets. It just logs some warnings.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">HTML_DEBUG</code> and |
| <code class="inline-code">DEBUG</code> |
| <code class="inline-code">TemplateExceptionHandler</code> output now |
| contains a warning like "HTML_DEBUG mode; use RETHROW |
| in production!", due to frequent misuse.</p> |
| </li> |
| |
| <li> |
| <p>Some fixes and improvements in template canonical form |
| output, and as a consequence of that, in FTL stack trace |
| instruction displaying.</p> |
| </li> |
| |
| <li> |
| <p>Marked some historically public but otherwise internal |
| API-s as deprecated, so that the disclaimer is more apparent |
| in IDE-s.</p> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| |
| |
| |
| |
| <h2 class="content-header header-section2" id="autoid_178">Notes</h2> |
| |
| |
| <p><a name="topic.defaultObjectWrapperSwitchToAdapters"></a>The |
| consequences and reasons of introducing adapter approach for |
| container types in <code class="inline-code">DefaultObjectWrapper</code> when its |
| incompatibleImprovements is set to 2.3.22:</p> |
| |
| <ul> |
| <li> |
| <p>With the new approach (the adapter approach), the key |
| order of <code class="inline-code">Map</code>-s is never lost. The copying |
| approach could only keep that for <code class="inline-code">HashMap</code> |
| subclasses (such as <code class="inline-code">LinkedHashMap</code>) and |
| <code class="inline-code">SortedMap</code>-s (such as |
| <code class="inline-code">TreeMap</code>), but not for more exotic |
| <code class="inline-code">Map</code>-s, like Guava's |
| <code class="inline-code">ImmutableMap</code>. Also, any other behavioral |
| peculiarities of the original <code class="inline-code">Map</code> (e.g., case |
| insensitive key lookup) is kept now.</p> |
| </li> |
| |
| <li> |
| <p>The exact type and identity of the |
| <code class="inline-code">Map</code>/<code class="inline-code">List</code> is kept when the |
| wrapped value is passed back to a Java method from the template. |
| With the legacy approach the Java methods have received a |
| <code class="inline-code">Map</code> or <code class="inline-code">List</code> of a special |
| FreeMarker specific type (that acted as an adapter for the |
| <code class="inline-code">TemplateModel</code>).</p> |
| </li> |
| |
| <li> |
| <p>Performance characteristics change, mostly for the better, |
| but it depends on the application. If the template reads the |
| <em>same(!)</em> entry <em>from the data |
| model</em> roughly once or twice (or not at all), which is |
| typical, them the adapter approach gives better results, |
| otherwise the legacy copying approach is faster (as it can reuse |
| the wrapped entry from the previous read), though this slowdown |
| certainly not a concern for most applications. The performance |
| of the new adapter approach is more predictable, because it has |
| no initial "spike" to set up the container copy |
| (especially painful for huge collections), instead the |
| performance is linearly proportional to the number of data model |
| reads (and not to the number of collection entries).</p> |
| </li> |
| |
| <li> |
| <p>If the |
| <code class="inline-code">Map</code>/<code class="inline-code">List</code>/array is changed |
| after it was wrapped, the change will now become visible in the |
| data-model. With the copying approach, the wrapped value was a |
| shallow-snapshot of the original |
| <code class="inline-code">Map</code>/<code class="inline-code">List</code>/array. While it's |
| unlikely that someone has deliberately utilized this, it's a |
| risk factor when switching to adapters.</p> |
| </li> |
| |
| <li> |
| <p>It's theoretically possible that some code (mostly |
| <code class="inline-code">TemplateDirectiveModel</code> implementations) |
| mistakenly assumed that wrapped <code class="inline-code">Map</code>-s are |
| <code class="inline-code">SimpleHash</code>-es, and wrapped |
| <code class="inline-code">List</code>-s are |
| <code class="inline-code">SimpleSequence</code>-s, etc., instead of them just |
| being <code class="inline-code">TemplateHashModel</code>-s and |
| <code class="inline-code">TemplateSequenceModel</code>-s. Such code was always |
| wrong, but now it will indeed break, so it's a risk |
| factor.</p> |
| </li> |
| |
| <li> |
| <p>As now the exact type of the wrapped original object is |
| used for overloaded method selection, the choice can be |
| different (and similar to what it would be with pure |
| <code class="inline-code">BeansWrapper</code>). It's difficult to find cases |
| where this matters. A change is most probable around arrays, as |
| with the copying approach they were unwrapped to |
| <code class="inline-code">List</code>-s, not to the original array. As the |
| overloaded method mechanism can convert between arrays and lists |
| (in both directions), it's usually not a problem. But, it |
| doesn't do conversion between different array types when the |
| overloaded method has various types on the parameter position of |
| the array, so that's a risk factor.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">SimpleHash</code> and |
| <code class="inline-code">SimpleSequence</code> haven't become deprecated. |
| They are still used for hashes and sequences created in FTL, and |
| are recommended for values that are built specifically to be |
| used from templates, rather than wrapping an already existing |
| <code class="inline-code">Map</code> or <code class="inline-code">List</code> or |
| array.</p> |
| </li> |
| |
| <li> |
| <p><code class="inline-code">List</code>-s and <code class="inline-code">Map</code>-s |
| that are exposed to templates in multiple threads are now under |
| greater stress regarding their correct operation under |
| multi-threaded read-only access. This is because the adapters |
| won't copy their contents into well known |
| <code class="inline-code">List</code> and <code class="inline-code">Map</code> |
| implementations (<code class="inline-code">HashMap</code>, |
| <code class="inline-code">ArrayList</code>, etc.) before accessing them from |
| multiple threads. So this is mostly a concern with custom |
| <code class="inline-code">List</code> and <code class="inline-code">Map</code> |
| implementations, which aren't as mature as the standard Java |
| classes. Note that this was always like so with pure |
| <code class="inline-code">BeansWrapper</code>, which is used by a lot of |
| projects/frameworks (like by Struts) for a long time, so it's |
| not an uncharted territory.</p> |
| </li> |
| |
| <li> |
| <p>When the wrapped <code class="inline-code">List</code> is a |
| <code class="inline-code">AbstractSequentialList</code> (like a |
| <code class="inline-code">LinkedList</code>), the resulting adapter will |
| implement <code class="inline-code">TemplateCollectionModel</code> for more |
| efficient enumeration (<code class="inline-code">#list</code>-ing), in |
| additionally to <code class="inline-code">TemplateSequenceModel</code> of |
| course. <code class="inline-code">TemplateCollectionModel</code> allows FTL to |
| traverse the list without accessing elements by index. With the |
| legacy copying approach |
| <code class="inline-code">TemplateCollectionModel</code> wasn't implemented as |
| it wasn't needed for efficient enumeration there.</p> |
| </li> |
| |
| <li> |
| <p>Iterators (when you put them directly into the data-model) |
| are wrapped into <code class="inline-code">DefaultIteratorAdapter</code> |
| instead of <code class="inline-code">SimpleCollection</code>. This has two |
| consequences:</p> |
| |
| <ul> |
| <li> |
| <p>The wrapped <code class="inline-code">Iterator</code> is now |
| unwrapped properly to the original Java object when it's |
| passed to Java method from the template.</p> |
| </li> |
| |
| <li> |
| <p>Wrapped <code class="inline-code">Iterator</code>-s (not to be |
| confused with <code class="inline-code">Iterable</code>) aren't |
| thread-safe anymore, to spare some synchronizations, after |
| all, exposing the same <code class="inline-code">Iterator</code> to |
| multiple parallel template executions doesn't make much |
| sense. This shouldn't be a migration concern, as even |
| earlier, only one of those template executions could succeed |
| (the "content" of <code class="inline-code">Iterator</code>-s |
| wasn't copied, so the one who first accessed it become the |
| exclusive owner). The change is just that earlier it was |
| guaranteed that the other threads will fail (that was the |
| thread-safe about it), while now there are no such |
| guarantees.</p> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| <div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="versions_2_3_23.html"><span>Previous</span></a><a class="paging-arrow next" href="versions_2_3_21.html"><span>Next</span></a></div></div></div></div> </div> |
| </div> |
| <div class="site-footer"><div class="site-width"><div class="footer-top"><div class="col-left sitemap"><div class="column"><h3 class="column-header">Overview</h3><ul><li><a href="https://freemarker.apache.org/">What is FreeMarker?</a></li><li><a href="https://freemarker.apache.org/freemarkerdownload.html">Download</a></li><li><a href="app_versions.html">Version history</a></li><li><a href="app_faq.html">FAQ</a></li><li><a itemprop="license" href="app_license.html">License</a></li><li><a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy policy</a></li></ul></div><div class="column"><h3 class="column-header">Often used / Reference</h3><ul><li><a href="https://try.freemarker.apache.org/">Try template online</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions cheatsheet</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_builtins_alphaidx.html">?built_ins</a></li><li><a href="ref_specvar.html">.special_vars</a></li><li><a href="api/freemarker/core/Configurable.html#setSetting-java.lang.String-java.lang.String-">Configuration settings</a></li></ul></div><div class="column"><h3 class="column-header">Community</h3><ul><li><a href="https://github.com/apache/freemarker">Github project page</a></li><li><a href="https://issues.apache.org/jira/projects/FREEMARKER">Report a bug</a></li><li><a href="https://freemarker.apache.org/report-security-vulnerabilities.html">Report security vulnerability</a></li><li><a href="https://stackoverflow.com/questions/ask?tags=freemarker">Get help on StackOverflow</a></li><li><a href="https://twitter.com/freemarker">Announcements on Twitter</a></li><li><a href="https://freemarker.apache.org/mailing-lists.html">Discuss on mailing lists</a></li></ul></div></div><div class="col-right"><ul class="social-icons"><li><a class="github" href="https://github.com/apache/freemarker">Github</a></li><li><a class="twitter" href="https://twitter.com/freemarker">Twitter</a></li><li><a class="stack-overflow" href="https://stackoverflow.com/questions/ask?tags=freemarker">Stack Overflow</a></li></ul><a class="xxe" href="http://www.xmlmind.com/xmleditor/" rel="nofollow" title="Edited with XMLMind XML Editor"><span>Edited with XMLMind XML Editor</span></a></div></div><div class="footer-bottom"> <p class="last-generated"> |
| Last generated: |
| <time itemprop="dateModified" datetime="2024-02-12T20:34:04Z" title="Monday, February 12, 2024 at 8:34:04 PM Greenwich Mean Time">2024-02-12 20:34:04 GMT</time>, for Freemarker 2.3.32 </p> |
| <p class="copyright"> |
| © <span itemprop="copyrightYear">1999</span>–2024 |
| <a itemtype="http://schema.org/Organization" itemprop="copyrightHolder" href="https://apache.org/">The Apache Software Foundation</a>. Apache FreeMarker, FreeMarker, Apache Incubator, Apache, the Apache FreeMarker logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners. </p> |
| </div></div></div></body> |
| </html> |