Settings are named values that
influence the behavior of FreeMarker. Examples of settings are:
locale
, number_format
,
default_encoding
,
template_exception_handler
. The full list of
settings can be found in the Java
API documentation of
Configuration.setSetting(...)
.
The settings coming from the Configuration
can be overridden in a Template
instance. For
example, if you set the locale
setting to
"en_US"
in the configuration, then the
locale
in all templates that use this configuration
will be "en_US"
, except in templates where the
locale
was explicitly specified differently (see
localization).
Thus, the setting values in the Configuration
serve
as defaults that can be overridden in a per template manner. The value
coming from the Configuration
instance or
Template
instance can be further overridden for a
single Template.process
call. For each such call a
freemarker.core.Environment
object is created
internally that holds the runtime environment of the template
processing, including the setting values that were overridden on that
level. The values stored there can even be changed during the template
processing, so a template can set settings itself, like switching
locale
at the middle of the ongoing
processing.
This can be imagined as 3 layers
(Configuration
, Template
,
Environment
) of settings, where the topmost layer
that contains the value for a certain setting provides the effective
value of that setting. For example (settings A to F are just imaginary
settings for this example):
Setting A | Setting B | Setting C | Setting D | Setting E | Setting F | |
---|---|---|---|---|---|---|
Layer 3: Environment |
1 | - | - | 1 | - | - |
Layer 2: Template |
2 | 2 | - | - | 2 | - |
Layer 1: Configuration |
3 | 3 | 3 | 3 | - | - |
The effective value of settings will be: A = 1, B = 2, C = 3, D
= 1, E = 2. The F setting is probably null
, or it
throws exception when you try to get it.
Let's see exactly how to set settings:
-
Configuration
layer: In principle you set the settings with the setter methods of theConfiguration
object, fore example:Configuration myCfg = new Configuration(Configuration.VERSION_2_3_27); myCfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); myCfg.setDefaultEncoding("UTF-8"); DefaultObjectWrapperBuilder owb = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_27); owb.setForceLegacyNonListCollections(false); owb.setDefaultDateType(TemplateDateModel.DATETIME); myCfg.setObjectWrapper(owb.build());
You do this before you start to actually use the
Configuration
object (typically, when you initialize the application); you should treat the object as read-only after that.In practice, in most frameworks you have to specify the settings in some kind of framework-specific configuration file that require specifying settings as
String
name-value pairs (like in a.properties
file). In that case the authors of the frameworks most probably use theConfguration.setSetting(String name, String value)
method; see available setting names and the format of the values in the API documentation ofsetSetting
. Example for Spring Framework:<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="freemarkerSettings"> <props> <prop key="incompatible_improvements">2.3.27</prop> <prop key="template_exception_handler">rethrow</prop> <prop key="default_encoding">UTF-8</prop> <prop key="object_wrapper"> DefaultObjectWrapper( 2.3.27, forceLegacyNonListCollections = false, defaultDateType = freemarker.template.TemplateDateModel.DATETIME) </prop> </props> </property> </bean>
Here's the same when configuring FreeMarker for Struts, which looks for a
freemarker.properties
in the classpath:incompatible_improvements=2.3.27 template_exception_handler=rethrow default_encoding=UTF-8 object_wrapper=DefaultObjectWrapper( \ 2.3.27, \ forceLegacyNonListCollections = false, \ defaultDateType = freemarker.template.TemplateDateModel.DATETIME)
As demonstrated above with
object_wrapper
, some settings can accept quite complex values, which can be used to instantiate objects of arbitrary classes and set their properties. Still, configuring withString
key-value pairs is limited compared to directly using the Java API, so in some cases you have to find a way to do this in Java. -
Template
layer: Settings on individual templates are normally set by template configurations (see them in their own chapter), which basically associate setting assignments to template name (template path) patterns. There's a deviation from this approach with thelocale
setting, because that you can also specify toConfiguration.getTemplate(...)
as parameter, to get the template for the requested locale (so called localized lookup).Warning!You should never set settings directly on the
Template
object that you get fromConfiguration.getTemplate(...)
! Those objects should be treated as already initialized and read-only.When a template includes or imports another template, most of the settings (like
locale
,number_format
, etc.) will remain those specified by the top-level template. The exceptions are the settings that affect the parsing of the template (liketag_syntax
,whitespace_stripping
, etc.), as these are not inherited from the top-level template, instead each template always uses its own values, no mater how it was invoked.Note:If you are going to use template layer settings, you should set the
incompatible_improvements
setting to 2.3.22 or higher, to avoid some confusing legacy bugs. -
Environment
layer: There are two ways of doing it:-
With Java API: Use the setter methods of the
Environment
object. You may run into the API problem thatmyTemplate.process(...)
both creates theEnvironment
object internally and processes the template, so you have no opportunity to adjust theEnvironment
in between. The solution is that those two steps can be separated like this:Environment env = myTemplate.createProcessingEnvironment(root, out); env.setLocale(java.util.Locale.ITALY); env.setNumberFormat("0.####"); env.process(); // process the template
-
Directly in the Template (considered as bad style, usually): Use the
setting
directive, for example:Template<#setting locale="it_IT"> <#setting number_format="0.####">
There are no restriction regarding when can you change the settings in this layer.
-
To see the list of supported settings and their meaning, please read the following parts of the FreeMarker Java API documentation:
-
Setter methods of
freemarker.core.Configurable
for the settings that are in all three layers -
Setter methods of
freemarker.template.Configuration
for the settings that are available only in theConfiguration
layer -
freemarker.core.Configurable.setSetting(String, String)
for settings that are available in all three layers and are writable withString
key-value pairs. -
freemarker.template.Configuration.setSetting(String, String)
for settings that are available only in theConfiguration
layer and are writable withString
key-value pairs.