http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/Configurable.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/Configurable.java b/src/main/java/org/apache/freemarker/core/Configurable.java deleted file mode 100644 index b6c73eb..0000000 --- a/src/main/java/org/apache/freemarker/core/Configurable.java +++ /dev/null @@ -1,2741 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 org.apache.freemarker.core; - -import java.io.IOException; -import java.io.Writer; -import java.text.NumberFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; -import java.util.TimeZone; - -import org.apache.freemarker.core.arithmetic.ArithmeticEngine; -import org.apache.freemarker.core.arithmetic.impl.BigDecimalArithmeticEngine; -import org.apache.freemarker.core.arithmetic.impl.ConservativeArithmeticEngine; -import org.apache.freemarker.core.model.ObjectWrapper; -import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.model.impl.DefaultObjectWrapper; -import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper; -import org.apache.freemarker.core.outputformat.OutputFormat; -import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat; -import org.apache.freemarker.core.outputformat.impl.PlainTextOutputFormat; -import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat; -import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat; -import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat; -import org.apache.freemarker.core.templateresolver.AndMatcher; -import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory; -import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher; -import org.apache.freemarker.core.templateresolver.FirstMatchTemplateConfigurationFactory; -import org.apache.freemarker.core.templateresolver.MergingTemplateConfigurationFactory; -import org.apache.freemarker.core.templateresolver.NotMatcher; -import org.apache.freemarker.core.templateresolver.OrMatcher; -import org.apache.freemarker.core.templateresolver.PathGlobMatcher; -import org.apache.freemarker.core.templateresolver.PathRegexMatcher; -import org.apache.freemarker.core.templateresolver.TemplateLoader; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2; -import org.apache.freemarker.core.util.FTLUtil; -import org.apache.freemarker.core.util.GenericParseException; -import org.apache.freemarker.core.util.OptInTemplateClassResolver; -import org.apache.freemarker.core.util._ClassUtil; -import org.apache.freemarker.core.util._NullArgumentException; -import org.apache.freemarker.core.util._SortedArraySet; -import org.apache.freemarker.core.util._StringUtil; -import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory; -import org.apache.freemarker.core.valueformat.TemplateNumberFormat; -import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory; - -/** - * This is a common superclass of {@link org.apache.freemarker.core.Configuration}, - * {@link org.apache.freemarker.core.Template}, and {@link Environment} classes. - * It provides settings that are common to each of them. FreeMarker - * uses a three-level setting hierarchy - the return value of every setting - * getter method on <code>Configurable</code> objects inherits its value from its parent - * <code>Configurable</code> object, unless explicitly overridden by a call to a - * corresponding setter method on the object itself. The parent of an - * <code>Environment</code> object is a <code>Template</code> object, the - * parent of a <code>Template</code> object is a <code>Configuration</code> - * object. - */ -public class Configurable { - static final String C_TRUE_FALSE = "true,false"; - - static final String NULL = "null"; - static final String DEFAULT = "default"; - static final String JVM_DEFAULT = "JVM default"; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String LOCALE_KEY_SNAKE_CASE = "locale"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String LOCALE_KEY_CAMEL_CASE = "locale"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String LOCALE_KEY = LOCALE_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String NUMBER_FORMAT_KEY_SNAKE_CASE = "number_format"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String NUMBER_FORMAT_KEY_CAMEL_CASE = "numberFormat"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String NUMBER_FORMAT_KEY = NUMBER_FORMAT_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String CUSTOM_NUMBER_FORMATS_KEY_SNAKE_CASE = "custom_number_formats"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String CUSTOM_NUMBER_FORMATS_KEY_CAMEL_CASE = "customNumberFormats"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String CUSTOM_NUMBER_FORMATS_KEY = CUSTOM_NUMBER_FORMATS_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String TIME_FORMAT_KEY_SNAKE_CASE = "time_format"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String TIME_FORMAT_KEY_CAMEL_CASE = "timeFormat"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String TIME_FORMAT_KEY = TIME_FORMAT_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String DATE_FORMAT_KEY_SNAKE_CASE = "date_format"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String DATE_FORMAT_KEY_CAMEL_CASE = "dateFormat"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String DATE_FORMAT_KEY = DATE_FORMAT_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String CUSTOM_DATE_FORMATS_KEY_SNAKE_CASE = "custom_date_formats"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String CUSTOM_DATE_FORMATS_KEY_CAMEL_CASE = "customDateFormats"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String CUSTOM_DATE_FORMATS_KEY = CUSTOM_DATE_FORMATS_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String DATETIME_FORMAT_KEY_SNAKE_CASE = "datetime_format"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String DATETIME_FORMAT_KEY_CAMEL_CASE = "datetimeFormat"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String DATETIME_FORMAT_KEY = DATETIME_FORMAT_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String TIME_ZONE_KEY_SNAKE_CASE = "time_zone"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String TIME_ZONE_KEY_CAMEL_CASE = "timeZone"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String TIME_ZONE_KEY = TIME_ZONE_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String SQL_DATE_AND_TIME_TIME_ZONE_KEY_SNAKE_CASE = "sql_date_and_time_time_zone"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String SQL_DATE_AND_TIME_TIME_ZONE_KEY_CAMEL_CASE = "sqlDateAndTimeTimeZone"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String SQL_DATE_AND_TIME_TIME_ZONE_KEY = SQL_DATE_AND_TIME_TIME_ZONE_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_EXCEPTION_HANDLER_KEY_SNAKE_CASE = "template_exception_handler"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_EXCEPTION_HANDLER_KEY_CAMEL_CASE = "templateExceptionHandler"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String TEMPLATE_EXCEPTION_HANDLER_KEY = TEMPLATE_EXCEPTION_HANDLER_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String ARITHMETIC_ENGINE_KEY_SNAKE_CASE = "arithmetic_engine"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String ARITHMETIC_ENGINE_KEY_CAMEL_CASE = "arithmeticEngine"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String ARITHMETIC_ENGINE_KEY = ARITHMETIC_ENGINE_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String OBJECT_WRAPPER_KEY_SNAKE_CASE = "object_wrapper"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String OBJECT_WRAPPER_KEY_CAMEL_CASE = "objectWrapper"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String OBJECT_WRAPPER_KEY = OBJECT_WRAPPER_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String BOOLEAN_FORMAT_KEY_SNAKE_CASE = "boolean_format"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String BOOLEAN_FORMAT_KEY_CAMEL_CASE = "booleanFormat"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String BOOLEAN_FORMAT_KEY = BOOLEAN_FORMAT_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String OUTPUT_ENCODING_KEY_SNAKE_CASE = "output_encoding"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String OUTPUT_ENCODING_KEY_CAMEL_CASE = "outputEncoding"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String OUTPUT_ENCODING_KEY = OUTPUT_ENCODING_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String URL_ESCAPING_CHARSET_KEY_SNAKE_CASE = "url_escaping_charset"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String URL_ESCAPING_CHARSET_KEY_CAMEL_CASE = "urlEscapingCharset"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String URL_ESCAPING_CHARSET_KEY = URL_ESCAPING_CHARSET_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String AUTO_FLUSH_KEY_SNAKE_CASE = "auto_flush"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String AUTO_FLUSH_KEY_CAMEL_CASE = "autoFlush"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. @since 2.3.17 */ - public static final String AUTO_FLUSH_KEY = AUTO_FLUSH_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String NEW_BUILTIN_CLASS_RESOLVER_KEY_SNAKE_CASE = "new_builtin_class_resolver"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String NEW_BUILTIN_CLASS_RESOLVER_KEY_CAMEL_CASE = "newBuiltinClassResolver"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. @since 2.3.17 */ - public static final String NEW_BUILTIN_CLASS_RESOLVER_KEY = NEW_BUILTIN_CLASS_RESOLVER_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String SHOW_ERROR_TIPS_KEY_SNAKE_CASE = "show_error_tips"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String SHOW_ERROR_TIPS_KEY_CAMEL_CASE = "showErrorTips"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. @since 2.3.21 */ - public static final String SHOW_ERROR_TIPS_KEY = SHOW_ERROR_TIPS_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String API_BUILTIN_ENABLED_KEY_SNAKE_CASE = "api_builtin_enabled"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String API_BUILTIN_ENABLED_KEY_CAMEL_CASE = "apiBuiltinEnabled"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. @since 2.3.22 */ - public static final String API_BUILTIN_ENABLED_KEY = API_BUILTIN_ENABLED_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String LOG_TEMPLATE_EXCEPTIONS_KEY_SNAKE_CASE = "log_template_exceptions"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String LOG_TEMPLATE_EXCEPTIONS_KEY_CAMEL_CASE = "logTemplateExceptions"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. @since 2.3.22 */ - public static final String LOG_TEMPLATE_EXCEPTIONS_KEY = LOG_TEMPLATE_EXCEPTIONS_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.25 */ - public static final String LAZY_IMPORTS_KEY_SNAKE_CASE = "lazy_imports"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.25 */ - public static final String LAZY_IMPORTS_KEY_CAMEL_CASE = "lazyImports"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String LAZY_IMPORTS_KEY = LAZY_IMPORTS_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.25 */ - public static final String LAZY_AUTO_IMPORTS_KEY_SNAKE_CASE = "lazy_auto_imports"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.25 */ - public static final String LAZY_AUTO_IMPORTS_KEY_CAMEL_CASE = "lazyAutoImports"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String LAZY_AUTO_IMPORTS_KEY = LAZY_AUTO_IMPORTS_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.25 */ - public static final String AUTO_IMPORT_KEY_SNAKE_CASE = "auto_import"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.25 */ - public static final String AUTO_IMPORT_KEY_CAMEL_CASE = "autoImport"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String AUTO_IMPORT_KEY = AUTO_IMPORT_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.25 */ - public static final String AUTO_INCLUDE_KEY_SNAKE_CASE = "auto_include"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.25 */ - public static final String AUTO_INCLUDE_KEY_CAMEL_CASE = "autoInclude"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String AUTO_INCLUDE_KEY = AUTO_INCLUDE_KEY_SNAKE_CASE; - - private static final String[] SETTING_NAMES_SNAKE_CASE = new String[] { - // Must be sorted alphabetically! - API_BUILTIN_ENABLED_KEY_SNAKE_CASE, - ARITHMETIC_ENGINE_KEY_SNAKE_CASE, - AUTO_FLUSH_KEY_SNAKE_CASE, - AUTO_IMPORT_KEY_SNAKE_CASE, - AUTO_INCLUDE_KEY_SNAKE_CASE, - BOOLEAN_FORMAT_KEY_SNAKE_CASE, - CUSTOM_DATE_FORMATS_KEY_SNAKE_CASE, - CUSTOM_NUMBER_FORMATS_KEY_SNAKE_CASE, - DATE_FORMAT_KEY_SNAKE_CASE, - DATETIME_FORMAT_KEY_SNAKE_CASE, - LAZY_AUTO_IMPORTS_KEY_SNAKE_CASE, - LAZY_IMPORTS_KEY_SNAKE_CASE, - LOCALE_KEY_SNAKE_CASE, - LOG_TEMPLATE_EXCEPTIONS_KEY_SNAKE_CASE, - NEW_BUILTIN_CLASS_RESOLVER_KEY_SNAKE_CASE, - NUMBER_FORMAT_KEY_SNAKE_CASE, - OBJECT_WRAPPER_KEY_SNAKE_CASE, - OUTPUT_ENCODING_KEY_SNAKE_CASE, - SHOW_ERROR_TIPS_KEY_SNAKE_CASE, - SQL_DATE_AND_TIME_TIME_ZONE_KEY_SNAKE_CASE, - TEMPLATE_EXCEPTION_HANDLER_KEY_SNAKE_CASE, - TIME_FORMAT_KEY_SNAKE_CASE, - TIME_ZONE_KEY_SNAKE_CASE, - URL_ESCAPING_CHARSET_KEY_SNAKE_CASE - }; - - private static final String[] SETTING_NAMES_CAMEL_CASE = new String[] { - // Must be sorted alphabetically! - API_BUILTIN_ENABLED_KEY_CAMEL_CASE, - ARITHMETIC_ENGINE_KEY_CAMEL_CASE, - AUTO_FLUSH_KEY_CAMEL_CASE, - AUTO_IMPORT_KEY_CAMEL_CASE, - AUTO_INCLUDE_KEY_CAMEL_CASE, - BOOLEAN_FORMAT_KEY_CAMEL_CASE, - CUSTOM_DATE_FORMATS_KEY_CAMEL_CASE, - CUSTOM_NUMBER_FORMATS_KEY_CAMEL_CASE, - DATE_FORMAT_KEY_CAMEL_CASE, - DATETIME_FORMAT_KEY_CAMEL_CASE, - LAZY_AUTO_IMPORTS_KEY_CAMEL_CASE, - LAZY_IMPORTS_KEY_CAMEL_CASE, - LOCALE_KEY_CAMEL_CASE, - LOG_TEMPLATE_EXCEPTIONS_KEY_CAMEL_CASE, - NEW_BUILTIN_CLASS_RESOLVER_KEY_CAMEL_CASE, - NUMBER_FORMAT_KEY_CAMEL_CASE, - OBJECT_WRAPPER_KEY_CAMEL_CASE, - OUTPUT_ENCODING_KEY_CAMEL_CASE, - SHOW_ERROR_TIPS_KEY_CAMEL_CASE, - SQL_DATE_AND_TIME_TIME_ZONE_KEY_CAMEL_CASE, - TEMPLATE_EXCEPTION_HANDLER_KEY_CAMEL_CASE, - TIME_FORMAT_KEY_CAMEL_CASE, - TIME_ZONE_KEY_CAMEL_CASE, - URL_ESCAPING_CHARSET_KEY_CAMEL_CASE - }; - - private Configurable parent; - private HashMap<Object, Object> customAttributes; - - private Locale locale; - private String numberFormat; - private String timeFormat; - private String dateFormat; - private String dateTimeFormat; - private TimeZone timeZone; - private TimeZone sqlDataAndTimeTimeZone; - private boolean sqlDataAndTimeTimeZoneSet; - private String booleanFormat; - private String trueStringValue; // deduced from booleanFormat - private String falseStringValue; // deduced from booleanFormat - private TemplateExceptionHandler templateExceptionHandler; - private ArithmeticEngine arithmeticEngine; - private ObjectWrapper objectWrapper; - private String outputEncoding; - private boolean outputEncodingSet; - private String urlEscapingCharset; - private boolean urlEscapingCharsetSet; - private Boolean autoFlush; - private TemplateClassResolver newBuiltinClassResolver; - private Boolean showErrorTips; - private Boolean apiBuiltinEnabled; - private Boolean logTemplateExceptions; - private Map<String, ? extends TemplateDateFormatFactory> customDateFormats; - private Map<String, ? extends TemplateNumberFormatFactory> customNumberFormats; - private LinkedHashMap<String, String> autoImports; - private ArrayList<String> autoIncludes; - private Boolean lazyImports; - private Boolean lazyAutoImports; - private boolean lazyAutoImportsSet; - - /** - * Intended to be called from inside FreeMarker only. - * Creates a top-level configurable, one that doesn't inherit from a parent, and thus stores the default values. - * Called by the {@link Configuration} constructor. - */ - protected Configurable(Version incompatibleImprovements) { - _CoreAPI.checkVersionNotNullAndSupported(incompatibleImprovements); - parent = null; - locale = Configuration.getDefaultLocale(); - timeZone = Configuration.getDefaultTimeZone(); - sqlDataAndTimeTimeZone = null; - numberFormat = "number"; - timeFormat = ""; - dateFormat = ""; - dateTimeFormat = ""; - templateExceptionHandler = Configuration.getDefaultTemplateExceptionHandler(); - arithmeticEngine = BigDecimalArithmeticEngine.INSTANCE; - objectWrapper = Configuration.getDefaultObjectWrapper(incompatibleImprovements); - autoFlush = Boolean.TRUE; - newBuiltinClassResolver = TemplateClassResolver.UNRESTRICTED_RESOLVER; - showErrorTips = Boolean.TRUE; - apiBuiltinEnabled = Boolean.FALSE; - logTemplateExceptions = Boolean.FALSE; - // outputEncoding and urlEscapingCharset defaults to null, - // which means "not specified" - setBooleanFormat(C_TRUE_FALSE); - - customAttributes = new HashMap(); - - customDateFormats = Collections.emptyMap(); - customNumberFormats = Collections.emptyMap(); - - lazyImports = false; - lazyAutoImportsSet = true; - - initAutoImportsMap(); - initAutoIncludesList(); - } - - /** - * Creates a new instance. Normally you do not need to use this constructor, - * as you don't use <code>Configurable</code> directly, but its subclasses. - */ - protected Configurable(Configurable parent) { - this.parent = parent; - locale = null; - numberFormat = null; - templateExceptionHandler = null; - customAttributes = new HashMap(0); - } - - /** - * Returns the parent {@link Configurable} object of this object. The parent stores the default setting values for - * this {@link Configurable}. For example, the parent of a {@link org.apache.freemarker.core.Template} object is a - * {@link Configuration} object, so values not specified on {@link Template}-level are get from the - * {@link Configuration} object. - * - * <p> - * Note on the parent of {@link Environment}: If you set {@link Configuration#setIncompatibleImprovements(Version) - * incompatible_improvements} to at least 2.3.22, it will be always the "main" {@link Template}, that is, the - * template for whose processing the {@link Environment} was created. With lower {@code incompatible_improvements}, - * the current parent can temporary change <em>during template execution</em>, for example when your are inside an - * {@code #include}-d template (among others). Thus, don't build on which {@link Template} the parent of - * {@link Environment} is during template execution, unless you set {@code incompatible_improvements} to 2.3.22 or - * higher. - * - * @return The parent {@link Configurable} object, or {@code null} if this is the root {@link Configurable} object - * (i.e, if it's the {@link Configuration} object). - */ - public final Configurable getParent() { - return parent; - } - - /** - * Reparenting support. This is used by Environment when it includes a - * template - the included template becomes the parent configurable during - * its evaluation. - */ - void setParent(Configurable parent) { - this.parent = parent; - } - - /** - * Sets the default locale used for number and date formatting (among others), also the locale used for searching - * localized template variations when no locale was explicitly requested. - * - * @see Configuration#getTemplate(String, Locale) - */ - public void setLocale(Locale locale) { - _NullArgumentException.check("locale", locale); - this.locale = locale; - } - - /** - * Returns the assumed locale when searching for template files with no - * explicit requested locale. Defaults to system locale. - */ - public Locale getLocale() { - return locale != null ? locale : parent.getLocale(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isLocaleSet() { - return locale != null; - } - - /** - * Sets the time zone to use when formatting date/time values. - * Defaults to the system time zone ({@link TimeZone#getDefault()}), regardless of the "locale" FreeMarker setting, - * so in a server application you probably want to set it explicitly in the {@link Environment} to match the - * preferred time zone of target audience (like the Web page visitor). - * - * <p>If you or the templates set the time zone, you should probably also set - * {@link #setSQLDateAndTimeTimeZone(TimeZone)}! - * - * @see #setSQLDateAndTimeTimeZone(TimeZone) - */ - public void setTimeZone(TimeZone timeZone) { - _NullArgumentException.check("timeZone", timeZone); - this.timeZone = timeZone; - } - - /** - * The getter pair of {@link #setTimeZone(TimeZone)}. - */ - public TimeZone getTimeZone() { - return timeZone != null ? timeZone : parent.getTimeZone(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isTimeZoneSet() { - return timeZone != null; - } - - /** - * Sets the time zone used when dealing with {@link java.sql.Date java.sql.Date} and - * {@link java.sql.Time java.sql.Time} values. It defaults to {@code null} for backward compatibility, but in most - * application this should be set to the JVM default time zone (server default time zone), because that's what - * most JDBC drivers will use when constructing the {@link java.sql.Date java.sql.Date} and - * {@link java.sql.Time java.sql.Time} values. If this setting is {@code null}, FreeMarker will use the value of - * ({@link #getTimeZone()}) for {@link java.sql.Date java.sql.Date} and {@link java.sql.Time java.sql.Time} values, - * which often gives bad results. - * - * <p>This setting doesn't influence the formatting of other kind of values (like of - * {@link java.sql.Timestamp java.sql.Timestamp} or plain {@link java.util.Date java.util.Date} values). - * - * <p>To decide what value you need, a few things has to be understood: - * <ul> - * <li>Date-only and time-only values in SQL-oriented databases are usually store calendar and clock field - * values directly (year, month, day, or hour, minute, seconds (with decimals)), as opposed to a set of points - * on the physical time line. Thus, unlike SQL timestamps, these values usually aren't meant to be shown - * differently depending on the time zone of the audience. - * - * <li>When a JDBC query has to return a date-only or time-only value, it has to convert it to a point on the - * physical time line, because that's what {@link java.util.Date} and its subclasses store (milliseconds since - * the epoch). Obviously, this is impossible to do. So JDBC just chooses a physical time which, when rendered - * <em>with the JVM default time zone</em>, will give the same field values as those stored - * in the database. (Actually, you can give JDBC a calendar, and so it can use other time zones too, but most - * application won't care using those overloads.) For example, assume that the system time zone is GMT+02:00. - * Then, 2014-07-12 in the database will be translated to physical time 2014-07-11 22:00:00 UTC, because that - * rendered in GMT+02:00 gives 2014-07-12 00:00:00. Similarly, 11:57:00 in the database will be translated to - * physical time 1970-01-01 09:57:00 UTC. Thus, the physical time stored in the returned value depends on the - * default system time zone of the JDBC client, not just on the content in the database. (This used to be the - * default behavior of ORM-s, like Hibernate, too.) - * - * <li>The value of the {@code time_zone} FreeMarker configuration setting sets the time zone used for the - * template output. For example, when a web page visitor has a preferred time zone, the web application framework - * may calls {@link Environment#setTimeZone(TimeZone)} with that time zone. Thus, the visitor will - * see {@link java.sql.Timestamp java.sql.Timestamp} and plain {@link java.util.Date java.util.Date} values as - * they look in his own time zone. While - * this is desirable for those types, as they meant to represent physical points on the time line, this is not - * necessarily desirable for date-only and time-only values. When {@code sql_date_and_time_time_zone} is - * {@code null}, {@code time_zone} is used for rendering all kind of date/time/dateTime values, including - * {@link java.sql.Date java.sql.Date} and {@link java.sql.Time java.sql.Time}, and then if, for example, - * {@code time_zone} is GMT+00:00, the - * values from the earlier examples will be shown as 2014-07-11 (one day off) and 09:57:00 (2 hours off). While - * those are the time zone correct renderings, those values are probably meant to be shown "as is". - * - * <li>You may wonder why this setting isn't simply "SQL time zone", since the time zone related behavior of JDBC - * applies to {@link java.sql.Timestamp java.sql.Timestamp} too. FreeMarker assumes that you have set up your - * application so that time stamps coming from the database go through the necessary conversion to store the - * correct distance from the epoch (1970-01-01 00:00:00 UTC), as requested by {@link java.util.Date}. In that case - * the time stamp can be safely rendered in different time zones, and thus it needs no special treatment. - * </ul> - * - * @param tz Maybe {@code null}, in which case {@link java.sql.Date java.sql.Date} and - * {@link java.sql.Time java.sql.Time} values will be formatted in the time zone returned by - * {@link #getTimeZone()}. - * (Note that since {@code null} is an allowed value for this setting, it will not cause - * {@link #getSQLDateAndTimeTimeZone()} to fall back to the parent configuration.) - * - * @see #setTimeZone(TimeZone) - * - * @since 2.3.21 - */ - public void setSQLDateAndTimeTimeZone(TimeZone tz) { - sqlDataAndTimeTimeZone = tz; - sqlDataAndTimeTimeZoneSet = true; - } - - /** - * The getter pair of {@link #setSQLDateAndTimeTimeZone(TimeZone)}. - * - * @return {@code null} if the value of {@link #getTimeZone()} should be used for formatting - * {@link java.sql.Date java.sql.Date} and {@link java.sql.Time java.sql.Time} values, otherwise the time zone - * that should be used to format the values of those two types. - * - * @since 2.3.21 - */ - public TimeZone getSQLDateAndTimeTimeZone() { - return sqlDataAndTimeTimeZoneSet - ? sqlDataAndTimeTimeZone - : (parent != null ? parent.getSQLDateAndTimeTimeZone() : null); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isSQLDateAndTimeTimeZoneSet() { - return sqlDataAndTimeTimeZoneSet; - } - - /** - * Sets the default number format used to convert numbers to strings. Currently, this is one of these: - * <ul> - * <li>{@code "number"}: The number format returned by {@link NumberFormat#getNumberInstance(Locale)}</li> - * <li>{@code "currency"}: The number format returned by {@link NumberFormat#getCurrencyInstance(Locale)}</li> - * <li>{@code "percent"}: The number format returned by {@link NumberFormat#getPercentInstance(Locale)}</li> - * <li>{@code "computer"}: The number format used by FTL's {@code c} built-in (like in {@code someNumber?c}).</li> - * <li>{@link java.text.DecimalFormat} pattern (like {@code "0.##"}). This syntax has a FreeMarker-specific - * extension, so that you can specify options like the rounding mode and the symbols used in this string. For - * example, {@code ",000;; roundingMode=halfUp groupingSeparator=_"} will format numbers like {@code ",000"} - * would, but with half-up rounding mode, and {@code _} as the group separator. See more about "extended Java - * decimal format" in the FreeMarker Manual. - * </li> - * <li>If the string starts with {@code @} character followed by a letter then it's interpreted as a custom number - * format, but only if either {@link Configuration#getIncompatibleImprovements()} is at least 2.3.24, or - * there's any custom formats defined (even if custom date/time/dateTime format). The format of a such string - * is <code>"@<i>name</i>"</code> or <code>"@<i>name</i> <i>parameters</i>"</code>, where - * <code><i>name</i></code> is the key in the {@link Map} set by {@link #setCustomNumberFormats(Map)}, and - * <code><i>parameters</i></code> is parsed by the custom {@link TemplateNumberFormat}. - * </li> - * </ul> - * - * - * <p>Defaults to <tt>"number"</tt>. - */ - public void setNumberFormat(String numberFormat) { - _NullArgumentException.check("numberFormat", numberFormat); - this.numberFormat = numberFormat; - } - - /** - * Getter pair of {@link #setNumberFormat(String)}. - */ - public String getNumberFormat() { - return numberFormat != null ? numberFormat : parent.getNumberFormat(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isNumberFormatSet() { - return numberFormat != null; - } - - /** - * Getter pair of {@link #setCustomNumberFormats(Map)}; do not modify the returned {@link Map}! To be consistent - * with other setting getters, if this setting was set directly on this {@link Configurable} object, this simply - * returns that value, otherwise it returns the value from the parent {@link Configurable}. So beware, the returned - * value doesn't reflect the {@link Map} key granularity fallback logic that FreeMarker actually uses for this - * setting (for that, use {@link #getCustomNumberFormat(String)}). The returned value isn't a snapshot; it may or - * may not shows the changes later made to this setting on this {@link Configurable} level (but usually it's well - * defined if until what point settings are possibly modified). - * - * <p> - * The return value is never {@code null}; called on the {@link Configuration} (top) level, it defaults to an empty - * {@link Map}. - * - * @see #getCustomNumberFormatsWithoutFallback() - * - * @since 2.3.24 - */ - public Map<String, ? extends TemplateNumberFormatFactory> getCustomNumberFormats() { - return customNumberFormats == null ? parent.getCustomNumberFormats() : customNumberFormats; - } - - /** - * Like {@link #getCustomNumberFormats()}, but doesn't fall back to the parent {@link Configurable}, nor does it - * provide a non-{@code null} default when called as the method of a {@link Configuration}. - * - * @since 2.3.25 - */ - public Map<String, ? extends TemplateNumberFormatFactory> getCustomNumberFormatsWithoutFallback() { - return customNumberFormats; - } - - /** - * Associates names with formatter factories, which then can be referred by the {@link #setNumberFormat(String) - * number_format} setting with values starting with <code>@<i>name</i></code>. Beware, if you specify any custom - * formats here, an initial {@code @} followed by a letter will have special meaning in number/date/time/datetime - * format strings, even if {@link Configuration#getIncompatibleImprovements() incompatible_improvements} is less - * than 2.3.24 (starting with {@link Configuration#getIncompatibleImprovements() incompatible_improvements} 2.3.24 - * {@code @} always has special meaning). - * - * @param customNumberFormats - * Can't be {@code null}. The name must start with an UNICODE letter, and can only contain UNICODE - * letters and digits (not {@code _}). - * - * @since 2.3.24 - */ - public void setCustomNumberFormats(Map<String, ? extends TemplateNumberFormatFactory> customNumberFormats) { - _NullArgumentException.check("customNumberFormats", customNumberFormats); - validateFormatNames(customNumberFormats.keySet()); - this.customNumberFormats = customNumberFormats; - } - - private void validateFormatNames(Set<String> keySet) { - for (String name : keySet) { - if (name.length() == 0) { - throw new IllegalArgumentException("Format names can't be 0 length"); - } - char firstChar = name.charAt(0); - if (firstChar == '@') { - throw new IllegalArgumentException( - "Format names can't start with '@'. '@' is only used when referring to them from format " - + "strings. In: " + name); - } - if (!Character.isLetter(firstChar)) { - throw new IllegalArgumentException("Format name must start with letter: " + name); - } - for (int i = 1; i < name.length(); i++) { - // Note that we deliberately don't allow "_" here. - if (!Character.isLetterOrDigit(name.charAt(i))) { - throw new IllegalArgumentException("Format name can only contain letters and digits: " + name); - } - } - } - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isCustomNumberFormatsSet() { - return customNumberFormats != null; - } - - /** - * Gets the custom name format registered for the name. - * - * @since 2.3.24 - */ - public TemplateNumberFormatFactory getCustomNumberFormat(String name) { - TemplateNumberFormatFactory r; - if (customNumberFormats != null) { - r = customNumberFormats.get(name); - if (r != null) { - return r; - } - } - return parent != null ? parent.getCustomNumberFormat(name) : null; - } - - /** - * Tells if this configurable object or its parent defines any custom formats. - * - * @since 2.3.24 - */ - public boolean hasCustomFormats() { - return customNumberFormats != null && !customNumberFormats.isEmpty() - || customDateFormats != null && !customDateFormats.isEmpty() - || getParent() != null && getParent().hasCustomFormats(); - } - - /** - * The string value for the boolean {@code true} and {@code false} values, intended for human audience (not for a - * computer language), separated with comma. For example, {@code "yes,no"}. Note that white-space is significant, - * so {@code "yes, no"} is WRONG (unless you want that leading space before "no"). - * - * <p>For backward compatibility the default is {@code "true,false"}, but using that value is denied for automatic - * boolean-to-string conversion (like <code>${myBoolean}</code> will fail with it), only {@code myBool?string} will - * allow it, which is deprecated since FreeMarker 2.3.20. - * - * <p>Note that automatic boolean-to-string conversion only exists since FreeMarker 2.3.20. Earlier this setting - * only influenced the result of {@code myBool?string}. - */ - public void setBooleanFormat(String booleanFormat) { - _NullArgumentException.check("booleanFormat", booleanFormat); - - int commaIdx = booleanFormat.indexOf(','); - if (commaIdx == -1) { - throw new IllegalArgumentException( - "Setting value must be string that contains two comma-separated values for true and false, " + - "respectively."); - } - - this.booleanFormat = booleanFormat; - - if (booleanFormat.equals(C_TRUE_FALSE)) { - // C_TRUE_FALSE is the default for BC, but it's not a good default for human audience formatting, so we - // pretend that it wasn't set. - trueStringValue = null; - falseStringValue = null; - } else { - trueStringValue = booleanFormat.substring(0, commaIdx); - falseStringValue = booleanFormat.substring(commaIdx + 1); - } - } - - /** - * The getter pair of {@link #setBooleanFormat(String)}. - */ - public String getBooleanFormat() { - return booleanFormat != null ? booleanFormat : parent.getBooleanFormat(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isBooleanFormatSet() { - return booleanFormat != null; - } - - String formatBoolean(boolean value, boolean fallbackToTrueFalse) throws TemplateException { - if (value) { - String s = getTrueStringValue(); - if (s == null) { - if (fallbackToTrueFalse) { - return MiscUtil.C_TRUE; - } else { - throw new _MiscTemplateException(getNullBooleanFormatErrorDescription()); - } - } else { - return s; - } - } else { - String s = getFalseStringValue(); - if (s == null) { - if (fallbackToTrueFalse) { - return MiscUtil.C_FALSE; - } else { - throw new _MiscTemplateException(getNullBooleanFormatErrorDescription()); - } - } else { - return s; - } - } - } - - private _ErrorDescriptionBuilder getNullBooleanFormatErrorDescription() { - return new _ErrorDescriptionBuilder( - "Can't convert boolean to string automatically, because the \"", BOOLEAN_FORMAT_KEY ,"\" setting was ", - new _DelayedJQuote(getBooleanFormat()), - (getBooleanFormat().equals(C_TRUE_FALSE) - ? ", which is the legacy default computer-language format, and hence isn't accepted." - : ".") - ).tips( - "If you just want \"true\"/\"false\" result as you are generting computer-language output, " - + "use \"?c\", like ${myBool?c}.", - "You can write myBool?string('yes', 'no') and like to specify boolean formatting in place.", - new Object[] { - "If you need the same two values on most places, the programmers should set the \"", - BOOLEAN_FORMAT_KEY ,"\" setting to something like \"yes,no\"." } - ); - } - - /** - * Returns the string to which {@code true} is converted to for human audience, or {@code null} if automatic - * coercion to string is not allowed. The default value is {@code null}. - * - * <p>This value is deduced from the {@code "boolean_format"} setting. - * Confusingly, for backward compatibility (at least until 2.4) that defaults to {@code "true,false"}, yet this - * defaults to {@code null}. That's so because {@code "true,false"} is treated exceptionally, as that default is a - * historical mistake in FreeMarker, since it targets computer language output, not human writing. Thus it's - * ignored. - * - * @since 2.3.20 - */ - String getTrueStringValue() { - // The first step deliberately tests booleanFormat instead of trueStringValue! - return booleanFormat != null ? trueStringValue : (parent != null ? parent.getTrueStringValue() : null); - } - - /** - * Same as {@link #getTrueStringValue()} but with {@code false}. - * @since 2.3.20 - */ - String getFalseStringValue() { - // The first step deliberately tests booleanFormat instead of falseStringValue! - return booleanFormat != null ? falseStringValue : (parent != null ? parent.getFalseStringValue() : null); - } - - /** - * Sets the format used to convert {@link java.util.Date}-s to string-s that are time (no date part) values, - * also the format that {@code someString?time} will use to parse strings. - * - * <p>For the possible values see {@link #setDateTimeFormat(String)}. - * - * <p>Defaults to {@code ""}, which means "use the FreeMarker default", which is currently {@code "medium"}. - */ - public void setTimeFormat(String timeFormat) { - _NullArgumentException.check("timeFormat", timeFormat); - this.timeFormat = timeFormat; - } - - /** - * The getter pair of {@link #setTimeFormat(String)}. - */ - public String getTimeFormat() { - return timeFormat != null ? timeFormat : parent.getTimeFormat(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isTimeFormatSet() { - return timeFormat != null; - } - - /** - * Sets the format used to convert {@link java.util.Date}-s to string-s that are date (no time part) values, - * also the format that {@code someString?date} will use to parse strings. - * - * <p>For the possible values see {@link #setDateTimeFormat(String)}. - * - * <p>Defaults to {@code ""}, which means "use the FreeMarker default", which is currently {@code "medium"}. - */ - public void setDateFormat(String dateFormat) { - _NullArgumentException.check("dateFormat", dateFormat); - this.dateFormat = dateFormat; - } - - /** - * The getter pair of {@link #setDateFormat(String)}. - */ - public String getDateFormat() { - return dateFormat != null ? dateFormat : parent.getDateFormat(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isDateFormatSet() { - return dateFormat != null; - } - - /** - * Sets the format used to convert {@link java.util.Date}-s to string-s that are date-time (timestamp) values, - * also the format that {@code someString?datetime} will use to parse strings. - * - * <p>The possible setting values are (the quotation marks aren't part of the value itself): - * - * <ul> - * <li><p>Patterns accepted by Java's {@link SimpleDateFormat}, for example {@code "dd.MM.yyyy HH:mm:ss"} (where - * {@code HH} means 24 hours format) or {@code "MM/dd/yyyy hh:mm:ss a"} (where {@code a} prints AM or PM, if - * the current language is English). - * - * <li><p>{@code "xs"} for XML Schema format, or {@code "iso"} for ISO 8601:2004 format. - * These formats allow various additional options, separated with space, like in - * {@code "iso m nz"} (or with {@code _}, like in {@code "iso_m_nz"}; this is useful in a case like - * {@code lastModified?string.iso_m_nz}). The options and their meanings are: - * - * <ul> - * <li><p>Accuracy options:<br> - * {@code ms} = Milliseconds, always shown with all 3 digits, even if it's all 0-s. - * Example: {@code 13:45:05.800}<br> - * {@code s} = Seconds (fraction seconds are dropped even if non-0), like {@code 13:45:05}<br> - * {@code m} = Minutes, like {@code 13:45}. This isn't allowed for "xs".<br> - * {@code h} = Hours, like {@code 13}. This isn't allowed for "xs".<br> - * Neither = Up to millisecond accuracy, but trailing millisecond 0-s are removed, also the whole - * milliseconds part if it would be 0 otherwise. Example: {@code 13:45:05.8} - * - * <li><p>Time zone offset visibility options:<br> - * {@code fz} = "Force Zone", always show time zone offset (even for for - * {@link java.sql.Date java.sql.Date} and {@link java.sql.Time java.sql.Time} values). - * But, because ISO 8601 doesn't allow for dates (means date without time of the day) to - * show the zone offset, this option will have no effect in the case of {@code "iso"} with - * dates.<br> - * {@code nz} = "No Zone", never show time zone offset<br> - * Neither = always show time zone offset, except for {@link java.sql.Date java.sql.Date} - * and {@link java.sql.Time java.sql.Time}, and for {@code "iso"} date values. - * - * <li><p>Time zone options:<br> - * {@code u} = Use UTC instead of what the {@code time_zone} setting suggests. However, - * {@link java.sql.Date java.sql.Date} and {@link java.sql.Time java.sql.Time} aren't affected - * by this (see {@link #setSQLDateAndTimeTimeZone(TimeZone)} to understand why)<br> - * {@code fu} = "Force UTC", that is, use UTC instead of what the {@code time_zone} or the - * {@code sql_date_and_time_time_zone} setting suggests. This also effects - * {@link java.sql.Date java.sql.Date} and {@link java.sql.Time java.sql.Time} values<br> - * Neither = Use the time zone suggested by the {@code time_zone} or the - * {@code sql_date_and_time_time_zone} configuration setting ({@link #setTimeZone(TimeZone)} and - * {@link #setSQLDateAndTimeTimeZone(TimeZone)}). - * </ul> - * - * <p>The options can be specified in any order.</p> - * - * <p>Options from the same category are mutually exclusive, like using {@code m} and {@code s} - * together is an error. - * - * <p>The accuracy and time zone offset visibility options don't influence parsing, only formatting. - * For example, even if you use "iso m nz", "2012-01-01T15:30:05.125+01" will be parsed successfully and with - * milliseconds accuracy. - * The time zone options (like "u") influence what time zone is chosen only when parsing a string that doesn't - * contain time zone offset. - * - * <p>Parsing with {@code "iso"} understands both extend format and basic format, like - * {@code 20141225T235018}. It doesn't, however, support the parsing of all kind of ISO 8601 strings: if - * there's a date part, it must use year, month and day of the month values (not week of the year), and the - * day can't be omitted. - * - * <p>The output of {@code "iso"} is deliberately so that it's also a good representation of the value with - * XML Schema format, except for 0 and negative years, where it's impossible. Also note that the time zone - * offset is omitted for date values in the {@code "iso"} format, while it's preserved for the {@code "xs"} - * format. - * - * <li><p>{@code "short"}, {@code "medium"}, {@code "long"}, or {@code "full"}, which that has locale-dependent - * meaning defined by the Java platform (see in the documentation of {@link java.text.DateFormat}). - * For date-time values, you can specify the length of the date and time part independently, be separating - * them with {@code _}, like {@code "short_medium"}. ({@code "medium"} means - * {@code "medium_medium"} for date-time values.) - * - * <li><p>Anything that starts with {@code "@"} followed by a letter is interpreted as a custom - * date/time/dateTime format, but only if either {@link Configuration#getIncompatibleImprovements()} - * is at least 2.3.24, or there's any custom formats defined (even if custom number format). The format of - * such string is <code>"@<i>name</i>"</code> or <code>"@<i>name</i> <i>parameters</i>"</code>, where - * <code><i>name</i></code> is the key in the {@link Map} set by {@link #setCustomDateFormats(Map)}, and - * <code><i>parameters</i></code> is parsed by the custom number format. - * - * </ul> - * - * <p>Defaults to {@code ""}, which means "use the FreeMarker default", which is currently {@code "medium_medium"}. - */ - public void setDateTimeFormat(String dateTimeFormat) { - _NullArgumentException.check("dateTimeFormat", dateTimeFormat); - this.dateTimeFormat = dateTimeFormat; - } - - /** - * The getter pair of {@link #setDateTimeFormat(String)}. - */ - public String getDateTimeFormat() { - return dateTimeFormat != null ? dateTimeFormat : parent.getDateTimeFormat(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isDateTimeFormatSet() { - return dateTimeFormat != null; - } - - /** - * Getter pair of {@link #setCustomDateFormats(Map)}; do not modify the returned {@link Map}! To be consistent with - * other setting getters, if this setting was set directly on this {@link Configurable} object, this simply returns - * that value, otherwise it returns the value from the parent {@link Configurable}. So beware, the returned value - * doesn't reflect the {@link Map} key granularity fallback logic that FreeMarker actually uses for this setting - * (for that, use {@link #getCustomDateFormat(String)}). The returned value isn't a snapshot; it may or may not - * shows the changes later made to this setting on this {@link Configurable} level (but usually it's well defined if - * until what point settings are possibly modified). - * - * <p> - * The return value is never {@code null}; called on the {@link Configuration} (top) level, it defaults to an empty - * {@link Map}. - * - * @see #getCustomDateFormatsWithoutFallback() - * - * @since 2.3.24 - */ - public Map<String, ? extends TemplateDateFormatFactory> getCustomDateFormats() { - return customDateFormats == null ? parent.getCustomDateFormats() : customDateFormats; - } - - /** - * Like {@link #getCustomDateFormats()}, but doesn't fall back to the parent {@link Configurable}, nor does it - * provide a non-{@code null} default when called as the method of a {@link Configuration}. - * - * @since 2.3.25 - */ - public Map<String, ? extends TemplateDateFormatFactory> getCustomDateFormatsWithoutFallback() { - return customDateFormats; - } - - /** - * Associates names with formatter factories, which then can be referred by the {@link #setDateTimeFormat(String) - * date_format}, {@link #setDateTimeFormat(String) time_format}, and {@link #setDateTimeFormat(String) - * datetime_format} settings with values starting with <code>@<i>name</i></code>. Beware, if you specify any custom - * formats here, an initial {@code @} followed by a letter will have special meaning in number/date/time/datetime - * format strings, even if {@link Configuration#getIncompatibleImprovements() incompatible_improvements} is less - * than 2.3.24 (starting with {@link Configuration#getIncompatibleImprovements() incompatible_improvements} 2.3.24 - * {@code @} always has special meaning). - * - * @param customDateFormats - * Can't be {@code null}. The name must start with an UNICODE letter, and can only contain UNICODE - * letters and digits. - * - * @since 2.3.24 - */ - public void setCustomDateFormats(Map<String, ? extends TemplateDateFormatFactory> customDateFormats) { - _NullArgumentException.check("customDateFormats", customDateFormats); - validateFormatNames(customDateFormats.keySet()); - this.customDateFormats = customDateFormats; - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isCustomDateFormatsSet() { - return customDateFormats != null; - } - - /** - * Gets the custom name format registered for the name. - * - * @since 2.3.24 - */ - public TemplateDateFormatFactory getCustomDateFormat(String name) { - TemplateDateFormatFactory r; - if (customDateFormats != null) { - r = customDateFormats.get(name); - if (r != null) { - return r; - } - } - return parent != null ? parent.getCustomDateFormat(name) : null; - } - - /** - * Sets the exception handler used to handle exceptions occurring inside templates. - * The default is {@link TemplateExceptionHandler#DEBUG_HANDLER}. The recommended values are: - * - * <ul> - * <li>In production systems: {@link TemplateExceptionHandler#RETHROW_HANDLER} - * <li>During development of HTML templates: {@link TemplateExceptionHandler#HTML_DEBUG_HANDLER} - * <li>During development of non-HTML templates: {@link TemplateExceptionHandler#DEBUG_HANDLER} - * </ul> - * - * <p>All of these will let the exception propagate further, so that you can catch it around - * {@link Template#process(Object, Writer)} for example. The difference is in what they print on the output before - * they do that. - * - * <p>Note that the {@link TemplateExceptionHandler} is not meant to be used for generating HTTP error pages. - * Neither is it meant to be used to roll back the printed output. These should be solved outside template - * processing when the exception raises from {@link Template#process(Object, Writer) Template.process}. - * {@link TemplateExceptionHandler} meant to be used if you want to include special content <em>in</em> the template - * output, or if you want to suppress certain exceptions. - */ - public void setTemplateExceptionHandler(TemplateExceptionHandler templateExceptionHandler) { - _NullArgumentException.check("templateExceptionHandler", templateExceptionHandler); - this.templateExceptionHandler = templateExceptionHandler; - } - - /** - * The getter pair of {@link #setTemplateExceptionHandler(TemplateExceptionHandler)}. - */ - public TemplateExceptionHandler getTemplateExceptionHandler() { - return templateExceptionHandler != null - ? templateExceptionHandler : parent.getTemplateExceptionHandler(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isTemplateExceptionHandlerSet() { - return templateExceptionHandler != null; - } - - /** - * Sets the arithmetic engine used to perform arithmetic operations. - * The default is {@link BigDecimalArithmeticEngine#INSTANCE}. - */ - public void setArithmeticEngine(ArithmeticEngine arithmeticEngine) { - _NullArgumentException.check("arithmeticEngine", arithmeticEngine); - this.arithmeticEngine = arithmeticEngine; - } - - /** - * The getter pair of {@link #setArithmeticEngine(ArithmeticEngine)}. - */ - public ArithmeticEngine getArithmeticEngine() { - return arithmeticEngine != null - ? arithmeticEngine : parent.getArithmeticEngine(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isArithmeticEngineSet() { - return arithmeticEngine != null; - } - - /** - * Sets the object wrapper used to wrap objects to {@link TemplateModel}-s. - * The default is {@link DefaultObjectWrapper.Builder#build()}. - */ - public void setObjectWrapper(ObjectWrapper objectWrapper) { - _NullArgumentException.check("objectWrapper", objectWrapper); - this.objectWrapper = objectWrapper; - } - - /** - * The getter pair of {@link #setObjectWrapper(ObjectWrapper)}. - */ - public ObjectWrapper getObjectWrapper() { - return objectWrapper != null - ? objectWrapper : parent.getObjectWrapper(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isObjectWrapperSet() { - return objectWrapper != null; - } - - /** - * Informs FreeMarker about the charset used for the output. As FreeMarker outputs character stream (not - * byte stream), it's not aware of the output charset unless the software that encloses it tells it - * with this setting. Some templates may use FreeMarker features that require this information. - * Setting this to {@code null} means that the output encoding is not known. - * - * <p>Defaults to {@code null} (unknown). - */ - public void setOutputEncoding(String outputEncoding) { - this.outputEncoding = outputEncoding; - outputEncodingSet = true; - } - - public String getOutputEncoding() { - return outputEncodingSet - ? outputEncoding - : (parent != null ? parent.getOutputEncoding() : null); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isOutputEncodingSet() { - return outputEncodingSet; - } - - /** - * Sets the URL escaping charset. If not set ({@code null}), the output encoding - * ({@link #setOutputEncoding(String)}) will be used for URL escaping. - * - * Defaults to {@code null}. - */ - public void setURLEscapingCharset(String urlEscapingCharset) { - this.urlEscapingCharset = urlEscapingCharset; - urlEscapingCharsetSet = true; - } - - public String getURLEscapingCharset() { - return urlEscapingCharsetSet - ? urlEscapingCharset - : (parent != null ? parent.getURLEscapingCharset() : null); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isURLEscapingCharsetSet() { - return urlEscapingCharsetSet; - } - - /** - * Sets the {@link TemplateClassResolver} that is used when the - * <code>new</code> built-in is called in a template. That is, when - * a template contains the <code>"com.example.SomeClassName"?new</code> - * expression, this object will be called to resolve the - * <code>"com.example.SomeClassName"</code> string to a class. The default - * value is {@link TemplateClassResolver#UNRESTRICTED_RESOLVER}. If you allow - * users to upload templates, it's important to use a custom restrictive - * {@link TemplateClassResolver} or {@link TemplateClassResolver#ALLOWS_NOTHING_RESOLVER}. - * - * @since 2.3.17 - */ - public void setNewBuiltinClassResolver(TemplateClassResolver newBuiltinClassResolver) { - _NullArgumentException.check("newBuiltinClassResolver", newBuiltinClassResolver); - this.newBuiltinClassResolver = newBuiltinClassResolver; - } - - /** - * Retrieves the {@link TemplateClassResolver} used - * to resolve classes when "SomeClassName"?new is called in a template. - * - * @see #setNewBuiltinClassResolver(TemplateClassResolver) - * - * @since 2.3.17 - */ - public TemplateClassResolver getNewBuiltinClassResolver() { - return newBuiltinClassResolver != null - ? newBuiltinClassResolver : parent.getNewBuiltinClassResolver(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isNewBuiltinClassResolverSet() { - return newBuiltinClassResolver != null; - } - - /** - * Sets whether the output {@link Writer} is automatically flushed at - * the end of {@link Template#process(Object, Writer)} (and its - * overloads). The default is {@code true}. - * - * <p>Using {@code false} is needed for example when a Web page is composed - * from several boxes (like portlets, GUI panels, etc.) that aren't inserted - * with <tt>#include</tt> (or with similar directives) into a master - * FreeMarker template, rather they are all processed with a separate - * {@link Template#process(Object, Writer)} call. In a such scenario the - * automatic flushes would commit the HTTP response after each box, hence - * interfering with full-page buffering, and also possibly decreasing - * performance with too frequent and too early response buffer flushes. - * - * @since 2.3.17 - */ - public void setAutoFlush(boolean autoFlush) { - this.autoFlush = Boolean.valueOf(autoFlush); - } - - /** - * See {@link #setAutoFlush(boolean)} - * - * @since 2.3.17 - */ - public boolean getAutoFlush() { - return autoFlush != null - ? autoFlush.booleanValue() - : (parent != null ? parent.getAutoFlush() : true); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isAutoFlushSet() { - return autoFlush != null; - } - - /** - * Sets if tips should be shown in error messages of errors arising during template processing. - * The default is {@code true}. - * - * @since 2.3.21 - */ - public void setShowErrorTips(boolean showTips) { - showErrorTips = Boolean.valueOf(showTips); - } - - /** - * See {@link #setShowErrorTips(boolean)} - * - * @since 2.3.21 - */ - public boolean getShowErrorTips() { - return showErrorTips != null - ? showErrorTips.booleanValue() - : (parent != null ? parent.getShowErrorTips() : true); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isShowErrorTipsSet() { - return showErrorTips != null; - } - - /** - * Specifies if {@code ?api} can be used in templates. Defaults to {@code false} so that updating FreeMarker won't - * decrease the security of existing applications. - * - * @since 2.3.22 - */ - public void setAPIBuiltinEnabled(boolean value) { - apiBuiltinEnabled = Boolean.valueOf(value); - } - - /** - * See {@link #setAPIBuiltinEnabled(boolean)} - * - * @since 2.3.22 - */ - public boolean isAPIBuiltinEnabled() { - return apiBuiltinEnabled != null - ? apiBuiltinEnabled.booleanValue() - : (parent != null ? parent.isAPIBuiltinEnabled() : false); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isAPIBuiltinEnabledSet() { - return apiBuiltinEnabled != null; - } - - /** - * Specifies if {@link TemplateException}-s thrown by template processing are logged by FreeMarker or not. The - * default is {@code true} for backward compatibility, but that results in logging the exception twice in properly - * written applications, because there the {@link TemplateException} thrown by the public FreeMarker API is also - * logged by the caller (even if only as the cause exception of a higher level exception). Hence, in modern - * applications it should be set to {@code false}. Note that this setting has no effect on the logging of exceptions - * caught by {@code #attempt}; those are always logged, no mater what (because those exceptions won't bubble up - * until the API caller). - * - * @since 2.3.22 - */ - public void setLogTemplateExceptions(boolean value) { - logTemplateExceptions = Boolean.valueOf(value); - } - - /** - * See {@link #setLogTemplateExceptions(boolean)} - * - * @since 2.3.22 - */ - public boolean getLogTemplateExceptions() { - return logTemplateExceptions != null - ? logTemplateExceptions.booleanValue() - : (parent != null ? parent.getLogTemplateExceptions() : true); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.24 - */ - public boolean isLogTemplateExceptionsSet() { - return logTemplateExceptions != null; - } - - /** - * The getter pair of {@link #setLazyImports(boolean)}. - * - * @since 2.3.25 - */ - public boolean getLazyImports() { - return lazyImports != null ? lazyImports.booleanValue() : parent.getLazyImports(); - } - - /** - * Specifies if {@code <#import ...>} (and {@link Environment#importLib(String, String)}) should delay the loading - * and processing of the imported templates until the content of the imported namespace is actually accessed. This - * makes the overhead of <em>unused</em> imports negligible. A drawback is that importing a missing or otherwise - * broken template will be successful, and the problem will remain hidden until (and if) the namespace content is - * actually used. Also, you lose the strict control over when the namespace initializing code in the imported - * template will be executed, though it shouldn't mater for well written imported templates anyway. Note that the - * namespace initializing code will run with the same {@linkplain Configurable#getLocale() locale} as it was at the - * point of the {@code <#import ...>} call (other settings won't be handled specially like that). - * - * <p> - * The default is {@code false} (and thus imports are eager) for backward compatibility, which can cause - * perceivable overhead if you have many imports and only a few of them is used. - * - * <p> - * This setting also affects {@linkplain #setAutoImports(Map) auto-imports}, unless you have set a non-{@code null} - * value with {@link #setLazyAutoImports(Boolean)}. - * - * @see #setLazyAutoImports(Boolean) - * - * @since 2.3.25 - */ - public void setLazyImports(boolean lazyImports) { - this.lazyImports = Boolean.valueOf(lazyImports); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.25 - */ - public boolean isLazyImportsSet() { - return lazyImports != null; - } - - /** - * The getter pair of {@link #setLazyAutoImports(Boolean)}. - * - * @since 2.3.25 - */ - public Boolean getLazyAutoImports() { - return lazyAutoImportsSet ? lazyAutoImports : parent.getLazyAutoImports(); - } - - /** - * Specifies if {@linkplain #setAutoImports(Map) auto-imports} will be - * {@link #setLazyImports(boolean) lazy imports}. This is useful to make the overhead of <em>unused</em> - * auto-imports negligible. If this is set to {@code null}, {@link #getLazyImports()} specifies the behavior of - * auto-imports too. The default value is {@code null}. - * - * @since 2.3.25 - */ - public void setLazyAutoImports(Boolean lazyAutoImports) { - this.lazyAutoImports = lazyAutoImports; - lazyAutoImportsSet = true; - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.25 - */ - public boolean isLazyAutoImportsSet() { - return lazyAutoImportsSet; - } - - /** - * Adds an invisible <code>#import <i>templateName</i> as <i>namespaceVarName</i></code> at the beginning of the - * main template (that's the top-level template that wasn't included/imported from another template). While it only - * affects the main template directly, as the imports will invoke a global variable there, the imports will be - * visible from the further imported templates too (note that {@link Configuration#getIncompatibleImprovements()} - * set to 2.3.24 fixes a rarely surfacing bug with that). - * - * <p> - * It's recommended to set the {@code auto_impots_lazy} setting ({@link Configuration#setLazyAutoImports(Boolean)}) - * to {@code true} when using this, so that auto-imports that are unused in a template won't degrade performance by - * unnecessary loading and initializing the imported library. - * - * <p> - * If the imports aren't lazy, the order of the imports will be the same as the order in which they were added with - * this method. (Calling this method with an already added {@code namespaceVarName} will move that to the end - * of the auto-import order.) - * - * <p> - * The auto-import is added directly to the {@link Configurable} on which this method is called (not to the parents - * or children), but when the main template is processed, the auto-imports are collected from all the - * {@link Configurable} levels, in parent-to-child order: {@link Configuration}, {@link Template} (the main - * template), {@link Environment}. If the same {@code namespaceVarName} occurs on multiple levels, the one on the - * child level is used, and the clashing import from the parent level is skipped. - * - * <p>If there are also auto-includes (see {@link #addAutoInclude(String)}), those will be executed after - * the auto-imports. - * - * @see #setAutoImports(Map) - */ - public void addAutoImport(String namespaceVarName, String templateName) { - // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration - synchronized (this) { - if (autoImports == null) { - initAutoImportsMap(); - } else { - // This was a List earlier, so re-inserted items must go to the end, hence we remove() before put(). - autoImports.remove(namespaceVarName); - } - autoImports.put(namespaceVarName, templateName); - } - } - - private void initAutoImportsMap() { - autoImports = new LinkedHashMap<>(4); - } - - /** - * Removes an auto-import from this {@link Configurable} level (not from the parents or children); - * see {@link #addAutoImport(String, String)}. Does nothing if the auto-import doesn't exist. - */ - public void removeAutoImport(String namespaceVarName) { - // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration - synchronized (this) { - if (autoImports != null) { - autoImports.remove(namespaceVarName); - } - } - } - - /** - * Removes all auto-imports, then calls {@link #addAutoImport(String, String)} for each {@link Map}-entry (the entry - * key is the {@code namespaceVarName}). The order of the auto-imports will be the same as {@link Map#keySet()} - * returns the keys (but the order of imports doesn't mater for properly designed libraries anyway). - * - * @param map - * Maps the namespace variable names to the template names; not {@code null} - */ - public void setAutoImports(Map map) { - _NullArgumentException.check("map", map); - - // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration - synchronized (this) { - if (autoImports != null) { - autoImports.clear(); - } - for (Map.Entry<?, ?> entry : ((Map<?, ?>) map).entrySet()) { - Object key = entry.getKey(); - if (!(key instanceof String)) { - throw new IllegalArgumentException( - "Key in Map wasn't a String, but a(n) " + key.getClass().getName() + "."); - } - - Object value = entry.getValue(); - if (!(value instanceof String)) { - throw new IllegalArgumentException( - "Value in Map wasn't a String, but a(n) " + key.getClass().getName() + "."); - } - - addAutoImport((String) key, (String) value); - } - } - } - - /** - * Getter pair of {@link #setAutoImports(Map)}; do not modify the returned {@link Map}! To be consistent with other - * setting getters, if this setting was set directly on this {@link Configurable} object, this simply returns that - * value, otherwise it returns the value from the parent {@link Configurable}. So beware, the returned value doesn't - * reflect the {@link Map} key granularity fallback logic that FreeMarker actually uses for this setting. The - * returned value is not the same {@link Map} object that was set with {@link #setAutoImports(Map)}, only its - * content is the same. The returned value isn't a snapshot; it may or may not shows the changes later made to this - * setting on this {@link Configurable} level (but usually it's well defined if until what point settings are - * possibly modified). - * - * <p> - * The return value is never {@code null}; called on the {@link Configuration} (top) level, it defaults to an empty - * {@link Map}. - * - * @see #getAutoImportsWithoutFallback() - * - * @since 2.3.25 - */ - public Map<String, String> getAutoImports() { - return autoImports != null ? autoImports : parent.getAutoImports(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.25 - */ - public boolean isAutoImportsSet() { - return autoImports != null; - } - - /** - * Like {@link #getAutoImports()}, but doesn't fall back to the parent {@link Configurable} (and so it can be - * {@code null}). - * - * @since 2.3.25 - */ - public Map<String, String> getAutoImportsWithoutFallback() { - return autoImports; - } - - /** - * Adds an invisible <code>#include <i>templateName</i></code> at the beginning of the main template (that's the - * top-level template that wasn't included/imported from another template). - * - * <p> - * The order of the inclusions will be the same as the order in which they were added with this method. - * - * <p> - * The auto-include is added directly to the {@link Configurable} on which this method is called (not to the parents - * or children), but when the main template is processed, the auto-includes are collected from all the - * {@link Configurable} levels, in parent-to-child order: {@link Configuration}, {@link Template} (the main - * template), {@link Environment}. - * - * <p> - * If there are also auto-imports ({@link #addAutoImport(String, String)}), those imports will be executed before - * the auto-includes, hence the namespace variables are accessible for the auto-included templates. - * - * <p> - * Calling {@link #addAutoInclude(String)} with an already added template name will just move that to the end of the - * auto-include list (within the same {@link Configurable} level). This works even if the same template name appears - * on different {@link Configurable} levels, in which case only the inclusion on the lowest (child) level will be - * executed. - * - * @see #setAutoIncludes(List) - */ - public void addAutoInclude(String templateName) { - // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration - synchronized (this) { - if (autoIncludes == null) { - initAutoIncludesList(); - } else { - autoIncludes.remove(templateName); - } - autoIncludes.add(templateName); - } - } - - private void initAutoIncludesList() { - autoIncludes = new ArrayList<>(4); - } - - /** - * Removes all auto-includes, then calls {@link #addAutoInclude(String)} for each {@link List} items. - * - * <p>Before {@linkplain Configuration#Configuration(Version) incompatible improvements} 2.3.25 it doesn't filter - * out duplicates from the list if this method was called on a {@link Configuration} instance. - */ - public void setAutoIncludes(List templateNames) { - _NullArgumentException.check("templateNames", templateNames); - // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration - synchronized (this) { - if (autoIncludes != null) { - autoIncludes.clear(); - } - for (Object templateName : templateNames) { - if (!(templateName instanceof String)) { - throw new IllegalArgumentException("List items must be String-s."); - } - addAutoInclude((String) templateName); - } - } - } - - /** - * Getter pair of {@link #setAutoIncludes(List)}; do not modify the returned {@link List}! To be consistent with - * other setting getters, if this setting was set directly on this {@link Configurable} object, this simply returns - * that value, otherwise it returns the value from the parent {@link Configurable}. So beware, the returned value - * doesn't reflect the {@link List} concatenation logic that FreeMarker actually uses for this setting. The returned - * value is not the same {@link List} object that was set with {@link #setAutoIncludes(List)}, only its content is - * the same (except that duplicate are removed). The returned value isn't a snapshot; it may or may not shows the - * changes later made to this setting on this {@link Configurable} level (but usually it's well defined if until - * what point settings are possibly modified). - * - * <p> - * The return value is never {@code null}; called on the {@link Configuration} (top) level, it defaults to an empty - * {@link List}. - * - * @see #getAutoIncludesWithoutFallback() - * - * @since 2.3.25 - */ - public List<String> getAutoIncludes() { - return autoIncludes != null ? autoIncludes : parent.getAutoIncludes(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.25 - */ - public boolean isAutoIncludesSet() { - return autoIncludes != null; - } - - /** - * Like {@link #getAutoIncludes()}, but doesn't fall back to the parent {@link Configurable} (and so it can be - * {@code null}). - * - * @since 2.3.25 - */ - public List<String> getAutoIncludesWithoutFallback() { - return autoIncludes; - } - - /** - * Removes the auto-include from this {@link Configurable} level (not from the parents or children); see - * {@link #addAutoInclude(String)}. Does nothing if the template is not there. - */ - public void removeAutoInclude(String templateName) { - // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration - synchronized (this) { - if (autoIncludes != null) { - autoIncludes.remove(templateName); - } - } - } - - private static final String ALLOWED_CLASSES = "allowed_classes"; - private static final String TRUSTED_TEMPLATES = "trusted_templates"; - - /** - * Sets a FreeMarker setting by a name and string value. If you can configure FreeMarker directly with Java (or - * other programming language), you should use the dedicated setter methods instead (like - * {@link #setObjectWrapper(ObjectWrapper)}. This meant to be used only when you get settings from somewhere - * as {@link String}-{@link String} name-value pairs (typically, as a {@link Properties} object). Below you find an - * overview of the settings available. - * - * <p>Note: As of FreeMarker 2.3.23, setting names can be written in camel case too. For example, instead of - * {@code date_format} you can also use {@code dateFormat}. It's likely that camel case will become to the - * recommended convention in the future. - * - * <p>The list of settings commonly supported in all {@link Configura
<TRUNCATED>
