http://git-wip-us.apache.org/repos/asf/incubator-freemarker-site/blob/a4004324/builds/2.3.26-nightly/versions_2_3_22.html
----------------------------------------------------------------------
diff --git a/builds/2.3.26-nightly/versions_2_3_22.html
b/builds/2.3.26-nightly/versions_2_3_22.html
deleted file mode 100644
index 15a52c2..0000000
--- a/builds/2.3.26-nightly/versions_2_3_22.html
+++ /dev/null
@@ -1,1197 +0,0 @@
-<!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="http://freemarker.org/docs/versions_2_3_22.html">
-<link rel="canonical" href="http://freemarker.org/docs/versions_2_3_22.html">
-<link rel="icon" href="favicon.png" type="image/png">
-<link rel="stylesheet" type="text/css"
href="http://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?1489402528979">
-<script>
-(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
-(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
-m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
-})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
-ga('create', 'UA-55420501-1', 'auto');
-ga('send', 'pageview');
-</script>
-</head>
-<body itemscope itemtype="https://schema.org/Code">
- <meta itemprop="url" content="http://freemarker.org/docs/">
- <meta itemprop="name" content="Apache FreeMarker Manual">
-
- <!--[if lte IE 9]>
- <div style="background-color: #C00; color: #fff; padding: 12px 24px;">Please
use a modern browser to view this website.</div>
- <![endif]--><div class="header-top-bg"><div class="site-width header-top"><a
class="logo" href="http://freemarker.org" role="banner"> <img
itemprop="image" src="logo.png" alt="FreeMarker">
-</a><ul class="tabs"><li><a href="http://freemarker.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="http://freemarker.org/contribute.html"
title="Contribute"><span>Contribute</span></a></li><li><a class="tab icon-bug"
href="https://issues.apache.org/jira/browse/FREEMARKER/" title="Report a
Bug"><span>Report a Bug</span></a></li><li><a class="tab icon-download"
href="http://freemarker.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="searc
h-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"><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="itemListEl
ement" 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 class="bookmarks"
title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul
class="bookmark-list"><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?1489402528979"></script>
- <script src="docgen-resources/main.min.js?1489402528979"></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_168"
data-menu-target="autoid_168">Changes on the FTL side</a></li><li><a
class="page-menu-link" href="#autoid_169" data-menu-target="autoid_169">Changes
on the Java side</a></li><li><a class="page-menu-link" href="#autoid_170"
data-menu-target="autoid_170">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_168">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_169">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="http://freemarker.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-wrapper"><pre class="code-block
code-unspecified"><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="http://freemarker.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="http://freemarker.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_170">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="http://freemarker.org/">What is FreeMarker?</a></li><li><a
href="http://freemarker.org/freemarkerdownload.html">Download</a></li><li><a
href="app_versions.html">Version history</a></li><li><a
href="http://freemarker.org/history.html">About us</a></li><li><a
itemprop="license" href="app_license.html">License</a></li></ul></div><div
class="column"><h3 class="column-header">Handy stuff</h3><ul><li><a
href="http://freemarker-online.kenshoo.com/">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></ul></div><div
class="column"><h3 class="column-header">Community</h3><ul><li><a href
="https://github.com/freemarker/freemarker">FreeMarker on
Github</a></li><li><a href="https://twitter.com/freemarker">Follow us on
Twitter</a></li><li><a
href="https://issues.apache.org/jira/browse/FREEMARKER/">Report a
bug</a></li><li><a
href="http://stackoverflow.com/questions/ask?tags=freemarker">Ask a
question</a></li><li><a href="http://freemarker.org/mailing-lists.html">Mailing
lists</a></li></ul></div></div><div class="col-right"><ul
class="social-icons"><li><a class="github"
href="https://github.com/freemarker/freemarker">Github</a></li><li><a
class="twitter" href="https://twitter.com/freemarker">Twitter</a></li><li><a
class="stack-overflow"
href="http://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="2017-03-13T10:55:28Z" title="Monday,
March 13, 2017 10:55:28 AM GMT">2017-03-13 10:55:28 GMT</time>, for Freemarker
2.3.26 </p>
-<p class="copyright">
-© <span itemprop="copyrightYear">1999</span>â2017
-<a itemtype="http://schema.org/Organization" itemprop="copyrightHolder"
href="http://apache.org/">The Apache Software Foundation</a>. Apache
FreeMarker, FreeMarker, Apache Incubator, Apache, the Apache FreeMarker logo
are trademarks of The Apache Software Foundation. </p>
-</div></div></div></body>
-</html>