blob: d58fd4f41c36101da19702f2ea14b25f96bbd695 [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>Template loading - 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="Template loading">
<meta property="og:locale" content="en_US">
<meta property="og:url" content="https://freemarker.apache.org/docs/pgui_config_templateloading.html">
<link rel="canonical" href="https://freemarker.apache.org/docs/pgui_config_templateloading.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="pgui.html"><span itemprop="name">Programmer&#39;s Guide</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_config.html"><span itemprop="name">The Configuration</span></a></li><li class="step-3" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="pgui_config_templateloading.html"><span itemprop="name">Template loading</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","Programmer\'s Guide","The Configuration","Template loading"];</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="pgui_config_settings.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_config_errorhandling.html"><span>Next</span></a></div><div class="title-wrapper">
<h1 class="content-header header-section1" id="pgui_config_templateloading" itemprop="headline">Template loading</h1>
</div></div><div class="page-menu">
<div class="page-menu-title">Page Contents</div>
<ul><li><a class="page-menu-link" href="#autoid_38" data-menu-target="autoid_38">Template loaders</a><ul><li><a class="page-menu-link" href="#autoid_39" data-menu-target="autoid_39">Built-in template loaders</a></li><li><a class="page-menu-link" href="#autoid_40" data-menu-target="autoid_40">Loading templates from multiple locations</a></li><li><a class="page-menu-link" href="#autoid_41" data-menu-target="autoid_41">Loading templates from other sources</a></li><li><a class="page-menu-link" href="#autoid_42" data-menu-target="autoid_42">The template name (template path)</a></li></ul></li><li><a class="page-menu-link" href="#pgui_config_templateloading_caching" data-menu-target="pgui_config_templateloading_caching">Template caching</a></li></ul> </div>
<h2 class="content-header header-section2" id="autoid_38">Template loaders</h2>
<p>Template loaders are objects that load raw textual data based
on abstract template paths like <code class="inline-code">&quot;index.ftl&quot;</code> or
<code class="inline-code">&quot;products/catalog.ftl&quot;</code>. It&#39;s up to the concrete
template loader if from where and how the template
"files" are loaded. They could be real files inside a
specified directory, or values in a data base table, or
<code class="inline-code">String</code>-s in a Java Map, etc. When you call
<code class="inline-code">cfg.getTemplate</code> (where <code class="inline-code">cfg</code> is
a <code class="inline-code">Configuration</code> instance), FreeMarker asks the
template loader (<code class="inline-code">cfg.getTemplateLoader</code>) to return
the text for the given template path, and then FreeMarker parses
that text as template. It doesn&#39;t care or even know if the template
is a real file or not, and where it is physically; those details are
only known by the template loader.</p>
<h3 class="content-header header-section3" id="autoid_39">Built-in template loaders</h3>
<p>You can set up the three most common template loading
mechanism in the <code class="inline-code">Configuration</code> using the
following <em>convenience</em> methods:</p>
<ul>
<li>
<p><code class="inline-code">void setDirectoryForTemplateLoading(File
dir)</code>: Sets a directory on the file system from which
to load templates. Template names (template paths) will be
interpreted relatively to this physical directory. It won&#39;t
let you load files outside this directory.</p>
</li>
<li>
<p><code class="inline-code">void setClassForTemplateLoading(Class cl,
String basePackagePath)</code> and <code class="inline-code">void
setClassLoaderForTemplateLoading(ClassLoader classLoader,
String basePackagePath)</code>: These are for when you want
to load templates via the same mechanism with which Java loads
classes (from the class-path, as they used to say vaguely).
This is very likely be the preferred means of loading
templates for production code, as it allows you to keep
everything inside the deployment <code class="inline-code">jar</code> files.
The first parameter decides which Java
<code class="inline-code">ClassLoader</code> will be used. The second
parameter specifies the package that contains the templates,
in <code class="inline-code">/</code>-separated format. Note that if you
don&#39;t start it with <code class="inline-code">/</code>, it will be
interpreted relatively to the package of the
<code class="inline-code">Class</code> parameter.</p>
</li>
<li>
<p><code class="inline-code">void setServletContextForTemplateLoading(Object
servletContext, String path)</code>: Takes the context of
your Servlet-based web application, and a base path, which is
interpreted relative to the web application root directory
(that&#39;s the parent of the <code class="inline-code">WEB-INF</code>
directory). Note that we refer to &quot;directory&quot; here although
this loading method works even for unpacked
<code class="inline-code">.war</code> files, since it uses
<code class="inline-code">ServletContext.getResource()</code> to access the
templates. If you omit the second parameter (or use
<code class="inline-code">&quot;&quot;</code>), you can simply store the static files
(<code class="inline-code">.html</code>, <code class="inline-code">.jpg</code>, etc.)
mixed with the <code class="inline-code">.ftl</code> files. Of course, you
must set up a Servlet for the <code class="inline-code">*.ftl</code>,
<code class="inline-code">*.ftlh</code>, <code class="inline-code">*.ftlx</code>
uri-patterns in <code class="inline-code">WEB-INF/web.xml</code> for this,
otherwise the client will get the raw templates as is! To
avoid a such accident, many prefers storing the templates
somewhere inside the <code class="inline-code">WEB-INF</code> directory,
which is never visitable directly. This mechanism will very
likely be the preferred means of loading templates for servlet
applications, since the templates can be updated without
restarting the web application, while this often doesn&#39;t work
with the class-loader mechanism.</p>
</li>
</ul>
<p>If you want to use a custom
<code class="inline-code">TemplateLoader</code> implementation, or need to set
up some extra settings of a built-in template loader, you need to
instantiate the <code class="inline-code">TemplateLoader</code> object yourself,
and then call
<code class="inline-code">Configuration.setTemplateLoader(TemplateLoader)</code>:</p>
<div class="code-block role-unspecified">
<pre class="code-block-body">WebappTemplateLoader templateLoader = new WebappTemplateLoader(servletContext, &quot;WEB-INF/templates&quot;);
templateLoader.setURLConnectionUsesCaches(false);
templateLoader.setAttemptFileAccess(false);
cfg.setTemplateLoader(templateLoader);</pre> </div>
<h3 class="content-header header-section3" id="autoid_40">Loading templates from multiple locations</h3>
<p>If you need to load templates from multiple locations, you
have to instantiate the template loader objects for every
location, wrap them into a <code class="inline-code">MultiTemplateLoader</code>,
and finally pass that loader to the
<code class="inline-code">setTemplateLoader(TemplateLoader loader)</code> method
of <code class="inline-code">Configuration</code>. Here&#39;s an example for loading
templates from two distinct directories and with the
class-loader:</p>
<div class="code-block role-unspecified">
<pre class="code-block-body">import freemarker.cache.*; // template loaders live in this package
<em>...</em>
FileTemplateLoader ftl1 = new FileTemplateLoader(new File(&quot;/tmp/templates&quot;));
FileTemplateLoader ftl2 = new FileTemplateLoader(new File(&quot;/usr/data/templates&quot;));
ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), &quot;/com/example/templates&quot;);
MultiTemplateLoader mtl = new MultiTemplateLoader(new TemplateLoader[] { ftl1, ftl2, ctl });
cfg.setTemplateLoader(mtl);</pre> </div>
<p>Now FreeMarker will try to load templates from
<code class="inline-code">/tmp/templates</code> directory, and if it does not
find the requested template there, it will try to load that from
<code class="inline-code">/usr/data/templates</code>, and if it still does not
find the requested template, then it tries to load it from the
<code class="inline-code">com.example.templates</code> Java package.</p>
<h3 class="content-header header-section3" id="autoid_41">Loading templates from other sources</h3>
<p>If none of the built-in class loaders fit your needs, you
can write your own class that implements the
<code class="inline-code">freemarker.cache.TemplateLoader</code> interface and
pass it to the <code class="inline-code">setTemplateLoader(TemplateLoader
loader)</code> method of <code class="inline-code">Configuration</code>.
Please read the API JavaDoc for more information.</p>
<p>If your template source accesses the templates through an
URL, you needn&#39;t implement a <code class="inline-code">TemplateLoader</code>
from scratch; you can choose to subclass
<code class="inline-code">freemarker.cache.URLTemplateLoader</code> instead and
just implement the <code class="inline-code">URL getURL(String
templateName)</code> method.</p>
<h3 class="content-header header-section3" id="autoid_42">The template name (template path)</h3>
<p>It is up to the template loader how it interprets template
names (also known as template paths). But to work together with
other components there are restrictions regarding the format of
the path. In general, it is strongly recommended that template
loaders use URL-style paths. The path must not use
<code class="inline-code">/</code> (path step separator) character, nor the
<code class="inline-code">.</code> (same-directory) and <code class="inline-code">..</code>
(parent directory) path steps with other meaning than they have in
URL paths (or in UN*X paths). The <code class="inline-code">*</code> (asterisk)
step is also reserved, and used for "template
acquisition" feature of FreeMarker.</p>
<p><code class="inline-code">://</code> (or with
<code class="inline-code">template_name_format</code> setting set to
<code class="inline-code">DEFAULT_2_4_0</code>, the <code class="inline-code">:</code> (colon)
character) is reserved for specifying a scheme part, similarly as
it works with URI-s. For example
<code class="inline-code">someModule://foo/bar.ftl</code> uses the
<code class="inline-code">someModule</code>, or assuming the
<code class="inline-code">DEFAULT_2_4_0</code> format,
<code class="inline-code">classpath:foo/bar.ftl</code> uses the
<code class="inline-code">classpath</code> scheme. Interpreting the scheme part
is completely up to the <code class="inline-code">TemplateLoader</code>. (The
FreeMarker core is only aware of the idea of schemes because
otherwise it couldn&#39;t resolve relative template names
properly.)</p>
<p>FreeMarker always normalizes the paths before passing them
to the <code class="inline-code">TemplateLoader</code>, so the paths don&#39;t
contain <code class="inline-code">/../</code> or such, and are relative to the
imaginary template root directory (that is, they don&#39;t start with
<code class="inline-code">/</code>). They don&#39;t contain the <code class="inline-code">*</code>
step either, as template acquisition happens in an earlier stage.
Furthermore, with <code class="inline-code">template_name_format</code> setting
set to <code class="inline-code">DEFAULT_2_4_0</code>, multiple consecutive
<code class="inline-code">/</code>-s will be normalized to a single
<code class="inline-code">/</code> (unless they are part of the
<code class="inline-code">://</code> scheme separator).</p>
<p>Note that FreeMarker template path should always uses slash
(not backslash) regardless of the host OS.</p>
<h2 class="content-header header-section2" id="pgui_config_templateloading_caching">Template caching</h2>
<p>FreeMarker caches templates (assuming you use the
<code class="inline-code">Configuration</code> methods to create
<code class="inline-code">Template</code> objects). This means that when you call
<code class="inline-code">getTemplate</code>, FreeMarker not only returns the
resulting <code class="inline-code">Template</code> object, but stores it in a
cache, so when next time you call <code class="inline-code">getTemplate</code>
with the same (or equivalent) path, it just returns the cached
<code class="inline-code">Template</code> instance, and will not load and parse
the template file again.</p>
<p>If you change the template file, then FreeMarker will re-load
and re-parse the template automatically when you get the template
next time. However, since always checking for changes can be burden
for a system that processes lot of templates, there is a
<code class="inline-code">Configuration</code> level setting called "update
delay" (defaults is 5 seconds). Until this much time has
elapsed since the last checking for a newer version, FreeMarker will
not check again if the template was changed. If you want to see the
changes without delay, set this setting to 0. Note that some
template loaders won&#39;t see that a template was changed because of
the underlying storage mechanism doesn&#39;t support that; for example,
class-loader based template loaders may have this problem.</p>
<p>A template will be removed from the cache if you call
<code class="inline-code">getTemplate</code> and FreeMarker realizes that the
template file has been removed meanwhile. Also, if the JVM thinks
that it begins to run out of memory, by default it can arbitrarily
drop templates from the cache. Furthermore, you can empty the cache
manually with the <code class="inline-code">clearTemplateCache</code> method of
<code class="inline-code">Configuration</code>. You can also drop selected
template from the cache with
<code class="inline-code">removeTemplateFromCache</code>; this can be also
utilized to force re-loading a template regardless of the
"update delay" setting.</p>
<p>The actual strategy of when a cached template should be thrown
away is pluggable with the <code class="inline-code">cache_storage</code> setting,
by which you can plug any <code class="inline-code">CacheStorage</code>
implementation. For most users
<code class="inline-code">freemarker.cache.MruCacheStorage</code> will be
sufficient. This cache storage implements a two-level Most Recently
Used cache. In the first level, items are strongly referenced up to
the specified maximum (strongly referenced items can&#39;t be dropped by
the JVM, as opposed to softly referenced items). When the maximum is
exceeded, the least recently used item is moved into the second
level cache, where they are softly referenced, up to another
specified maximum. The size of the strong and soft parts can be
specified with the constructor. For example, set the size of the
strong part to 20, and the size of soft part to 250:</p>
<div class="code-block role-unspecified">
<pre class="code-block-body">cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(20, 250))</pre> </div>
<p>Or, since <code class="inline-code">MruCacheStorage</code> is the default
cache storage implementation:</p>
<div class="code-block role-unspecified">
<pre class="code-block-body">cfg.setSetting(Configuration.CACHE_STORAGE_KEY, &quot;strong:20, soft:250&quot;);</pre> </div>
<p>When you create a new <code class="inline-code">Configuration</code> object,
initially it uses an <code class="inline-code">MruCacheStorage</code> where
<code class="inline-code">strongSizeLimit</code> is 0, and
<code class="inline-code">softSizeLimit</code> is
<code class="inline-code">Integer.MAX_VALUE</code> (that is, in practice,
infinite). Depending on how smart the JVM is, using non-0
<code class="inline-code">strongSizeLimit</code> is maybe a safer option, as with
only softly referenced items the JVM could even throw the most
frequently used templates when there&#39;s a resource shortage, which
then have to be re-loaded and re-parsed, burdening the system even
more.</p>
<div class="bottom-pagers-wrapper"><div class="pagers bottom"><a class="paging-arrow previous" href="pgui_config_settings.html"><span>Previous</span></a><a class="paging-arrow next" href="pgui_config_errorhandling.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>