blob: c5976afd221fdb6086c8882520e8460a8598371e [file] [log] [blame]
<!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&#39;s always clearly indicated),
because they could, with very small chance, break existing
applications. For actively maintained applications it&#39;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&#39;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(&quot;myMethod&quot;)).invoke(...)</code> in Java, thus you
can&#39;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(&quot;myProperty&quot;)</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&#39;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&#39;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">&lt;@box
class=&quot;someCssClass&quot; data\-id=product.id /&gt;</code>. (When
you enumerate the catch-all parameter names inside the macro,
the key string you get is <code class="inline-code">&quot;data-id&quot;</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">&quot;a&quot;</code>, <code class="inline-code">&quot;b&quot;</code>,
<code class="inline-code">&quot;c&quot;</code>, etc. (or for <code class="inline-code">&quot;A&quot;</code>,
<code class="inline-code">&quot;B&quot;</code>, <code class="inline-code">&quot;C&quot;</code>, etc.). When
reaching <code class="inline-code">&quot;z&quot;</code>, it continues like
<code class="inline-code">&quot;aa&quot;</code>, <code class="inline-code">&quot;ab&quot;</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">&quot;foo.bar.txt&quot;?keep_before_last(&quot;.&quot;)</code> returns
<code class="inline-code">&quot;foo.bar&quot;</code>,
<code class="inline-code">&quot;foo.bar.txt&quot;?keep_after_last(&quot;.&quot;)</code> returns
<code class="inline-code">&quot;txt&quot;</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>&#39;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&#39;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&#39;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&#39;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&#39;s wrapped by
<code class="inline-code">DefaultObjectWrapper</code>, it won&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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">&lt;#assign
u=JspTaglibs[&quot;/WEB-INF/utils.tld&quot;]&gt; ...
${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
&quot;java.lang.IllegalArgumentException: argument type
mismatch&quot;, without any FTL context). Now it&#39;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&#39;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&#39;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">&lt;init-param&gt;
&lt;param-name&gt;MetaInfTldSources&lt;/param-name&gt;
&lt;param-value&gt;classpath&lt;/param-value&gt;
&lt;/init-param&gt;</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">&lt;param-value&gt;[ WEB-INF/templates,
classpath:com/example/myapp/templates
]&lt;/param-value&gt;</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&#39;s <code class="inline-code">false</code> (the legacy
behavior), you only get a HTTP 404 "Not found".
While that&#39;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&#39;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&#39;t affected. It&#39;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&#39;s
practically always the case in applications that use
FreeMarker&#39;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&#39;t be relied upon, it&#39;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&#39;t be accidentally overwritten by
<code class="inline-code">FreemarkerServlet</code>&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;t fully backward compatible
(though most applications won&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;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&#39;s no change there now.</p>
</li>
<li>
<p>Bug fixed [<a href="https://sourceforge.net/p/freemarker/bugs/419/">419</a>]:
FreeMarker doesn&#39;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&#39;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&#39;s
unlikely that someone has deliberately utilized this, it&#39;s a
risk factor when switching to adapters.</p>
</li>
<li>
<p>It&#39;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&#39;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&#39;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&#39;s usually not a problem. But, it
doesn&#39;t do conversion between different array types when the
overloaded method has various types on the parameter position of
the array, so that&#39;s a risk factor.</p>
</li>
<li>
<p><code class="inline-code">SimpleHash</code> and
<code class="inline-code">SimpleSequence</code> haven&#39;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&#39;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&#39;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&#39;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&#39;t implemented as
it wasn&#39;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&#39;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&#39;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&#39;t make much
sense. This shouldn&#39;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&#39;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>