Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Copyright 2014 Attila Szegedi, Daniel Dekany, Jonathan Revusky
    * 
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    * 
    * http://www.apache.org/licenses/LICENSE-2.0
    * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package freemarker.template;
  
  import java.io.File;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Set;
  import java.util.TreeMap;
  
The main entry point into the FreeMarker API; encapsulates the configuration settings of FreeMarker, also serves as a central template-loading and caching service.

This class is meant to be used in a singleton pattern. That is, you create an instance of this at the beginning of the application life-cycle, set its configuration settings there (either with the setter methods like setTemplateLoader(freemarker.cache.TemplateLoader) or by loading a .properties file), and then use that single instance everywhere in your application. Frequently re-creating Configuration is a typical and grave mistake from performance standpoint, as the Configuration holds the template cache, and often also the class introspection cache, which then will be lost. (Note that, naturally, having multiple long-lived instances, like one per component that internally uses FreeMarker is fine.)

The basic usage pattern is like:

  // Where the application is initialized; in general you do this ONLY ONCE in the application life-cycle!
  Configuration cfg = new Configuration(VERSION_X_Y_Z));
  // Where X, Y, Z enables the not-100%-backward-compatible fixes introduced in
  // FreeMarker version X.Y.Z  and earlier (see Configuration(freemarker.template.Version)).
  cfg.setSomeSetting(...);
  cfg.setOtherSetting(...);
  ...
  
  // Later, whenever the application needs a template (so you may do this a lot, and from multiple threads):
  Template myTemplate = cfg.getTemplate("myTemplate.html");
  myTemplate.process(dataModel, out);

A couple of settings that you should not leave on its default value are:

A Configuration object is thread-safe only after you have stopped modifying the configuration settings, and you have safely published it (see JSR 133 and related literature) to other threads. Generally, you set everything directly after you have instantiated the Configuration object, then you don't change the settings anymore, so then it's safe to make it accessible (again, via a "safe publication" technique) from multiple threads. The methods that aren't for modifying settings, like getTemplate(java.lang.String), are thread-safe.

 
 public class Configuration extends Configurable implements Cloneable {
     
     private static final Logger CACHE_LOG = Logger.getLogger("freemarker.cache");
     
     private static final String VERSION_PROPERTIES_PATH = "freemarker/version.properties";
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String DEFAULT_ENCODING_KEY_SNAKE_CASE = "default_encoding"
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String DEFAULT_ENCODING_KEY_CAMEL_CASE = "defaultEncoding"
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String DEFAULT_ENCODING_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String LOCALIZED_LOOKUP_KEY_SNAKE_CASE = "localized_lookup";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String LOCALIZED_LOOKUP_KEY_CAMEL_CASE = "localizedLookup";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String LOCALIZED_LOOKUP_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String STRICT_SYNTAX_KEY_SNAKE_CASE = "strict_syntax";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String STRICT_SYNTAX_KEY_CAMEL_CASE = "strictSyntax";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String STRICT_SYNTAX_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String WHITESPACE_STRIPPING_KEY_SNAKE_CASE = "whitespace_stripping";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String WHITESPACE_STRIPPING_KEY_CAMEL_CASE = "whitespaceStripping";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String WHITESPACE_STRIPPING_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String CACHE_STORAGE_KEY_SNAKE_CASE = "cache_storage";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String CACHE_STORAGE_KEY_CAMEL_CASE = "cacheStorage";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String CACHE_STORAGE_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String TEMPLATE_UPDATE_DELAY_KEY_SNAKE_CASE = "template_update_delay";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String TEMPLATE_UPDATE_DELAY_KEY_CAMEL_CASE = "templateUpdateDelay";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String TEMPLATE_UPDATE_DELAY_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String AUTO_IMPORT_KEY_SNAKE_CASE = "auto_import";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String AUTO_IMPORT_KEY_CAMEL_CASE = "autoImport";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String AUTO_IMPORT_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String AUTO_INCLUDE_KEY_SNAKE_CASE = "auto_include";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String AUTO_INCLUDE_KEY_CAMEL_CASE = "autoInclude";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String AUTO_INCLUDE_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String TAG_SYNTAX_KEY_SNAKE_CASE = "tag_syntax";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String TAG_SYNTAX_KEY_CAMEL_CASE = "tagSyntax";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String TAG_SYNTAX_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String NAMING_CONVENTION_KEY_SNAKE_CASE = "naming_convention";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String NAMING_CONVENTION_KEY_CAMEL_CASE = "namingConvention";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String NAMING_CONVENTION_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String TEMPLATE_LOADER_KEY_SNAKE_CASE = "template_loader";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String TEMPLATE_LOADER_KEY_CAMEL_CASE = "templateLoader";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String TEMPLATE_LOADER_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String TEMPLATE_LOOKUP_STRATEGY_KEY_SNAKE_CASE = "template_lookup_strategy";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String TEMPLATE_LOOKUP_STRATEGY_KEY_CAMEL_CASE = "templateLookupStrategy";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String TEMPLATE_LOOKUP_STRATEGY_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String TEMPLATE_NAME_FORMAT_KEY_SNAKE_CASE = "template_name_format";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String TEMPLATE_NAME_FORMAT_KEY_CAMEL_CASE = "templateNameFormat";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String TEMPLATE_NAME_FORMAT_KEY = ;
    
    
Legacy, snake case (like_this) variation of the setting name.

Since:
2.3.23
 
     public static final String INCOMPATIBLE_IMPROVEMENTS_KEY_SNAKE_CASE = "incompatible_improvements";
    
Modern, camel case (likeThis) variation of the setting name.

Since:
2.3.23
 
     public static final String INCOMPATIBLE_IMPROVEMENTS_KEY_CAMEL_CASE = "incompatibleImprovements";
    
Alias to the ..._SNAKE_CASE variation due to backward compatibility constraints.
 
     public static final String INCOMPATIBLE_IMPROVEMENTS_KEY = ;
    
    

Deprecated:
Use INCOMPATIBLE_IMPROVEMENTS_KEY instead.
 

Deprecated:
Use INCOMPATIBLE_IMPROVEMENTS_KEY instead.
 
     public static final String INCOMPATIBLE_ENHANCEMENTS = "incompatible_enhancements";
     
     private static final String[] SETTING_NAMES_SNAKE_CASE = new String[] {
         // Must be sorted alphabetically!
         ,
     };
 
     private static final String[] SETTING_NAMES_CAMEL_CASE = new String[] {
         // Must be sorted alphabetically!
         ,
     };
     
     public static final int AUTO_DETECT_TAG_SYNTAX = 0;
     public static final int ANGLE_BRACKET_TAG_SYNTAX = 1;
     public static final int SQUARE_BRACKET_TAG_SYNTAX = 2;
 
     public static final int AUTO_DETECT_NAMING_CONVENTION = 10;
     public static final int LEGACY_NAMING_CONVENTION = 11;
     public static final int CAMEL_CASE_NAMING_CONVENTION = 12;
    
    
FreeMarker version 2.3.0 (an incompatible improvements break-point)
 
     public static final Version VERSION_2_3_0 = new Version(2, 3, 0);
    
    
FreeMarker version 2.3.19 (an incompatible improvements break-point)
 
     public static final Version VERSION_2_3_19 = new Version(2, 3, 19);
    
    
FreeMarker version 2.3.20 (an incompatible improvements break-point)
 
     public static final Version VERSION_2_3_20 = new Version(2, 3, 20);
    
    
FreeMarker version 2.3.21 (an incompatible improvements break-point)
 
     public static final Version VERSION_2_3_21 = new Version(2, 3, 21);

    
FreeMarker version 2.3.22 (an incompatible improvements break-point)
 
     public static final Version VERSION_2_3_22 = new Version(2, 3, 22);

    
FreeMarker version 2.3.23 (an incompatible improvements break-point)
 
     public static final Version VERSION_2_3_23 = new Version(2, 3, 23);

    
The default of getIncompatibleImprovements(), currently VERSION_2_3_0.
 
     public static final Version DEFAULT_INCOMPATIBLE_IMPROVEMENTS = .;
    

Deprecated:
Use DEFAULT_INCOMPATIBLE_IMPROVEMENTS instead.
 

Deprecated:
Use DEFAULT_INCOMPATIBLE_IMPROVEMENTS instead.
 
     
     private static final String DEFAULT = "default";
     
     private static final Version VERSION;
     static {
         try {
             Properties vp = new Properties();
             InputStream ins = Configuration.class.getClassLoader()
                     .getResourceAsStream();
             if (ins == null) {
                 throw new RuntimeException("Version file is missing.");
             } else {
                 try {
                     vp.load(ins);
                 } finally {
                     ins.close();
                 }
                 
                 String versionString  = getRequiredVersionProperty(vp"version");
                 
                 Date buildDate;
                 {
                     String buildDateStr = getRequiredVersionProperty(vp"buildTimestamp");
                     if (buildDateStr.endsWith("Z")) {
                         buildDateStr = buildDateStr.substring(0, buildDateStr.length() - 1) + "+0000";
                     }
                     try {
                         buildDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ".).parse(buildDateStr);
                     } catch (java.text.ParseException e) {
                         buildDate = null;
                     }
                 }
                 
                 final Boolean gaeCompliant = Boolean.valueOf(getRequiredVersionProperty(vp"isGAECompliant"));
                 
                  = new Version(versionStringgaeCompliantbuildDate);
             }
         } catch (IOException e) {
             throw new RuntimeException("Failed to load and parse " + e);
         }
     }
     
     private static final String FM_24_DETECTION_CLASS_NAME = "freemarker.core._2_4_OrLaterMarker";
     private static final boolean FM_24_DETECTED;
     static {
         boolean fm24detected;
         try {
             Class.forName();
             fm24detected = true;
         } catch (ClassNotFoundException e) {
             fm24detected = false;
         } catch (LinkageError e) {
             fm24detected = true;
         } catch (Throwable e) {
             // Unexpected. We assume that there's no clash.
             fm24detected = false;
         }
          = fm24detected;
     }
     
     private final static Object defaultConfigLock = new Object();
     private static Configuration defaultConfig;
 
     private boolean strictSyntax = true;
     private volatile boolean localizedLookup = true;
     private boolean whitespaceStripping = true;
     private int tagSyntax = ;
 
     private TemplateCache cache;
     
     private boolean templateLoaderExplicitlySet;
     private boolean templateLookupStrategyExplicitlySet;
     private boolean templateNameFormatExplicitlySet;
     private boolean cacheStorageExplicitlySet;
     
     private boolean objectWrapperExplicitlySet;
     private boolean templateExceptionHandlerExplicitlySet;
     private boolean logTemplateExceptionsExplicitlySet;
     
     private HashMap/*<String, TemplateModel>*/ sharedVariables = new HashMap();

    
Needed so that it doesn't mater in what order do you call setSharedVaribles(java.util.Map) and setObjectWrapper(freemarker.template.ObjectWrapper). When the user configures FreeMarker from Spring XML, he has no control over the order, so it has to work on both ways.
 
     private HashMap/*<String, Object>*/ rewrappableSharedVariables = null;
     
     private String defaultEncoding = SecurityUtilities.getSystemProperty("file.encoding""utf-8");
     private Map localeToCharsetMap = _ConcurrentMapFactory.newThreadSafeMap();
     
     private ArrayList autoImports = new ArrayList(), autoIncludes = new ArrayList(); 
     private Map autoImportNsToTmpMap = new HashMap();   // TODO No need for this, instead use List<NamespaceToTemplate> below.
 
    
 
     public Configuration() {
         this();
     }

    
Creates a new instance and sets which of the non-backward-compatible bugfixes/improvements should be enabled. Note that the specified versions corresponds to the incompatible_improvements configuration setting, and can be changed later, with setIncompatibleImprovements(freemarker.template.Version) for example.

About the "incompatible improvements" setting

This setting value is the FreeMarker version number where the not 100% backward compatible bug fixes and improvements that you want to enable were already implemented. In new projects you should set this to the FreeMarker version that you are actually using. In older projects it's also usually better to keep this high, however you better check the changes activated (find them below), at least if not only the 3rd version number (the micro version) of incompatibleImprovements is increased. Generally, as far as you only increase the last version number of this setting, the changes are always low risk. The default value is 2.3.0 to maximize backward compatibility, but that value isn't recommended.

Bugfixes and improvements that are fully backward compatible, also those that are important security fixes, are enabled regardless of the incompatible improvements setting.

An important consequence of setting this setting is that now your application will check if the stated minimum FreeMarker version requirement is met. Like if you set this setting to 2.3.22, but accidentally the application is deployed with FreeMarker 2.3.21, then FreeMarker will fail, telling that a higher version is required. After all, the fixes/improvements you have requested aren't available on a lower version.

Note that as FreeMarker's minor (2nd) or major (1st) version number increments, it's possible that emulating some of the old bugs will become unsupported, that is, even if you set this setting to a low value, it silently wont bring back the old behavior anymore. Information about that will be present here.

Currently the effects of this setting are:

  • 2.3.0: This is the lowest supported value, the version used in older projects. This is the default in the FreeMarker 2.3.x series.

  • 2.3.19 (or higher): Bug fix: Wrong # tags were printed as static text instead of causing parsing error when there was no correct # or @ tag earlier in the same template.

  • 2.3.20 (or higher): ?html will escape apostrophe-quotes just like ?xhtml does. Utilizing this is highly recommended, because otherwise if interpolations are used inside attribute values that use apostrophe-quotation (<foo bar='${val}'>) instead of plain quotation mark (<foo bar="${val}">), they might produce HTML/XML that's not well-formed. Note that ?html didn't do this because long ago there was no cross-browser way of doing this, but it's not a concern anymore.

  • 2.3.21 (or higher):

    • The default of the object_wrapper setting (freemarker.core.Configurable.getObjectWrapper()) changes from ObjectWrapper.DEFAULT_WRAPPER to another almost identical DefaultObjectWrapper singleton, returned by DefaultObjectWrapperBuilder.build(). The new default object wrapper's "incompatible improvements" version is set to the same as of the Configuration. See freemarker.ext.beans.BeansWrapper.(freemarker.template.Version) for further details. Furthermore, the new default object wrapper doesn't allow changing its settings; setter methods throw java.lang.IllegalStateException). (If anything tries to call setters on the old default in your application, that's a dangerous bug that won't remain hidden now. As the old default is a singleton too, potentially shared by independently developed components, most of them expects the out-of-the-box behavior from it (and the others are necessarily buggy). Also, then concurrency glitches can occur (and even pollute the class introspection cache) because the singleton is modified after publishing to other threads.) Furthermore the new default object wrapper shares class introspection cache with other freemarker.ext.beans.BeansWrapper-s created with freemarker.ext.beans.BeansWrapperBuilder, which has an impact as freemarker.ext.beans.BeansWrapper.clearClassIntrospecitonCache() will be disallowed; see more about it there.

    • The ?iso_... built-ins won't show the time zone offset for java.sql.Time values anymore, because most databases store time values that aren't in any time zone, but just store hour, minute, second, and decimal second field values. If you still want to show the offset (like for PostgreSQL "time with time zone" columns you should), you can force showing the time zone offset by using myTime?string.iso_fz (and its other variants).

    • ?is_enumerable correctly returns false for Java methods get from Java objects that are wrapped with freemarker.ext.beans.BeansWrapper and its subclasses, like DefaultObjectWrapper. Although method values implement TemplateSequenceModel (because of a historical design quirk in freemarker.ext.beans.BeansWrapper), trying to #list them will cause error, hence they aren't enumerable.

    • ?c will return "INF", "-INF" and "NaN" for positive/negative infinity and IEEE floating point Not-a-Number, respectively. These are the XML Schema compatible representations of these special values. Earlier it has returned what java.text.DecimalFormat did with US locale, none of which was understood by any (common) computer language.

    • FTL hash literals that repeat keys now only have the key once with ?keys, and only has the last value associated to that key with ?values. This is consistent with the behavior of hash[key] and how maps work in Java.

    • In most cases (where FreeMarker is able to do that), for freemarker.cache.TemplateLoader-s that use java.net.URLConnection, URLConnection#setUseCaches(boolean) will called with false, so that only FreeMarker will do caching, not the URL scheme's handler. See freemarker.cache.URLTemplateLoader.setURLConnectionUsesCaches(java.lang.Boolean) for more details.

    • The default of the template_loader setting (getTemplateLoader()) changes to null, which means that FreeMarker will not find any templates. Earlier the default was a freemarker.cache.FileTemplateLoader that used the current directory as the root. This was dangerous and fragile as you usually don't have good control over what the current directory will be. Luckily, the old default almost never looked for the templates at the right place anyway, so pretty much all applications had to set the template_loader setting, so it's unlikely that changing the default breaks your application.

    • Right-unlimited ranges become readable (like listable), so <#list 1.. as i>...</#list> works. Earlier they were only usable for slicing (like hits[10..]).

    • Empty ranges return freemarker.template.utility.Constants.EMPTY_SEQUENCE instead of an empty SimpleSequence. This is in theory backward compatible, as the API only promises to give something that implements TemplateSequenceModel.

    • Unclosed comments (<#-- ...) and #noparse-s won't be silently closed at the end of template anymore, but cause a parsing error instead.

  • 2.3.22 (or higher):

    • DefaultObjectWrapper has some substantial changes with incompatibleImprovements 2.3.22; check them out at DefaultObjectWrapper.(freemarker.template.Version). It's important to know that if you set the object_wrapper setting (to an other value than "default"), rather than leaving it on its default value, the object_wrapper won't inherit the incompatibleImprovements of the Configuration. In that case, if you want the 2.3.22 improvements of DefaultObjectWrapper, you have to set it in the DefaultObjectWrapper object itself too! (Note that it's OK to use a DefaultObjectWrapper with a different incompatibleImprovements version number than that of the Configuration, if that's really what you want.)

    • In templates, .template_name will always return the main (top level) template's name. It won't be affected by #include and #nested anymore. This is unintended, a bug with incompatible_improvement 2.3.22 (a consequence of the lower level fixing described in the next point). The old behavior of .template_name is restored if you set incompatible_improvement to 2.3.23 (while freemarker.core.Configurable.getParent()) of freemarker.core.Environment keeps the changed behavior shown in the next point).

    • #include and #nested doesn't change the parent Template (see freemarker.core.Configurable.getParent()) of the freemarker.core.Environment anymore to the Template that's included or whose namespace #nested "returns" to. Thus, the parent of freemarker.core.Environment will be now always the main Template. (The main Template is the Template whose process or createProcessingEnvironment method was called to initiate the output generation.) Note that apart from the effect on FTL's .template_name (see previous point), this should only matter if you have set settings directly on Template objects, and almost nobody does that. Also note that macro calls have never changed the freemarker.core.Environment parent to the Template that contains the macro definition, so this mechanism was always broken. As now we consistently never change the parent, the behavior when calling macros didn't change.

    • When using freemarker.ext.servlet.FreemarkerServlet:

      • When using custom JSP tag libraries: Fixes bug where some kind of values, when put into the JSP page scope (via #global or via the JSP PageContext API) and later read back with the JSP PageContext API (typically in a custom JSP tag), might come back as FreeMarker TemplateModel 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 ?date/time/datetime), or you had to use DefaultObjectWrapper or SimpleObjectWrapper (or a subclass of them):

      • Initial "[" in the TemplatePath init-param has special meaning; it's used for specifying multiple comma separated locations, like in <param-value>[ WEB-INF/templates, classpath:com/example/myapp/templates ]</param-value>

      • Initial "{" in the TemplatePath init-param is reserved for future purposes, and thus will throw exception.

  • 2.3.23 (or higher):

    • Fixed a loophole in the implementation of the long existing parse-time rule that says that #break, in the FTL source code itself, must occur nested inside a breakable directive, such as #list or #switch. This check could be circumvented with #macro or #function, like this: <#list 1..1 as x><#macro callMeLater><#break></#macro></#list><@callMeLater />. After activating this fix, this will be a parse time error.

    • If you have used incompatible_improvements 2.3.22 earlier, know that there the behavior of the .template_name special variable used in templates was accidentally altered, but now it's restored to be backward compatible with 2.3.0. (Ironically, the restored legacy behavior itself is broken when it comes to macro invocations, we just keep it for backward compatibility. If you need fixed behavior, use .current_template_name or .main_template_name instead.)

Throws:
java.lang.IllegalArgumentException If incompatibleImmprovements refers to a version that wasn't released yet when the currently used FreeMarker version was released, or is less than 2.3.0, or is null.
Since:
2.3.21
 
     public Configuration(Version incompatibleImprovements) {
         super(incompatibleImprovements);
         
         // We postpone this until here (rather that doing this in static initializer) for two reason:
         // - Class initialization errors are often not reported very well
         // - This way we avoid the error if FM isn't actually used
         checkFreeMarkerVersionClash();
         
         NullArgumentException.check("incompatibleImprovements"incompatibleImprovements);
         this. = incompatibleImprovements;
         
         createTemplateCache();
         loadBuiltInSharedVariables();
     }
 
     private static void checkFreeMarkerVersionClash() {
         if () {
             throw new RuntimeException("Clashing FreeMarker versions (" +  + " and some post-2.3.x) detected: "
                     + "found post-2.3.x class " +  + ". You probably have two different "
                     + "freemarker.jar-s in the classpath.");
         }
     }
     
     private void createTemplateCache() {
          = new TemplateCache(
                 getDefaultTemplateLoader(),
                 getDefaultCacheStorage(),
                 getDefaultTemplateLookupStrategy(),
                 getDefaultTemplateNameFormat(),
                 this);
         .clear(); // for fully BC behavior
         .setDelay(5000);
     }
     
     private void recreateTemplateCacheWith(
             TemplateLoader loaderCacheStorage storageTemplateLookupStrategy templateLookupStrategy,
             TemplateNameFormat templateNameFormat) {
         TemplateCache oldCache = ;
          = new TemplateCache(loaderstoragetemplateLookupStrategytemplateNameFormatthis);
         .clear(); // for fully BC behavior
         .setDelay(oldCache.getDelay());
     }
     
     }
 
     static TemplateLoader createDefaultTemplateLoader(Version incompatibleImprovements) {
         return createDefaultTemplateLoader(incompatibleImprovementsnull);
     }
     
     private static TemplateLoader createDefaultTemplateLoader(
             Version incompatibleImprovementsTemplateLoader existingTemplateLoader) {
         if (incompatibleImprovements.intValue() < .) {
             if (existingTemplateLoader instanceof LegacyDefaultFileTemplateLoader) {
                 return existingTemplateLoader;
             }
             try {
                 return new LegacyDefaultFileTemplateLoader();
             } catch(Exception e) {
                 .warn("Couldn't create legacy default TemplateLoader which accesses the current directory. "
                         + "(Use new Configuration(Configuration.VERSION_2_3_21) or higher to avoid this.)"e);
                 return null;
             }
         } else {
             return null;
         }
     }
     
     private static class LegacyDefaultFileTemplateLoader extends FileTemplateLoader {
 
         public LegacyDefaultFileTemplateLoader() throws IOException {
             super();
         }
         
     }
     
     }
     
     static TemplateLookupStrategy getDefaultTemplateLookupStrategy(Version incompatibleImprovements) {
         return .;
     }
     
     }
     
     static TemplateNameFormat getDefaultTemplateNameFormat(Version incompatibleImprovements) {
         return .;
     }
     
     private CacheStorage getDefaultCacheStorage() {
     }
     
     static CacheStorage createDefaultCacheStorage(Version incompatibleImprovementsCacheStorage existingCacheStorage) {
         if (existingCacheStorage instanceof DefaultSoftCacheStorage) {
             return existingCacheStorage;
         }
         return new DefaultSoftCacheStorage(); 
     }
     
     static CacheStorage createDefaultCacheStorage(Version incompatibleImprovements) {
         return createDefaultCacheStorage(incompatibleImprovementsnull); 
     }
     
     private static class DefaultSoftCacheStorage extends SoftCacheStorage {
         // Nothing to override
     }
 
     }
     
     private boolean getDefaultLogTemplateExceptions() {
     }
     
     private ObjectWrapper getDefaultObjectWrapper() {
     }
     
     // Package visible as Configurable needs this to initialize the field defaults.
     final static TemplateExceptionHandler getDefaultTemplateExceptionHandler(Version incompatibleImprovements) {
         return .;
     }
 
     // Package visible as Configurable needs this to initialize the field defaults.
     final static boolean getDefaultLogTemplateExceptions(Version incompatibleImprovements) {
         return true;
     }
     
     public Object clone() {
         try {
             Configuration copy = (Configuration)super.clone();
             copy.sharedVariables = new HashMap();
             copy.localeToCharsetMap = new HashMap();
             copy.autoImportNsToTmpMap = new HashMap();
             copy.autoImports = (ArrayList.clone();
             copy.autoIncludes = (ArrayList.clone();
             copy.recreateTemplateCacheWith(
                     .getTemplateLoader(), .getCacheStorage(),
                     .getTemplateLookupStrategy(), .getTemplateNameFormat());
             return copy;
         } catch (CloneNotSupportedException e) {
             throw new BugException(e.getMessage());  // Java 5: use cause exc.
         }
     }
     
     private void loadBuiltInSharedVariables() {
         .put("capture_output"new CaptureOutput());
         .put("compress".);
         .put("html_escape"new HtmlEscape());
         .put("normalize_newlines"new NormalizeNewlines());
         .put("xml_escape"new XmlEscape());
     }
    
    
Loads a preset language-to-encoding map, similarly as if you have called clearEncodingMap() and then did multiple setEncoding(java.util.Locale,java.lang.String) calls. It assumes the usual character encodings for most languages. The previous content of the encoding map will be lost. This default map currently contains the following mappings:
arISO-8859-6
beISO-8859-5
bgISO-8859-5
caISO-8859-1
csISO-8859-2
daISO-8859-1
deISO-8859-1
elISO-8859-7
enISO-8859-1
esISO-8859-1
etISO-8859-1
fiISO-8859-1
frISO-8859-1
hrISO-8859-2
huISO-8859-2
isISO-8859-1
itISO-8859-1
iwISO-8859-8
jaShift_JIS
koEUC-KR
ltISO-8859-2
lvISO-8859-2
mkISO-8859-5
nlISO-8859-1
noISO-8859-1
plISO-8859-2
ptISO-8859-1
roISO-8859-2
ruISO-8859-5
shISO-8859-5
skISO-8859-2
slISO-8859-2
sqISO-8859-2
srISO-8859-5
svISO-8859-1
trISO-8859-9
ukISO-8859-5
zhGB2312
zh_TWBig5

 
     public void loadBuiltInEncodingMap() {
         .clear();
         .put("ar""ISO-8859-6");
         .put("be""ISO-8859-5");
         .put("bg""ISO-8859-5");
         .put("ca""ISO-8859-1");
         .put("cs""ISO-8859-2");
         .put("da""ISO-8859-1");
         .put("de""ISO-8859-1");
         .put("el""ISO-8859-7");
         .put("en""ISO-8859-1");
         .put("es""ISO-8859-1");
         .put("et""ISO-8859-1");
         .put("fi""ISO-8859-1");
         .put("fr""ISO-8859-1");
         .put("hr""ISO-8859-2");
         .put("hu""ISO-8859-2");
         .put("is""ISO-8859-1");
         .put("it""ISO-8859-1");
         .put("iw""ISO-8859-8");
         .put("ja""Shift_JIS");
         .put("ko""EUC-KR");    
         .put("lt""ISO-8859-2");
         .put("lv""ISO-8859-2");
         .put("mk""ISO-8859-5");
         .put("nl""ISO-8859-1");
         .put("no""ISO-8859-1");
         .put("pl""ISO-8859-2");
         .put("pt""ISO-8859-1");
         .put("ro""ISO-8859-2");
         .put("ru""ISO-8859-5");
         .put("sh""ISO-8859-5");
         .put("sk""ISO-8859-2");
         .put("sl""ISO-8859-2");
         .put("sq""ISO-8859-2");
         .put("sr""ISO-8859-5");
         .put("sv""ISO-8859-1");
         .put("tr""ISO-8859-9");
         .put("uk""ISO-8859-5");
         .put("zh""GB2312");
         .put("zh_TW""Big5");
     }

    
 
     public void clearEncodingMap() {
         .clear();
     }

    
Returns the default (singleton) Configuration object. Note that you can create as many separate configurations as you wish; this global instance is provided for convenience, or when you have no reason to use a separate instance.

Deprecated:
The usage of the static singleton (the "default") Configuration instance can easily cause erroneous, unpredictable behavior. This is because multiple independent software components may use FreeMarker internally inside the same application, so they will interfere because of the common Configuration instance. Each such component should use its own private Configuration object instead, that it typically creates with new Configuration() when the component is initialized.
 
     static public Configuration getDefaultConfiguration() {
         // Java 5: use volatile + double check
         synchronized () {
             if ( == null) {
                  = new Configuration();
             }
             return ;
         }
     }

    
Sets the Configuration object that will be retrieved from future calls to getDefaultConfiguration().

Deprecated:
Using the "default" Configuration instance can easily lead to erroneous, unpredictable behaviour. See more here....
 
     static public void setDefaultConfiguration(Configuration config) {
         synchronized () {
              = config;
         }
     }
    
    
Sets a freemarker.cache.TemplateLoader that is used to look up and load templates; as a side effect the template cache will be emptied. By providing your own freemarker.cache.TemplateLoader implementation, you can load templates from whatever kind of storages, like from relational databases, NoSQL-storages, etc.

Convenience methods exists to install commonly used loaders, instead of using this method: setClassForTemplateLoading(java.lang.Class,java.lang.String), setClassLoaderForTemplateLoading(java.lang.ClassLoader,java.lang.String), setDirectoryForTemplateLoading(java.io.File), and setServletContextForTemplateLoading(java.lang.Object,java.lang.String).

You can chain several freemarker.cache.TemplateLoader-s together with freemarker.cache.MultiTemplateLoader.

Default value: You should always set the template loader instead of relying on the default value. (But if you still care what it is, before "incompatible improvements" 2.3.21 it's a freemarker.cache.FileTemplateLoader that uses the current directory as its root; as it's hard tell what that directory will be, it's not very useful and dangerous. Starting with "incompatible improvements" 2.3.21 the default is null.)

 
     public void setTemplateLoader(TemplateLoader templateLoader) {
         // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration
         synchronized (this) {
             if (.getTemplateLoader() != templateLoader) {
                 recreateTemplateCacheWith(templateLoader.getCacheStorage(),
                         .getTemplateLookupStrategy(), .getTemplateNameFormat());
             }
              = true;
         }
     }
    
    
Resets the setting to its default, as it was never set. This means that when you change the incompatibe_improvements setting later, the default will also change as appropriate. Also isTemplateLoaderExplicitlySet() will return false.

Since:
2.3.22
 
     public void unsetTemplateLoader() {
         if () {
             setTemplateLoader(getDefaultTemplateLoader());
              = false;
         }
     }

    
Tells if setTemplateLoader(freemarker.cache.TemplateLoader) (or equivalent) was already called on this instance.

Since:
2.3.22
 
     public boolean isTemplateLoaderExplicitlySet() {
         return ;
     }

    
 
     public TemplateLoader getTemplateLoader() {
         if ( == null) {
             return null;
         }
         return .getTemplateLoader();
     }
    
    
Sets a freemarker.cache.TemplateLookupStrategy that is used to look up templates based on the requested name; as a side effect the template cache will be emptied. The default value is freemarker.cache.TemplateLookupStrategy.DEFAULT_2_3_0.

Since:
2.3.22
    public void setTemplateLookupStrategy(TemplateLookupStrategy templateLookupStrategy) {
        if (.getTemplateLookupStrategy() != templateLookupStrategy) {
                    templateLookupStrategy.getTemplateNameFormat());
        }
         = true;
    }

    
Resets the setting to its default, as it was never set. This means that when you change the incompatibe_improvements setting later, the default will also change as appropriate. Also isTemplateLookupStrategyExplicitlySet() will return false.

Since:
2.3.22
    public void unsetTemplateLookupStrategy() {
             = false;
        }
    }
    
    
Tells if setTemplateLookupStrategy(freemarker.cache.TemplateLookupStrategy) (or equivalent) was already called on this instance.

Since:
2.3.22
    public boolean isTemplateLookupStrategyExplicitlySet() {
    }
    
    
        if ( == null) {
            return null;
        }
        return .getTemplateLookupStrategy();
    }
    
    
Sets the template name format used. The default is freemarker.cache.TemplateNameFormat.DEFAULT_2_3_0, while the recommended value for new projects is freemarker.cache.TemplateNameFormat.DEFAULT_2_4_0.

Since:
2.3.22
    public void setTemplateNameFormat(TemplateNameFormat templateNameFormat) {
        if (.getTemplateNameFormat() != templateNameFormat) {
                    .getTemplateLookupStrategy(), templateNameFormat);
        }
         = true;
    }

    
Resets the setting to its default, as it was never set. This means that when you change the incompatibe_improvements setting later, the default will also change as appropriate. Also isTemplateNameFormatExplicitlySet() will return false.

Since:
2.3.22
    public void unsetTemplateNameFormat() {
        if () {
             = false;
        }
    }
    
    
Tells if setTemplateNameFormat(freemarker.cache.TemplateNameFormat) (or equivalent) was already called on this instance.

Since:
2.3.22
    public boolean isTemplateNameFormatExplicitlySet() {
        return ;
    }

    
        if ( == null) {
            return null;
        }
        return .getTemplateNameFormat();
    }

    
Sets the freemarker.cache.CacheStorage used for caching Template-s; the earlier content of the template cache will be dropt. The default is a freemarker.cache.SoftCacheStorage. If the total size of the Template objects is significant but most templates are used rarely, using a freemarker.cache.MruCacheStorage instead might be advisable. If you don't want caching at all, use freemarker.cache.NullCacheStorage (you can't use null).

Note that setting the cache storage will re-create the template cache, so all its content will be lost.

    public void setCacheStorage(CacheStorage cacheStorage) {
        // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration
        synchronized (this) {
            if (getCacheStorage() != cacheStorage) {
                recreateTemplateCacheWith(.getTemplateLoader(), cacheStorage,
                        .getTemplateLookupStrategy(), .getTemplateNameFormat());
            }
             = true;
        }
    }
    
    
Resets the setting to its default, as it was never set. This means that when you change the incompatibe_improvements setting later, the default will also change as appropriate. Also isCacheStorageExplicitlySet() will return false.

Since:
2.3.22
    public void unsetCacheStorage() {
        if () {
            setCacheStorage(getDefaultCacheStorage());
             = false;
        }
    }
    
    
Tells if setCacheStorage(freemarker.cache.CacheStorage) (or equivalent) was already called on this instance.

Since:
2.3.22
    public boolean isCacheStorageExplicitlySet() {
        return ;
    }
    
    
The getter pair of setCacheStorage(freemarker.cache.CacheStorage).

Since:
2.3.20
    public CacheStorage getCacheStorage() {
        // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration
        synchronized (this) {
            if ( == null) {
                return null;
            }
            return .getCacheStorage();
        }
    }

    
Sets the file system directory from which to load templates. This is equivalent to setTemplateLoader(new FileTemplateLoader(dir)), so see freemarker.cache.FileTemplateLoader.(java.io.File) for more details. Note that FreeMarker can load templates from non-file-system sources too. See setTemplateLoader(freemarker.cache.TemplateLoader) from more details.
    public void setDirectoryForTemplateLoading(File dirthrows IOException {
        TemplateLoader tl = getTemplateLoader();
        if (tl instanceof FileTemplateLoader) {
            String path = ((FileTemplateLoadertl)..getCanonicalPath();
            if (path.equals(dir.getCanonicalPath()))
                return;
        }
        setTemplateLoader(new FileTemplateLoader(dir));
    }

    
Sets the servlet context from which to load templates. This is equivalent to setTemplateLoader(new WebappTemplateLoader(sctxt, path)) or setTemplateLoader(new WebappTemplateLoader(sctxt)) if path was null, so see freemarker.cache.WebappTemplateLoader for more details.

Parameters:
servletContext the javax.servlet.ServletContext object. (The declared type is java.lang.Object to prevent class loading error when using FreeMarker in an environment where there's no servlet classes available.)
path the path relative to the ServletContext.
See also:
setTemplateLoader(freemarker.cache.TemplateLoader)
    public void setServletContextForTemplateLoading(Object servletContextString path) {
        try {
            // Don't introduce linking-time dependency on servlets
            final Class webappTemplateLoaderClass = ClassUtil.forName("freemarker.cache.WebappTemplateLoader");
            
            // Don't introduce linking-time dependency on servlets
            final Class servletContextClass = ClassUtil.forName("javax.servlet.ServletContext");
            
            final Class[] constructorParamTypes;
            final Object[] constructorParams;
            if (path == null) {
                constructorParamTypes = new Class[] { servletContextClass };
                constructorParams = new Object[] { servletContext };
            } else {
                constructorParamTypes = new Class[] { servletContextClassString.class };
                constructorParams = new Object[] { servletContextpath };
            }
            
            setTemplateLoader( (TemplateLoader)
                    webappTemplateLoaderClass
                            .getConstructor(constructorParamTypes)
                                    .newInstance(constructorParams));
        } catch (Exception e) {
            throw new BugException(e);
        }
    }

    
Sets the class whose java.lang.Class.getResource(java.lang.String) method will be used to load templates, from the inside the package specified. See freemarker.cache.ClassTemplateLoader.(java.lang.Class,java.lang.String) for more details.

Parameters:
basePackagePath Separate steps with "/", not ".", and note that it matters if this starts with / or not. See freemarker.cache.ClassTemplateLoader.(java.lang.Class,java.lang.String) for more details.
See also:
setClassLoaderForTemplateLoading(java.lang.ClassLoader,java.lang.String)
setTemplateLoader(freemarker.cache.TemplateLoader)
    public void setClassForTemplateLoading(Class resourceLoaderClassString basePackagePath) {
        setTemplateLoader(new ClassTemplateLoader(resourceLoaderClassbasePackagePath));
    }
    
    
Sets the java.lang.ClassLoader whose java.lang.ClassLoader.getResource(java.lang.String) method will be used to load templates, from the inside the package specified. See freemarker.cache.ClassTemplateLoader.(java.lang.Class,java.lang.String) for more details.

    public void setClassLoaderForTemplateLoading(ClassLoader classLoaderString basePackagePath) {
        setTemplateLoader(new ClassTemplateLoader(classLoaderbasePackagePath));
    }

    
Sets the time in seconds that must elapse before checking whether there is a newer version of a template "file" than the cached one.

Historical note: Despite what the API documentation said earlier, this method is not thread-safe. While it works well on most hardware, it's not guaranteed that FreeMarker will see the update in all threads, and theoretically it's also possible that it will see a value that's a binary mixture of the new and the old one.

Deprecated:
Use setTemplateUpdateDelayMilliseconds(long) instead, because the time granularity of this method is often misunderstood to be milliseconds.
    public void setTemplateUpdateDelay(int seconds) {
        .setDelay(1000L * seconds);
    }

    
Sets the time in milliseconds that must elapse before checking whether there is a newer version of a template "file" exists than the cached one. Defaults to 5000 ms.

When you get a template via getTemplate(java.lang.String) (or some of its overloads). FreeMarker will try to get the template from the template cache. If the template is found, and at least this amount of time was elapsed since the template last modification date was checked, FreeMarker will re-check the last modification date (this could mean I/O), possibly reloading the template and updating the cache as a consequence (can mean even more I/O). The getTemplate(java.lang.String) (or some of its overloads) call will only return after this all is done, so it will return the fresh template.

Since:
2.3.23
    public void setTemplateUpdateDelayMilliseconds(long millis) {
        .setDelay(millis);
    }
    
    
The getter pair of setTemplateUpdateDelayMilliseconds(long).

Since:
2.3.23
    public long getTemplateUpdateDelayMilliseconds() {
        return .getDelay();
    }
    
    
Sets whether directives such as if, else, etc must be written as #if, #else, etc. Defaults to true.

When this is true, any tag not starting with <# or </# or <@ or </@ is considered as plain text and will go to the output as is. Tag starting with <# or </# must be valid FTL tag, or else the template is invalid (i.e. <#noSuchDirective> is an error).

Deprecated:
Only true (the default) value will be supported sometimes in the future.
    public void setStrictSyntaxMode(boolean b) {
         = b;
    }
    public void setObjectWrapper(ObjectWrapper objectWrapper) {
        ObjectWrapper prevObjectWrapper = getObjectWrapper();
        super.setObjectWrapper(objectWrapper);
         = true;
        if (objectWrapper != prevObjectWrapper) {
            try {
                setSharedVariablesFromRewrappableSharedVariables();
            } catch (TemplateModelException e) {
                throw new RuntimeException(
                        "Failed to re-wrap earliearly set shared variables with the newly set object wrapper",
                        e);
            }
        }
    }
    
    
Resets the setting to its default, as it was never set. This means that when you change the incompatibe_improvements setting later, the default will also change as appropriate. Also isObjectWrapperExplicitlySet() will return false.

Since:
2.3.22
    public void unsetObjectWrapper() {
        if () {
            setObjectWrapper(getDefaultObjectWrapper());
             = false;
        }
    }
    
    
Tells if setObjectWrapper(freemarker.template.ObjectWrapper) (or equivalent) was already called on this instance.

Since:
2.3.22
    public boolean isObjectWrapperExplicitlySet() {
        return ;
    }
    
    public void setTemplateExceptionHandler(TemplateExceptionHandler templateExceptionHandler) {
        super.setTemplateExceptionHandler(templateExceptionHandler);
    }

    
Resets the setting to its default, as it was never set. This means that when you change the incompatibe_improvements setting later, the default will also change as appropriate. Also isTemplateExceptionHandlerExplicitlySet() will return false.

Since:
2.3.22
    public void unsetTemplateExceptionHandler() {
             = false;
        }
    }
    
    
Tells if setTemplateExceptionHandler(freemarker.template.TemplateExceptionHandler) (or equivalent) was already called on this instance.

Since:
2.3.22
    public boolean isTemplateExceptionHandlerExplicitlySet() {
    }    
    
    

Since:
2.3.22
    public void setLogTemplateExceptions(boolean value) {
        super.setLogTemplateExceptions(value);
         = true;
    }

    
Resets the setting to its default, as it was never set. This means that when you change the incompatibe_improvements setting later, the default will also change as appropriate. Also isTemplateExceptionHandlerExplicitlySet() will return false.

Since:
2.3.22
    public void unsetLogTemplateExceptions() {
             = false;
        }
    }
    
    
Tells if setLogTemplateExceptions(boolean) (or equivalent) was already called on this instance.

Since:
2.3.22
    public boolean isLogTemplateExceptionsExplicitlySet() {
    }

    
The getter pair of setStrictSyntaxMode(boolean).
    public boolean getStrictSyntaxMode() {
        return ;
    }

    
Use Configuration(freemarker.template.Version) instead if possible; see the meaning of the parameter there. If the default value of a setting depends on the incompatibleImprovements and the value of that setting was never set in this Configuration object through the public API, its value will be set to the default value appropriate for the new incompatibleImprovements. (This adjustment of a setting value doesn't count as setting that setting, so setting incompatibleImprovements for multiple times also works as expected.) Note that if the template_loader have to be changed because of this, the template cache will be emptied.

Throws:
java.lang.IllegalArgumentException If incompatibleImmprovements refers to a version that wasn't released yet when the currently used FreeMarker version was released, or is less than 2.3.0, or is null.
Since:
2.3.20
    public void setIncompatibleImprovements(Version incompatibleImprovements) {
        _TemplateAPI.checkVersionNotNullAndSupported(incompatibleImprovements);
        
        if (!this..equals(incompatibleImprovements)) {
            this. = incompatibleImprovements;
            
            if (!) {
                 = true
                unsetTemplateLoader();
            }
            if (!) {
                 = true;
                unsetTemplateLookupStrategy();
            }
            
            if (!) {
                 = true;
                unsetTemplateNameFormat();
            }
            
            if (!) {
                 = true;
                unsetCacheStorage();
            }
            
            if (!) {
                 = true;
                unsetTemplateExceptionHandler();
            }
            
            if (!) {
                 = true;
                unsetLogTemplateExceptions();
            }
            
            if (!) {
                 = true;
                unsetObjectWrapper();
            }
        }
    }

    

Returns:
Never null.
Since:
2.3.20
See also:
setIncompatibleImprovements(freemarker.template.Version)
        return ;
    }
    
    
    public void setIncompatibleEnhancements(String version) {
        setIncompatibleImprovements(new Version(version));
    }
    
    

Deprecated:
Use getIncompatibleImprovements() instead.
        return .toString();
    }
    
    

Deprecated:
Use getIncompatibleImprovements() instead.
    public int getParsedIncompatibleEnhancements() {
        return getIncompatibleImprovements().intValue();
    }
    
    
Sets whether the FTL parser will try to remove superfluous white-space around certain FTL tags.
    public void setWhitespaceStripping(boolean b) {
         = b;
    }

    
Gets whether the FTL parser will try to remove superfluous white-space around certain FTL tags.

    public boolean getWhitespaceStripping() {
        return ;
    }
    
    
Determines the syntax of the template files (angle bracket VS square bracket) that has no #ftl in it. The tagSyntax parameter must be one of:

In FreeMarker 2.3.x ANGLE_BRACKET_TAG_SYNTAX is the default for better backward compatibility. Starting from 2.4.x AUTO_DETECT_TAG_SYNTAX is the default, so it's recommended to use that even for 2.3.x.

This setting is ignored for the templates that have ftl directive in it. For those templates the syntax used for the ftl directive determines the syntax.

    public void setTagSyntax(int tagSyntax) {
        if (tagSyntax != 
            && tagSyntax != 
            && tagSyntax != )
        {
            throw new IllegalArgumentException("\"tag_syntax\" can only be set to one of these: "
                    + "Configuration.AUTO_DETECT_TAG_SYNTAX, Configuration.ANGLE_BRACKET_SYNTAX, "
                    + "or Configuration.SQAUARE_BRACKET_SYNTAX");
        }
        this. = tagSyntax;
    }
    
    
The getter pair of setTagSyntax(int).
    public int getTagSyntax() {
        return ;
    }

    
Sets the naming convention used for the identifiers that are part of the template language. The available naming conventions are legacy (directive (tag) names are all-lower-case likethis, others are snake case like_this), and camel case (likeThis). The default is auto-detect, which detects the naming convention used and enforces that same naming convention for the whole template.

This setting doesn't influence what naming convention is used for the setting names outside templates. Also, it won't ever convert the names of user-defined things, like of data-model members, or the names of user defined macros/functions. It only influences the names of the built-in directives (#elseIf VS elseif), built-ins (?upper_case VS ?upperCase ), special variables (.data_model VS .dataModel).

Which convention to use: FreeMarker prior to 2.3.23 has only supported LEGACY_NAMING_CONVENTION, so that's how most templates and examples out there are written as of 2015. But as templates today are mostly written by programmers and often access Java API-s which already use camel case, CAMEL_CASE_NAMING_CONVENTION is the recommended option for most projects. However, it's no necessary to make a application-wide decision; see auto-detection below.

FreeMarker will decide the naming convention automatically for each template individually when this setting is set to AUTO_DETECT_NAMING_CONVENTION (which is the default). The naming convention of a template is decided when the first core (non-user-defined) identifier is met during parsing (not during processing) where the naming convention is relevant (like for s?upperCase or s?upper_case it's relevant, but for s?length it isn't). At that point, the naming convention of the template is decided, and any later core identifier that uses a different convention will be a parsing error. As the naming convention is decided per template, it's not a problem if a template and the other template it #include-s/#import uses a different convention.

FreeMarker always enforces the same naming convention to be used consistently within the same template "file". Additionally, when this setting is set to non-AUTO_DETECT_NAMING_CONVENTION, the selected naming convention is enforced on all templates. Thus such a setup can be used to enforce an application-wide naming convention.

Non-strict tags (a long deprecated syntax from FreeMarker 1, activated via setStrictSyntaxMode(boolean)) are only recognized as FTL tags when they are using the LEGACY_NAMING_CONVENTION syntax, regardless of this setting. As they aren't exempt from the naming convention consistency enforcement, generally, you can't use strict CAMEL_CASE_NAMING_CONVENTION tags mixed with non-strict tags.

Parameters:
namingConvention One of the AUTO_DETECT_NAMING_CONVENTION or LEGACY_NAMING_CONVENTION CAMEL_CASE_NAMING_CONVENTION.
Throws:
java.lang.IllegalArgumentException If the parameter isn't one of the valid constants.
Since:
2.3.23
    public void setNamingConvention(int namingConvention) {
        if (namingConvention != 
            && namingConvention != 
            && namingConvention != )
        {
            throw new IllegalArgumentException("\"naming_convention\" can only be set to one of these: "
                    + "Configuration.AUTO_DETECT_NAMING_CONVENTION, "
                    + "or Configuration.LEGACY_NAMING_CONVENTION"
                    + "or Configuration.CAMEL_CASE_NAMING_CONVENTION");
        }
        this. = namingConvention;
    }
    
    
The getter pair of setNamingConvention(int).

Since:
2.3.23
    public int getNamingConvention() {
        return ;
    }
    
    
Retrieves the template with the given name from the template cache, loading it into the cache first if it's missing/staled.

This is a shorthand for getTemplate(name, null, null, null, true, false); see more details there.

See Configuration for an example of basic usage.

    public Template getTemplate(String name)
        return getTemplate(namenullnullnulltruefalse);
    }

    
Shorthand for getTemplate(name, locale, null, null, true, false).
    public Template getTemplate(String nameLocale locale)
        return getTemplate(namelocalenullnulltruefalse);
    }

    
Shorthand for getTemplate(name, null, null, encoding, true, false).
    public Template getTemplate(String nameString encoding)
        return getTemplate(namenullnullencodingtruefalse);
    }

    
Shorthand for getTemplate(name, locale, null, encoding, true, false).
    public Template getTemplate(String nameLocale localeString encoding)
        return getTemplate(namelocalenullencodingtruefalse);
    }
    
    
Shorthand for getTemplate(name, locale, null, encoding, parseAsFTL, false).
    public Template getTemplate(String nameLocale localeString encodingboolean parseAsFTL)
        return getTemplate(namelocalenullencodingparseAsFTLfalse);
    }

    
Shorthand for getTemplate(name, locale, null, encoding, parseAsFTL, ignoreMissing).

Since:
2.3.21
    public Template getTemplate(String nameLocale localeString encodingboolean parseAsFTLboolean ignoreMissing)
        return getTemplate(namelocalenullencodingparseAsFTLignoreMissing);
    }
    
    
Retrieves the template with the given name (and according the specified further parameters) from the template cache, loading it into the cache first if it's missing/staled.

This method is thread-safe.

See Configuration for an example of basic usage.

Parameters:
name The name or path of the template, which is not a real path, but interpreted inside the current freemarker.cache.TemplateLoader. Can't be null. The exact syntax of the name depends on the underlying freemarker.cache.TemplateLoader, but the cache makes some assumptions. First, the name is expected to be a hierarchical path, with path components separated by a slash character (not with backslash!). The path (the name) given here must not begin with slash; it's always interpreted relative to the "template root directory". Then, the .. and . path meta-elements will be resolved. For example, if the name is a/../b/./c.ftl, then it will be simplified to b/c.ftl. The rules regarding this are the same as with conventional UN*X paths. The path must not reach outside the template root directory, that is, it can't be something like "../templates/my.ftl" (not even if this path happens to be equivalent with "/my.ftl"). Furthermore, the path is allowed to contain at most one path element whose name is * (asterisk). This path meta-element triggers the acquisition mechanism. If the template is not found in the location described by the concatenation of the path left to the asterisk (called base path) and the part to the right of the asterisk (called resource path), the cache will attempt to remove the rightmost path component from the base path ("go up one directory") and concatenate that with the resource path. The process is repeated until either a template is found, or the base path is completely exhausted.
locale The requested locale of the template. This is what freemarker.core.Configurable.getLocale() on the resulting Template will return. This parameter can be null since 2.3.22, in which case it defaults to freemarker.core.Configurable.getLocale() (note that freemarker.core.Configurable.getLocale() will give the default value, not null). This parameter also drives localized template lookup. Assuming that you have specified en_US as the locale and myTemplate.ftl as the name of the template, and the default freemarker.cache.TemplateLookupStrategy is used and #setLocalizedLookup(boolean) localized_lookup is true, FreeMarker will first try to retrieve myTemplate_en_US.html, then myTemplate.en.ftl, and finally myTemplate.ftl. Note that that the template's locale will be en_US even if it only finds myTemplate.ftl.
customLookupCondition This value can be used by a custom freemarker.cache.TemplateLookupStrategy; has no effect with the default one. Can be null (though it's up to the custom freemarker.cache.TemplateLookupStrategy if it allows that). This object will be used as part of the cache key, so it must to have a proper java.lang.Object.equals(java.lang.Object) and java.lang.Object.hashCode() method. It also should have reasonable java.lang.Object.toString(), as it's possibly quoted in error messages. The expected type is up to the custom freemarker.cache.TemplateLookupStrategy. See also: freemarker.cache.TemplateLookupContext.getCustomLookupCondition().
encoding The charset used to interpret the template source code bytes (if it's read from a binary source). Can be null since 2.3.22, will default to getEncoding(java.util.Locale) where Locale is the locale parameter (when locale was null too, the its default value is used instead).
parseAsFTL If true, the loaded template is parsed and interpreted normally, as a regular FreeMarker template. If false, the loaded template is treated as a static text, so ${...}, <#...> etc. will not have special meaning in it.
ignoreMissing If true, the method won't throw TemplateNotFoundException if the template doesn't exist, instead it returns null. Other kind of exceptions won't be suppressed.
Returns:
the requested template; maybe null when the ignoreMissing parameter is true.
Throws:
TemplateNotFoundException If the template could not be found. Note that this exception extends java.io.IOException.