http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/ParserConfiguration.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ParserConfiguration.java b/src/main/java/org/apache/freemarker/core/ParserConfiguration.java index d79b545..7b4b887 100644 --- a/src/main/java/org/apache/freemarker/core/ParserConfiguration.java +++ b/src/main/java/org/apache/freemarker/core/ParserConfiguration.java @@ -18,14 +18,18 @@ */ package org.apache.freemarker.core; +import java.io.Writer; + import org.apache.freemarker.core.arithmetic.ArithmeticEngine; import org.apache.freemarker.core.outputformat.OutputFormat; /** * <b>Don't implement this interface yourself</b>; use the existing implementation(s). This interface is implemented by - * classes that hold settings that affect parsing. New parser settings can be added in new FreeMarker versions, which - * will break your implementation. - * + * classes that hold settings that affect template parsing (as opposed to {@linkplain Template#process(Object, Writer) + * template processing}). New parser settings can be added in new FreeMarker versions, which will break your + * implementation. + * + * @see ProcessingConfiguration * @since 2.3.24 */ public interface ParserConfiguration { @@ -38,40 +42,89 @@ public interface ParserConfiguration { int getTagSyntax(); /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isTagSyntaxSet(); + + /** * See {@link Configuration#getNamingConvention()}. */ int getNamingConvention(); /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isNamingConventionSet(); + + /** * See {@link Configuration#getWhitespaceStripping()}. */ boolean getWhitespaceStripping(); /** - * Overlaps with {@link Configurable#getArithmeticEngine()}; the parser needs this for creating numerical literals. + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isWhitespaceStrippingSet(); + + /** + * Overlaps with {@link MutableProcessingConfiguration#getArithmeticEngine()}; the parser needs this for creating numerical literals. */ ArithmeticEngine getArithmeticEngine(); - + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isArithmeticEngineSet(); + /** * See {@link Configuration#getAutoEscapingPolicy()}. */ int getAutoEscapingPolicy(); - + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isAutoEscapingPolicySet(); + /** * See {@link Configuration#getOutputEncoding()}. */ OutputFormat getOutputFormat(); - + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isOutputFormatSet(); + /** * See {@link Configuration#getRecognizeStandardFileExtensions()}. */ boolean getRecognizeStandardFileExtensions(); - + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isRecognizeStandardFileExtensionsSet(); + /** * See {@link Configuration#getIncompatibleImprovements()}. */ Version getIncompatibleImprovements(); - + /** * See {@link Configuration#getTabSize()}. * @@ -79,4 +132,18 @@ public interface ParserConfiguration { */ int getTabSize(); + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isTabSizeSet(); + + /** + * Gets the default encoding for converting bytes to characters when + * reading template files in a locale for which no explicit encoding + * was specified. Defaults to the default system encoding. + */ + String getEncoding(); + }
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/ProcessingConfiguration.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ProcessingConfiguration.java b/src/main/java/org/apache/freemarker/core/ProcessingConfiguration.java new file mode 100644 index 0000000..16cbdd5 --- /dev/null +++ b/src/main/java/org/apache/freemarker/core/ProcessingConfiguration.java @@ -0,0 +1,335 @@ +/* + * 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.Writer; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; + +import org.apache.freemarker.core.arithmetic.ArithmeticEngine; +import org.apache.freemarker.core.model.ObjectWrapper; +import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory; +import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory; + +/** + * <b>Don't implement this interface yourself</b>; use the existing implementation(s). This interface is implemented by + * classes that hold settings that affect {@linkplain Template#process(Object, Writer) template processing} (as opposed + * to template parsing). New parser settings can be added in new FreeMarker versions, which will break your + * implementation. + * + * @see ParserConfiguration + */ +// TODO [FM3] JavaDoc +public interface ProcessingConfiguration { + + /** + * Getter pair of {@link MutableProcessingConfiguration#setLocale(Locale)}. + */ + Locale getLocale(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isLocaleSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setTimeZone(TimeZone)}. + */ + TimeZone getTimeZone(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isTimeZoneSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#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. + */ + TimeZone getSQLDateAndTimeTimeZone(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isSQLDateAndTimeTimeZoneSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setNumberFormat(String)}. + */ + String getNumberFormat(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isNumberFormatSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setCustomNumberFormats(Map)}. + */ + Map<String, ? extends TemplateNumberFormatFactory> getCustomNumberFormats(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isCustomNumberFormatsSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setBooleanFormat(String)}. + */ + String getBooleanFormat(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isBooleanFormatSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setTimeFormat(String)}. + */ + String getTimeFormat(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isTimeFormatSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setDateFormat(String)}. + */ + String getDateFormat(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isDateFormatSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setDateTimeFormat(String)}. + */ + String getDateTimeFormat(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isDateTimeFormatSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setCustomDateFormats(Map)}. + */ + Map<String, ? extends TemplateDateFormatFactory> getCustomDateFormats(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isCustomDateFormatsSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setTemplateExceptionHandler(TemplateExceptionHandler)}. + */ + TemplateExceptionHandler getTemplateExceptionHandler(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isTemplateExceptionHandlerSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setArithmeticEngine(ArithmeticEngine)}. + */ + ArithmeticEngine getArithmeticEngine(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isArithmeticEngineSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setObjectWrapper(ObjectWrapper)}. + */ + ObjectWrapper getObjectWrapper(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isObjectWrapperSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setOutputEncoding(String)}. + */ + String getOutputEncoding(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isOutputEncodingSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setURLEscapingCharset(String)}. + */ + String getURLEscapingCharset(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isURLEscapingCharsetSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setNewBuiltinClassResolver(TemplateClassResolver)}. + */ + TemplateClassResolver getNewBuiltinClassResolver(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isNewBuiltinClassResolverSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setAutoFlush(boolean)}. + */ + boolean getAutoFlush(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isAutoFlushSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setShowErrorTips(boolean)}. + */ + boolean getShowErrorTips(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isShowErrorTipsSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setLogTemplateExceptions(boolean)}. + */ + boolean getLogTemplateExceptions(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isLogTemplateExceptionsSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setLazyImports(boolean)}. + */ + boolean getLazyImports(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isLazyImportsSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setLazyAutoImports(Boolean)}. + */ + Boolean getLazyAutoImports(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isLazyAutoImportsSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setAutoImports(Map)}. + */ + Map<String, String> getAutoImports(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isAutoImportsSet(); + + /** + * Getter pair of {@link MutableProcessingConfiguration#setAutoIncludes(List)}. + */ + List<String> getAutoIncludes(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isAutoIncludesSet(); + + Map<Object, Object> getCustomAttributes(); + + /** + * Tells if this setting is set directly in this object. If not, then depending on the implementing class, reading + * the setting mights returns a default value, or returns the value of the setting from a parent object, or throws + * an {@link SettingValueNotSetException}. + */ + boolean isCustomAttributesSet(); + + Object getCustomAttribute(Object name); + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/SettingValueNotSetException.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/SettingValueNotSetException.java b/src/main/java/org/apache/freemarker/core/SettingValueNotSetException.java new file mode 100644 index 0000000..6ff7bab --- /dev/null +++ b/src/main/java/org/apache/freemarker/core/SettingValueNotSetException.java @@ -0,0 +1,33 @@ +/* + * 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 org.apache.freemarker.core.util._StringUtil; + +public class SettingValueNotSetException extends IllegalStateException { + + private final String settingName; + + public SettingValueNotSetException(String settingName) { + super("Setting " + _StringUtil.jQuote(settingName) + + " is not set in this layer and has no default here either."); + this.settingName = settingName; + } +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/Template.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/Template.java b/src/main/java/org/apache/freemarker/core/Template.java index e253197..77b5b2d 100644 --- a/src/main/java/org/apache/freemarker/core/Template.java +++ b/src/main/java/org/apache/freemarker/core/Template.java @@ -38,6 +38,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; import org.apache.freemarker.core.debug._DebuggerService; import org.apache.freemarker.core.model.ObjectWrapper; @@ -72,7 +73,7 @@ import org.apache.freemarker.core.util._NullArgumentException; * shared {@link Configuration}, and you are using {@link Configuration#getTemplate(String)} (or its overloads), then * use {@link Configuration#setTemplateConfigurations(org.apache.freemarker.core.templateresolver.TemplateConfigurationFactory)} to achieve that. */ -public class Template extends Configurable { +public class Template extends MutableProcessingConfiguration<Template> implements CustomStateScope { public static final String DEFAULT_NAMESPACE_PREFIX = "D"; public static final String NO_NS_PREFIX = "N"; @@ -95,6 +96,9 @@ public class Template extends Configurable { private Map namespaceURIToPrefixLookup = new HashMap(); private Version templateLanguageVersion; + private final Object lock = new Object(); + private final ConcurrentHashMap<CustomStateKey, Object> customStateMap = new ConcurrentHashMap<>(0); + /** * A prime constructor to which all other constructors should * delegate directly or indirectly. @@ -206,7 +210,7 @@ public class Template extends Configurable { * practically just overrides some of the parser settings, as the others are inherited from the * {@link Configuration}. Note that if this is a {@link TemplateConfiguration}, you will also want to * call {@link TemplateConfiguration#apply(Template)} on the resulting {@link Template} so that - * {@link Configurable} settings will be set too, because this constructor only uses it as a + * {@link MutableProcessingConfiguration} settings will be set too, because this constructor only uses it as a * {@link ParserConfiguration}. * @param encoding * Same as in {@link #Template(String, String, Reader, Configuration, String)}. @@ -425,7 +429,7 @@ public class Template extends Configurable { * @param dataModel the holder of the variables visible from all templates; see {@link #process(Object, Writer)} for * more details. * @param wrapper The {@link ObjectWrapper} to use to wrap objects into {@link TemplateModel} - * instances. Normally you left it {@code null}, in which case {@link Configurable#getObjectWrapper()} will be + * instances. Normally you left it {@code null}, in which case {@link MutableProcessingConfiguration#getObjectWrapper()} will be * used. * @param out The {@link Writer} where the output of the template will go; see {@link #process(Object, Writer)} for * more details. @@ -928,5 +932,25 @@ public class Template extends Configurable { return prefix + ":" + localName; } + @Override + @SuppressWarnings("unchecked") + public <T> T getCustomState(CustomStateKey<T> customStateKey) { + T customState = (T) customStateMap.get(customStateKey); + if (customState == null) { + synchronized (lock) { + customState = (T) customStateMap.get(customStateKey); + if (customState == null) { + customState = customStateKey.create(); + if (customState == null) { + throw new IllegalStateException("CustomStateKey.create() must not return null (for key: " + + customStateKey + ")"); + } + customStateMap.put(customStateKey, customState); + } + } + } + return customState; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/TemplateClassResolver.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/TemplateClassResolver.java b/src/main/java/org/apache/freemarker/core/TemplateClassResolver.java index 0c5a9fc..c49e3fa 100644 --- a/src/main/java/org/apache/freemarker/core/TemplateClassResolver.java +++ b/src/main/java/org/apache/freemarker/core/TemplateClassResolver.java @@ -29,7 +29,7 @@ import org.apache.freemarker.core.util._ClassUtil; * The implementation should be thread-safe, unless an * instance is always only used in a single {@link Environment} object. * - * @see Configurable#setNewBuiltinClassResolver(TemplateClassResolver) + * @see MutableProcessingConfiguration#setNewBuiltinClassResolver(TemplateClassResolver) * * @since 2.3.17 */ http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java b/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java index 3d1b903..3be8b3e 100644 --- a/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java +++ b/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java @@ -59,11 +59,11 @@ import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory; * you should be aware of a few more details: * * <ul> - * <li>This class implements both {@link Configurable} and {@link ParserConfiguration}. This means that it can influence + * <li>This class implements both {@link MutableProcessingConfiguration} and {@link ParserConfiguration}. This means that it can influence * both the template parsing phase and the runtime settings. For both aspects (i.e., {@link ParserConfiguration} and - * {@link Configurable}) to take effect, you have first pass this object to the {@link Template} constructor + * {@link MutableProcessingConfiguration}) to take effect, you have first pass this object to the {@link Template} constructor * (this is where the {@link ParserConfiguration} interface is used), and then you have to call {@link #apply(Template)} - * on the resulting {@link Template} object (this is where the {@link Configurable} aspect is used). + * on the resulting {@link Template} object (this is where the {@link MutableProcessingConfiguration} aspect is used). * * <li>{@link #apply(Template)} only change the settings that weren't yet set on the {@link Template} (but are inherited * from the {@link Configuration}). This is primarily because if the template configures itself via the {@code #ftl} @@ -77,7 +77,8 @@ import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory; * * @since 2.3.24 */ -public final class TemplateConfiguration extends Configurable implements ParserConfiguration { +public final class TemplateConfiguration extends MutableProcessingConfiguration<TemplateConfiguration> + implements ParserConfiguration { private TemplateLanguage templateLanguage; private Integer tagSyntax; @@ -102,13 +103,13 @@ public final class TemplateConfiguration extends Configurable implements ParserC * Same as {@link #setParentConfiguration(Configuration)}. */ @Override - void setParent(Configurable cfg) { + void setParent(MutableProcessingConfiguration cfg) { _NullArgumentException.check("cfg", cfg); if (!(cfg instanceof Configuration)) { throw new IllegalArgumentException("The parent of a TemplateConfiguration can only be a Configuration"); } - Configurable parent = getParent(); + MutableProcessingConfiguration parent = getParent(); if (parent != null) { if (parent != cfg) { throw new IllegalStateException( @@ -144,7 +145,7 @@ public final class TemplateConfiguration extends Configurable implements ParserC } private Configuration getNonNullParentConfiguration() { - Configurable parent = getParent(); + MutableProcessingConfiguration parent = getParent(); if (parent == null) { throw new IllegalStateException("The TemplateConfiguration wasn't associated with a Configuration yet."); } @@ -253,13 +254,23 @@ public final class TemplateConfiguration extends Configurable implements ParserC setLazyAutoImports(tc.getLazyAutoImports()); } if (tc.isAutoImportsSet()) { - setAutoImports(mergeMaps(getAutoImportsWithoutFallback(), tc.getAutoImportsWithoutFallback(),true)); + setAutoImports(mergeMaps( + isAutoImportsSet() ? getAutoImports() : null, + tc.isAutoImportsSet() ? tc.getAutoImports() : null, + true)); } if (tc.isAutoIncludesSet()) { - setAutoIncludes(mergeLists(getAutoIncludesWithoutFallback(), tc.getAutoIncludesWithoutFallback())); + setAutoIncludes(mergeLists( + isAutoIncludesSet() ? getAutoIncludes() : null, + tc.isAutoIncludesSet() ? tc.getAutoIncludes() : null)); + } + + if (tc.isCustomAttributesSet()) { + setCustomAttributes(mergeMaps( + isCustomAttributesSet() ? getCustomAttributes() : null, + tc.isCustomAttributesSet() ? tc.getCustomAttributes() : null, + true)); } - - tc.copyDirectCustomAttributes(this, true); } /** @@ -301,11 +312,17 @@ public final class TemplateConfiguration extends Configurable implements ParserC } if (isCustomDateFormatsSet()) { template.setCustomDateFormats( - mergeMaps(getCustomDateFormats(), template.getCustomDateFormatsWithoutFallback(), false)); + mergeMaps( + getCustomDateFormats(), + template.isCustomDateFormatsSet() ? template.getCustomDateFormats() : null, + false)); } if (isCustomNumberFormatsSet()) { template.setCustomNumberFormats( - mergeMaps(getCustomNumberFormats(), template.getCustomNumberFormatsWithoutFallback(), false)); + mergeMaps( + getCustomNumberFormats(), + template.isCustomNumberFormatsSet() ? template.getCustomNumberFormats() : null, + false)); } if (isDateFormatSet() && !template.isDateFormatSet()) { template.setDateFormat(getDateFormat()); @@ -363,10 +380,15 @@ public final class TemplateConfiguration extends Configurable implements ParserC // - Existing template-level imports have precedence over those coming from the TC (just as with the others // apply()-ed settings), thus for clashing import prefixes they must win. // - Template-level imports count as more specific, and so come after the more generic ones from TC. - template.setAutoImports(mergeMaps(getAutoImports(), template.getAutoImportsWithoutFallback(), true)); + template.setAutoImports(mergeMaps( + getAutoImports(), + template.isAutoImportsSet() ? template.getAutoImports() : null, + true)); } if (isAutoIncludesSet()) { - template.setAutoIncludes(mergeLists(getAutoIncludes(), template.getAutoIncludesWithoutFallback())); + template.setAutoIncludes(mergeLists( + getAutoIncludes(), + template.isAutoIncludesSet() ? template.getAutoIncludes() : null)); } copyDirectCustomAttributes(template, false); @@ -388,9 +410,7 @@ public final class TemplateConfiguration extends Configurable implements ParserC return tagSyntax != null ? tagSyntax : getNonNullParentConfiguration().getTagSyntax(); } - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - */ + @Override public boolean isTagSyntaxSet() { return tagSyntax != null; } @@ -435,6 +455,7 @@ public final class TemplateConfiguration extends Configurable implements ParserC /** * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. */ + @Override public boolean isNamingConventionSet() { return namingConvention != null; } @@ -458,6 +479,7 @@ public final class TemplateConfiguration extends Configurable implements ParserC /** * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. */ + @Override public boolean isWhitespaceStrippingSet() { return whitespaceStripping != null; } @@ -483,6 +505,7 @@ public final class TemplateConfiguration extends Configurable implements ParserC /** * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. */ + @Override public boolean isAutoEscapingPolicySet() { return autoEscapingPolicy != null; } @@ -506,6 +529,7 @@ public final class TemplateConfiguration extends Configurable implements ParserC /** * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. */ + @Override public boolean isOutputFormatSet() { return outputFormat != null; } @@ -529,12 +553,14 @@ public final class TemplateConfiguration extends Configurable implements ParserC /** * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. */ + @Override public boolean isRecognizeStandardFileExtensionsSet() { return recognizeStandardFileExtensions != null; } + @Override public String getEncoding() { - return encoding != null ? encoding : getNonNullParentConfiguration().getDefaultEncoding(); + return encoding != null ? encoding : getNonNullParentConfiguration().getEncoding(); } /** @@ -580,6 +606,7 @@ public final class TemplateConfiguration extends Configurable implements ParserC * * @since 2.3.25 */ + @Override public boolean isTabSizeSet() { return tabSize != null; } @@ -596,8 +623,6 @@ public final class TemplateConfiguration extends Configurable implements ParserC return getNonNullParentConfiguration().getIncompatibleImprovements(); } - - @Override public Locale getLocale() { try { @@ -879,7 +904,7 @@ public final class TemplateConfiguration extends Configurable implements ParserC } @Override - public Object getCustomAttribute(String name) { + public Object getCustomAttribute(Object name) { try { return super.getCustomAttribute(name); } catch (NullPointerException e) { @@ -888,34 +913,6 @@ public final class TemplateConfiguration extends Configurable implements ParserC } } - private boolean hasAnyConfigurableSet() { - return - isAPIBuiltinEnabledSet() - || isArithmeticEngineSet() - || isAutoFlushSet() - || isAutoImportsSet() - || isAutoIncludesSet() - || isBooleanFormatSet() - || isCustomDateFormatsSet() - || isCustomNumberFormatsSet() - || isDateFormatSet() - || isDateTimeFormatSet() - || isLazyImportsSet() - || isLazyAutoImportsSet() - || isLocaleSet() - || isLogTemplateExceptionsSet() - || isNewBuiltinClassResolverSet() - || isNumberFormatSet() - || isObjectWrapperSet() - || isOutputEncodingSet() - || isShowErrorTipsSet() - || isSQLDateAndTimeTimeZoneSet() - || isTemplateExceptionHandlerSet() - || isTimeFormatSet() - || isTimeZoneSet() - || isURLEscapingCharsetSet(); - } - private Map mergeMaps(Map m1, Map m2, boolean overwriteUpdatesOrder) { if (m1 == null) return m2; if (m2 == null) return m1; http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/TemplateExceptionHandler.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/TemplateExceptionHandler.java b/src/main/java/org/apache/freemarker/core/TemplateExceptionHandler.java index 797a4c2..8270740 100644 --- a/src/main/java/org/apache/freemarker/core/TemplateExceptionHandler.java +++ b/src/main/java/org/apache/freemarker/core/TemplateExceptionHandler.java @@ -27,7 +27,7 @@ import org.apache.freemarker.core.util._StringUtil; /** * Used for the {@code template_exception_handler} configuration setting; - * see {@link Configurable#setTemplateExceptionHandler(TemplateExceptionHandler)} for more. + * see {@link MutableProcessingConfiguration#setTemplateExceptionHandler(TemplateExceptionHandler)} for more. */ public interface TemplateExceptionHandler { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java b/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java index 53d09ea..e709862 100644 --- a/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java +++ b/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java @@ -43,11 +43,21 @@ public final class _ParserConfigurationWithInheritedFormat implements ParserConf } @Override + public boolean isWhitespaceStrippingSet() { + return wrappedPCfg.isWhitespaceStrippingSet(); + } + + @Override public int getTagSyntax() { return wrappedPCfg.getTagSyntax(); } @Override + public boolean isTagSyntaxSet() { + return wrappedPCfg.isTagSyntaxSet(); + } + + @Override public TemplateLanguage getTemplateLanguage() { return wrappedPCfg.getTemplateLanguage(); } @@ -58,16 +68,31 @@ public final class _ParserConfigurationWithInheritedFormat implements ParserConf } @Override + public boolean isOutputFormatSet() { + return wrappedPCfg.isOutputFormatSet(); + } + + @Override public boolean getRecognizeStandardFileExtensions() { return false; } @Override + public boolean isRecognizeStandardFileExtensionsSet() { + return wrappedPCfg.isRecognizeStandardFileExtensionsSet(); + } + + @Override public int getNamingConvention() { return wrappedPCfg.getNamingConvention(); } @Override + public boolean isNamingConventionSet() { + return wrappedPCfg.isNamingConventionSet(); + } + + @Override public Version getIncompatibleImprovements() { return wrappedPCfg.getIncompatibleImprovements(); } @@ -78,13 +103,33 @@ public final class _ParserConfigurationWithInheritedFormat implements ParserConf } @Override + public boolean isAutoEscapingPolicySet() { + return wrappedPCfg.isAutoEscapingPolicySet(); + } + + @Override public ArithmeticEngine getArithmeticEngine() { return wrappedPCfg.getArithmeticEngine(); } @Override + public boolean isArithmeticEngineSet() { + return wrappedPCfg.isArithmeticEngineSet(); + } + + @Override public int getTabSize() { return wrappedPCfg.getTabSize(); } - + + @Override + public boolean isTabSizeSet() { + return wrappedPCfg.isTabSizeSet(); + } + + @Override + public String getEncoding() { + return wrappedPCfg.getEncoding(); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/debug/DebuggedEnvironment.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/debug/DebuggedEnvironment.java b/src/main/java/org/apache/freemarker/core/debug/DebuggedEnvironment.java index 9536ac8..dca312d 100644 --- a/src/main/java/org/apache/freemarker/core/debug/DebuggedEnvironment.java +++ b/src/main/java/org/apache/freemarker/core/debug/DebuggedEnvironment.java @@ -21,6 +21,8 @@ package org.apache.freemarker.core.debug; import java.rmi.RemoteException; +import org.apache.freemarker.core.MutableProcessingConfiguration; + /** * Represents the debugger-side mirror of a debugged * {@link org.apache.freemarker.core.Environment} object in the remote VM. This interface @@ -32,7 +34,7 @@ import java.rmi.RemoteException; * <p>The debug model for the configuration supports key "sharedVariables". * <p>Additionally, all of the debug models for environment, template, and * configuration also support all the setting keys of - * {@link org.apache.freemarker.core.Configurable} objects. + * {@link MutableProcessingConfiguration} objects. */ public interface DebuggedEnvironment extends DebugModel { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java b/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java index 8f83eca..c42af46 100644 --- a/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java +++ b/src/main/java/org/apache/freemarker/core/debug/RmiDebuggedEnvironmentImpl.java @@ -32,9 +32,10 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import org.apache.freemarker.core.Configurable; import org.apache.freemarker.core.Configuration; import org.apache.freemarker.core.Environment; +import org.apache.freemarker.core.MutableProcessingConfiguration; +import org.apache.freemarker.core.ProcessingConfiguration; import org.apache.freemarker.core.Template; import org.apache.freemarker.core.model.TemplateCollectionModel; import org.apache.freemarker.core.model.TemplateHashModelEx; @@ -164,17 +165,17 @@ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEn private static class DebugConfigurableModel extends DebugMapModel { static final List KEYS = Arrays.asList( - Configurable.ARITHMETIC_ENGINE_KEY, - Configurable.BOOLEAN_FORMAT_KEY, - Configurable.LOCALE_KEY, - Configurable.NUMBER_FORMAT_KEY, - Configurable.OBJECT_WRAPPER_KEY, - Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY); + MutableProcessingConfiguration.ARITHMETIC_ENGINE_KEY, + MutableProcessingConfiguration.BOOLEAN_FORMAT_KEY, + MutableProcessingConfiguration.LOCALE_KEY, + MutableProcessingConfiguration.NUMBER_FORMAT_KEY, + MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, + MutableProcessingConfiguration.TEMPLATE_EXCEPTION_HANDLER_KEY); - final Configurable configurable; + final ProcessingConfiguration ProcessingConfiguration; - DebugConfigurableModel(Configurable configurable) { - this.configurable = configurable; + DebugConfigurableModel(ProcessingConfiguration processingConfiguration) { + this.ProcessingConfiguration = processingConfiguration; } @Override @@ -196,12 +197,12 @@ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEn { @Override Collection keySet() { - return ((Configuration) configurable).getSharedVariableNames(); + return ((Configuration) ProcessingConfiguration).getSharedVariableNames(); } @Override public TemplateModel get(String key) { - return ((Configuration) configurable).getSharedVariable(key); + return ((Configuration) ProcessingConfiguration).getSharedVariable(key); } }; @@ -244,7 +245,7 @@ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEn public TemplateModel get(String key) throws TemplateModelException { if ("configuration".equals(key)) { try { - return (TemplateModel) getCachedWrapperFor(((Template) configurable).getConfiguration()); + return (TemplateModel) getCachedWrapperFor(((Template) ProcessingConfiguration).getConfiguration()); } catch (RemoteException e) { throw new TemplateModelException(e); } @@ -271,7 +272,7 @@ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEn @Override Collection keySet() { try { - return ((Environment) configurable).getKnownVariableNames(); + return ((Environment) ProcessingConfiguration).getKnownVariableNames(); } catch (TemplateModelException e) { throw new UndeclaredThrowableException(e); } @@ -279,7 +280,7 @@ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEn @Override public TemplateModel get(String key) throws TemplateModelException { - return ((Environment) configurable).getVariable(key); + return ((Environment) ProcessingConfiguration).getVariable(key); } }; @@ -295,30 +296,30 @@ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEn @Override public TemplateModel get(String key) throws TemplateModelException { if ("currentNamespace".equals(key)) { - return ((Environment) configurable).getCurrentNamespace(); + return ((Environment) ProcessingConfiguration).getCurrentNamespace(); } if ("dataModel".equals(key)) { - return ((Environment) configurable).getDataModel(); + return ((Environment) ProcessingConfiguration).getDataModel(); } if ("globalNamespace".equals(key)) { - return ((Environment) configurable).getGlobalNamespace(); + return ((Environment) ProcessingConfiguration).getGlobalNamespace(); } if ("knownVariables".equals(key)) { return knownVariables; } if ("mainNamespace".equals(key)) { - return ((Environment) configurable).getMainNamespace(); + return ((Environment) ProcessingConfiguration).getMainNamespace(); } if ("mainTemplate".equals(key)) { try { - return (TemplateModel) getCachedWrapperFor(((Environment) configurable).getMainTemplate()); + return (TemplateModel) getCachedWrapperFor(((Environment) ProcessingConfiguration).getMainTemplate()); } catch (RemoteException e) { throw new TemplateModelException(e); } } if ("currentTemplate".equals(key)) { try { - return (TemplateModel) getCachedWrapperFor(((Environment) configurable).getCurrentTemplate()); + return (TemplateModel) getCachedWrapperFor(((Environment) ProcessingConfiguration).getCurrentTemplate()); } catch (RemoteException e) { throw new TemplateModelException(e); } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java b/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java index d630752..91fe9dc 100644 --- a/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java +++ b/src/main/java/org/apache/freemarker/core/model/impl/BeanModel.java @@ -125,7 +125,7 @@ public class BeanModel * <tt>non-void-return-type get(java.lang.String)</tt>, * then <tt>non-void-return-type get(java.lang.Object)</tt>, or * alternatively (if the wrapped object is a resource bundle) - * <tt>Object getObject(java.lang.String)</tt>. + * <tt>Object get(java.lang.String)</tt>. * @throws TemplateModelException if there was no property nor method nor * a generic <tt>get</tt> method to invoke. */ http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java b/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java index 5bc97a1..6cde3ee 100644 --- a/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java +++ b/src/main/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapper.java @@ -1275,6 +1275,7 @@ public class DefaultObjectWrapper implements RichObjectWrapper { * Returns a {@link DefaultObjectWrapper} instance that matches the settings of this builder. This will be possibly * a singleton that is also in use elsewhere. */ + @Override public DefaultObjectWrapper build() { return DefaultObjectWrapperTCCLSingletonUtil.getSingleton( this, INSTANCE_CACHE, INSTANCE_CACHE_REF_QUEUE, ConstructorInvoker.INSTANCE); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java b/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java index c48b2e0..31af451 100644 --- a/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java +++ b/src/main/java/org/apache/freemarker/core/model/impl/ResourceBundleModel.java @@ -63,7 +63,7 @@ public class ResourceBundleModel } /** - * Overridden to invoke the getObject method of the resource bundle. + * Overridden to invoke the get method of the resource bundle. */ @Override protected TemplateModel invokeGenericGet(Map keyMap, Class clazz, String key) http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java b/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java index a4df46f..f520c3d 100644 --- a/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java +++ b/src/main/java/org/apache/freemarker/core/model/impl/SimpleHash.java @@ -67,11 +67,11 @@ import org.apache.freemarker.core.model.WrappingTemplateModel; * <p> * It also matters if for how many times will the <em>same</em> {@link Map} entry be read from the template(s) later, on * average. If, on average, you read each entry for more than 4 times, {@link SimpleHash} will be most certainly faster, - * but if for 2 times or less (and especially if not at all) then {@link DefaultMapAdapter} will be. Before choosing - * based on performance though, pay attention to the behavioral differences; {@link SimpleHash} will shallow-copy - * the original {@link Map} at construction time, so key order will be lost in some cases, and it won't reflect - * {@link Map} content changes after the {@link SimpleHash} construction, also {@link SimpleHash} can't be unwrapped - * to the original {@link Map} instance. + * but if for 2 times or less (and especially if not at all) then {@link DefaultMapAdapter} will be faster. Before + * choosing based on performance though, pay attention to the behavioral differences; {@link SimpleHash} will + * shallow-copy the original {@link Map} at construction time, so key order will be lost in some cases, and it won't + * reflect {@link Map} content changes after the {@link SimpleHash} construction, also {@link SimpleHash} can't be + * unwrapped to the original {@link Map} instance. * * @see DefaultMapAdapter * @see TemplateHashModelEx http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/model/impl/SimpleSequence.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/model/impl/SimpleSequence.java b/src/main/java/org/apache/freemarker/core/model/impl/SimpleSequence.java index 907acb2..1b949f1 100644 --- a/src/main/java/org/apache/freemarker/core/model/impl/SimpleSequence.java +++ b/src/main/java/org/apache/freemarker/core/model/impl/SimpleSequence.java @@ -59,7 +59,7 @@ import org.apache.freemarker.core.model.WrappingTemplateModel; * It also matters if for how many times will the <em>same</em> {@link List} entry be read from the template(s) later, * on average. If, on average, you read each entry for more than 4 times, {@link SimpleSequence} will be most * certainly faster, but if for 2 times or less (and especially if not at all) then {@link DefaultMapAdapter} will - * be. Before choosing based on performance though, pay attention to the behavioral differences; + * be faster. Before choosing based on performance though, pay attention to the behavioral differences; * {@link SimpleSequence} will shallow-copy the original {@link List} at construction time, so it won't reflect * {@link List} content changes after the {@link SimpleSequence} construction, also {@link SimpleSequence} can't be * unwrapped to the original wrapped instance. http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java b/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java index a5a574c..4436874 100644 --- a/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java +++ b/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java @@ -551,10 +551,8 @@ public class DefaultTemplateResolver extends TemplateResolver { if (tc != null && tc.isLocaleSet()) { locale = tc.getLocale(); } - - String initialEncoding = tc != null && tc.isEncodingSet() ? tc.getEncoding() : config.getDefaultEncoding(); - TemplateLanguage templateLanguage = tc != null && tc.isTemplateLanguageSet() ? tc.getTemplateLanguage() - : config .getTemplateLanguage(); + String initialEncoding = tc != null ? tc.getEncoding() : config.getEncoding(); + TemplateLanguage templateLanguage = tc != null ? tc.getTemplateLanguage() : config .getTemplateLanguage(); Template template; { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/util/OptInTemplateClassResolver.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/util/OptInTemplateClassResolver.java b/src/main/java/org/apache/freemarker/core/util/OptInTemplateClassResolver.java index 51da424..8fd7b38 100644 --- a/src/main/java/org/apache/freemarker/core/util/OptInTemplateClassResolver.java +++ b/src/main/java/org/apache/freemarker/core/util/OptInTemplateClassResolver.java @@ -26,7 +26,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import org.apache.freemarker.core.Configurable; +import org.apache.freemarker.core.MutableProcessingConfiguration; import org.apache.freemarker.core.Environment; import org.apache.freemarker.core.Template; import org.apache.freemarker.core.TemplateClassResolver; @@ -104,7 +104,7 @@ public class OptInTemplateClassResolver implements TemplateClassResolver { throw new _MiscTemplateException(env, "Instantiating ", className, " is not allowed in the template for security reasons. (If you " + "run into this problem when using ?new in a template, you may want to check the \"", - Configurable.NEW_BUILTIN_CLASS_RESOLVER_KEY, + MutableProcessingConfiguration.NEW_BUILTIN_CLASS_RESOLVER_KEY, "\" setting in the FreeMarker configuration.)"); } else { try { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/util/_CollectionUtil.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/util/_CollectionUtil.java b/src/main/java/org/apache/freemarker/core/util/_CollectionUtil.java index 1b54947..5d532de 100644 --- a/src/main/java/org/apache/freemarker/core/util/_CollectionUtil.java +++ b/src/main/java/org/apache/freemarker/core/util/_CollectionUtil.java @@ -25,8 +25,8 @@ public class _CollectionUtil { private _CollectionUtil() { } public static final Object[] EMPTY_OBJECT_ARRAY = new Object[] { }; - public static final Class[] EMPTY_CLASS_ARRAY = new Class[] { }; + public static final String[] EMPTY_STRING_ARRAY = new String[] { }; /** * @since 2.3.22 http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/util/_LocaleUtil.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/util/_LocaleUtil.java b/src/main/java/org/apache/freemarker/core/util/_LocaleUtil.java index 2ee4d53..2f09c88 100644 --- a/src/main/java/org/apache/freemarker/core/util/_LocaleUtil.java +++ b/src/main/java/org/apache/freemarker/core/util/_LocaleUtil.java @@ -22,9 +22,7 @@ import java.util.Locale; /** * For internal use only; don't depend on this, there's no backward compatibility guarantee at all! - * This class is to work around the lack of module system in Java, i.e., so that other FreeMarker packages can - * access things inside this package that users shouldn't. - */ + */ public class _LocaleUtil { /** http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/util/_ObjectHolder.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/util/_ObjectHolder.java b/src/main/java/org/apache/freemarker/core/util/_ObjectHolder.java new file mode 100644 index 0000000..cbd7e11 --- /dev/null +++ b/src/main/java/org/apache/freemarker/core/util/_ObjectHolder.java @@ -0,0 +1,55 @@ +/* + * 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.util; + +/** + * For internal use only; don't depend on this, there's no backward compatibility guarantee at all! + */ +public class _ObjectHolder<T> { + + private T object; + + public _ObjectHolder(T object) { + this.object = object; + } + + public T get() { + return object; + } + + public void set(T object) { + this.object = object; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + _ObjectHolder<?> that = (_ObjectHolder<?>) o; + + return object != null ? object.equals(that.object) : that.object == null; + } + + @Override + public int hashCode() { + return object != null ? object.hashCode() : 0; + } +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/valueformat/TemplateDateFormatFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/valueformat/TemplateDateFormatFactory.java b/src/main/java/org/apache/freemarker/core/valueformat/TemplateDateFormatFactory.java index 5ee26e0..07c2256 100644 --- a/src/main/java/org/apache/freemarker/core/valueformat/TemplateDateFormatFactory.java +++ b/src/main/java/org/apache/freemarker/core/valueformat/TemplateDateFormatFactory.java @@ -23,7 +23,7 @@ import java.util.Date; import java.util.Locale; import java.util.TimeZone; -import org.apache.freemarker.core.Configurable; +import org.apache.freemarker.core.MutableProcessingConfiguration; import org.apache.freemarker.core.Configuration; import org.apache.freemarker.core.Environment; import org.apache.freemarker.core.model.TemplateDateModel; @@ -32,7 +32,7 @@ import org.apache.freemarker.core.model.TemplateDateModel; * Factory for a certain kind of date/time/dateTime formatting ({@link TemplateDateFormat}). Usually a singleton * (one-per-VM or one-per-{@link Configuration}), and so must be thread-safe. * - * @see Configurable#setCustomDateFormats(java.util.Map) + * @see MutableProcessingConfiguration#setCustomDateFormats(java.util.Map) * * @since 2.3.24 */ @@ -50,7 +50,7 @@ public abstract class TemplateDateFormatFactory extends TemplateValueFormatFacto * * @param params * The string that further describes how the format should look. For example, when the - * {@link Configurable#getDateFormat() dateFormat} is {@code "@fooBar 1, 2"}, then it will be + * {@link MutableProcessingConfiguration#getDateFormat() dateFormat} is {@code "@fooBar 1, 2"}, then it will be * {@code "1, 2"} (and {@code "@fooBar"} selects the factory). The format of this string is up to the * {@link TemplateDateFormatFactory} implementation. Not {@code null}, often an empty string. * @param dateType http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/valueformat/TemplateNumberFormatFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/valueformat/TemplateNumberFormatFactory.java b/src/main/java/org/apache/freemarker/core/valueformat/TemplateNumberFormatFactory.java index 464e6ff..7e21cfe 100644 --- a/src/main/java/org/apache/freemarker/core/valueformat/TemplateNumberFormatFactory.java +++ b/src/main/java/org/apache/freemarker/core/valueformat/TemplateNumberFormatFactory.java @@ -20,7 +20,7 @@ package org.apache.freemarker.core.valueformat; import java.util.Locale; -import org.apache.freemarker.core.Configurable; +import org.apache.freemarker.core.MutableProcessingConfiguration; import org.apache.freemarker.core.Configuration; import org.apache.freemarker.core.Environment; @@ -28,7 +28,7 @@ import org.apache.freemarker.core.Environment; * Factory for a certain kind of number formatting ({@link TemplateNumberFormat}). Usually a singleton (one-per-VM or * one-per-{@link Configuration}), and so must be thread-safe. * - * @see Configurable#setCustomNumberFormats(java.util.Map) + * @see MutableProcessingConfiguration#setCustomNumberFormats(java.util.Map) * * @since 2.3.24 */ @@ -46,7 +46,7 @@ public abstract class TemplateNumberFormatFactory extends TemplateValueFormatFac * * @param params * The string that further describes how the format should look. For example, when the - * {@link Configurable#getNumberFormat() numberFormat} is {@code "@fooBar 1, 2"}, then it will be + * {@link MutableProcessingConfiguration#getNumberFormat() numberFormat} is {@code "@fooBar 1, 2"}, then it will be * {@code "1, 2"} (and {@code "@fooBar"} selects the factory). The format of this string is up to the * {@link TemplateNumberFormatFactory} implementation. Not {@code null}, often an empty string. * @param locale http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/core/valueformat/impl/ISOLikeTemplateDateFormatFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/valueformat/impl/ISOLikeTemplateDateFormatFactory.java b/src/main/java/org/apache/freemarker/core/valueformat/impl/ISOLikeTemplateDateFormatFactory.java index fb13fad..5db8f46 100644 --- a/src/main/java/org/apache/freemarker/core/valueformat/impl/ISOLikeTemplateDateFormatFactory.java +++ b/src/main/java/org/apache/freemarker/core/valueformat/impl/ISOLikeTemplateDateFormatFactory.java @@ -19,6 +19,7 @@ package org.apache.freemarker.core.valueformat.impl; +import org.apache.freemarker.core.CustomStateKey; import org.apache.freemarker.core.Environment; import org.apache.freemarker.core.util._DateUtil.CalendarFieldsToDateConverter; import org.apache.freemarker.core.util._DateUtil.DateToISO8601CalendarFactory; @@ -28,27 +29,29 @@ import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory; abstract class ISOLikeTemplateDateFormatFactory extends TemplateDateFormatFactory { - private static final Object DATE_TO_CAL_CONVERTER_KEY = new Object(); - private static final Object CAL_TO_DATE_CONVERTER_KEY = new Object(); + private static final CustomStateKey<TrivialDateToISO8601CalendarFactory> DATE_TO_CAL_CONVERTER_KEY + = new CustomStateKey<TrivialDateToISO8601CalendarFactory>() { + @Override + protected TrivialDateToISO8601CalendarFactory create() { + return new TrivialDateToISO8601CalendarFactory(); + } + }; + private static final CustomStateKey<TrivialCalendarFieldsToDateConverter> CAL_TO_DATE_CONVERTER_KEY + = new CustomStateKey<TrivialCalendarFieldsToDateConverter>() { + @Override + protected TrivialCalendarFieldsToDateConverter create() { + return new TrivialCalendarFieldsToDateConverter(); + } + }; protected ISOLikeTemplateDateFormatFactory() { } public DateToISO8601CalendarFactory getISOBuiltInCalendar(Environment env) { - DateToISO8601CalendarFactory r = (DateToISO8601CalendarFactory) env.getCustomState(DATE_TO_CAL_CONVERTER_KEY); - if (r == null) { - r = new TrivialDateToISO8601CalendarFactory(); - env.setCustomState(DATE_TO_CAL_CONVERTER_KEY, r); - } - return r; + return (DateToISO8601CalendarFactory) env.getCustomState(DATE_TO_CAL_CONVERTER_KEY); } public CalendarFieldsToDateConverter getCalendarFieldsToDateCalculator(Environment env) { - CalendarFieldsToDateConverter r = (CalendarFieldsToDateConverter) env.getCustomState(CAL_TO_DATE_CONVERTER_KEY); - if (r == null) { - r = new TrivialCalendarFieldsToDateConverter(); - env.setCustomState(CAL_TO_DATE_CONVERTER_KEY, r); - } - return r; + return (CalendarFieldsToDateConverter) env.getCustomState(CAL_TO_DATE_CONVERTER_KEY); } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/dom/JaxenXPathSupport.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/dom/JaxenXPathSupport.java b/src/main/java/org/apache/freemarker/dom/JaxenXPathSupport.java index 36773f4..f578158 100644 --- a/src/main/java/org/apache/freemarker/dom/JaxenXPathSupport.java +++ b/src/main/java/org/apache/freemarker/dom/JaxenXPathSupport.java @@ -31,7 +31,7 @@ import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import org.apache.freemarker.core.CustomAttribute; +import org.apache.freemarker.core.CustomStateKey; import org.apache.freemarker.core.Environment; import org.apache.freemarker.core.Template; import org.apache.freemarker.core.TemplateException; @@ -42,6 +42,7 @@ import org.apache.freemarker.core.model.TemplateModelException; import org.apache.freemarker.core.model.TemplateNumberModel; import org.apache.freemarker.core.model.TemplateScalarModel; import org.apache.freemarker.core.util.UndeclaredThrowableException; +import org.apache.freemarker.core.util._ObjectHolder; import org.jaxen.BaseXPath; import org.jaxen.Function; import org.jaxen.FunctionCallException; @@ -62,14 +63,14 @@ import org.xml.sax.SAXException; /** */ class JaxenXPathSupport implements XPathSupport { - - private static final CustomAttribute XPATH_CACHE_ATTR = - new CustomAttribute(CustomAttribute.SCOPE_TEMPLATE) { - @Override - protected Object create() { - return new HashMap<String, BaseXPath>(); - } - }; + + private static final CustomStateKey<Map<String, BaseXPath>> XPATH_CACHE_ATTR + = new CustomStateKey<Map<String, BaseXPath>>() { + @Override + protected Map<String, BaseXPath> create() { + return new HashMap<String, BaseXPath>(); + } + }; // [2.4] Can't we just use Collections.emptyList()? private final static ArrayList EMPTY_ARRAYLIST = new ArrayList(); @@ -78,7 +79,8 @@ class JaxenXPathSupport implements XPathSupport { public TemplateModel executeQuery(Object context, String xpathQuery) throws TemplateModelException { try { BaseXPath xpath; - Map<String, BaseXPath> xpathCache = (Map<String, BaseXPath>) XPATH_CACHE_ATTR.get(); + Map<String, BaseXPath> xpathCache = Environment.getCurrentEnvironmentNotNull().getCurrentTemplateNotNull() + .getCustomState(XPATH_CACHE_ATTR); synchronized (xpathCache) { xpath = xpathCache.get(xpathQuery); if (xpath == null) { @@ -162,29 +164,38 @@ class JaxenXPathSupport implements XPathSupport { /** * Stores the the template parsed as {@link Document} in the template itself. */ - private static final CustomAttribute FM_DOM_NAVIAGOTOR_CACHED_DOM - = new CustomAttribute(CustomAttribute.SCOPE_TEMPLATE); + private static final CustomStateKey<_ObjectHolder<Document>> FM_DOM_NAVIAGOTOR_CACHED_DOM + = new CustomStateKey<_ObjectHolder<Document>>() { + @Override + protected _ObjectHolder<Document> create() { + return new _ObjectHolder<>(null); + } + }; private static final Navigator FM_DOM_NAVIGATOR = new DocumentNavigator() { @Override public Object getDocument(String uri) throws FunctionCallException { try { Template raw = getTemplate(uri); - Document doc = (Document) FM_DOM_NAVIAGOTOR_CACHED_DOM.get(raw); - if (doc == null) { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - FmEntityResolver er = new FmEntityResolver(); - builder.setEntityResolver(er); - doc = builder.parse(createInputSource(null, raw)); - // If the entity resolver got called 0 times, the document - // is standalone, so we can safely cache it - if (er.getCallCount() == 0) { - FM_DOM_NAVIAGOTOR_CACHED_DOM.set(doc, raw); + _ObjectHolder<Document> docHolder = Environment.getCurrentEnvironmentNotNull() + .getCurrentTemplateNotNull().getCustomState(FM_DOM_NAVIAGOTOR_CACHED_DOM); + synchronized (docHolder) { + Document doc = docHolder.get(); + if (doc == null) { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + FmEntityResolver er = new FmEntityResolver(); + builder.setEntityResolver(er); + doc = builder.parse(createInputSource(null, raw)); + // If the entity resolver got called 0 times, the document + // is standalone, so we can safely cache it + if (er.getCallCount() == 0) { + docHolder.set(doc); + } } + return doc; } - return doc; } catch (Exception e) { throw new FunctionCallException("Failed to parse document for URI: " + uri, e); } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java b/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java index 0853133..48fcde5 100644 --- a/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java +++ b/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java @@ -41,7 +41,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.apache.freemarker.core.Configurable; +import org.apache.freemarker.core.MutableProcessingConfiguration; import org.apache.freemarker.core.Configuration; import org.apache.freemarker.core.ConfigurationException; import org.apache.freemarker.core.Environment; @@ -199,16 +199,16 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; * {@value #INIT_PARAM_VALUE_FROM_TEMPLATE} (or some of the other options) instead. {@value #INIT_PARAM_VALUE_LEGACY} * will use the charset of the template file to set the charset of the servlet response. Except, if the * {@value #INIT_PARAM_CONTENT_TYPE} init-param contains a charset, it will use that instead. A quirk of this legacy - * mode is that it's not aware of the {@link Configurable#getOutputEncoding()} FreeMarker setting, and thus never reads + * mode is that it's not aware of the {@link MutableProcessingConfiguration#getOutputEncoding()} FreeMarker setting, and thus never reads * or writes it (though very few applications utilize that setting anyway). Also, it sets the charset of the servlet * response by adding it to the response content type via calling {@link HttpServletResponse#setContentType(String)} (as * that was the only way before Servlet 2.4), not via the more modern * {@link HttpServletResponse#setCharacterEncoding(String)} method. Note that the charset of a template usually comes - * from {@link Configuration#getDefaultEncoding()} (i.e., from the {@code default_encoding} FreeMarker setting), + * from {@link Configuration#getEncoding()} (i.e., from the {@code encoding} FreeMarker setting), * or occasionally from {@link Configuration#getTemplateConfigurations()} (when FreeMarker was * configured to use a specific charset for certain templates). * <li>{@value #INIT_PARAM_VALUE_FROM_TEMPLATE}: This should be used in most applications, but it's not the default for - * backward compatibility. It reads the {@link Configurable#getOutputEncoding()} setting of the template (note that the + * backward compatibility. It reads the {@link MutableProcessingConfiguration#getOutputEncoding()} setting of the template (note that the * template usually just inherits that from the {@link Configuration}), and if that's not set, then reads the source * charset of the template, just like {@value #INIT_PARAM_VALUE_LEGACY}, and if that's {@code null} (which happens if * the template was loaded from a non-binary source) then it will be UTF-8. Then it passes the charset acquired this way @@ -622,16 +622,16 @@ public class FreemarkerServlet extends HttpServlet { try { if (name.equals(DEPR_INITPARAM_OBJECT_WRAPPER) - || name.equals(Configurable.OBJECT_WRAPPER_KEY) + || name.equals(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY) || name.equals(INIT_PARAM_TEMPLATE_PATH) || name.equals(Configuration.INCOMPATIBLE_IMPROVEMENTS_KEY)) { // ignore: we have already processed these } else if (name.equals(DEPR_INITPARAM_ENCODING)) { // BC - if (getInitParameter(Configuration.DEFAULT_ENCODING_KEY) != null) { + if (getInitParameter(Configuration.ENCODING_KEY) != null) { throw new ConflictingInitParamsException( - Configuration.DEFAULT_ENCODING_KEY, DEPR_INITPARAM_ENCODING); + Configuration.ENCODING_KEY, DEPR_INITPARAM_ENCODING); } - config.setDefaultEncoding(value); + config.setEncoding(value); } else if (name.equals(DEPR_INITPARAM_TEMPLATE_DELAY)) { // BC if (getInitParameter(Configuration.TEMPLATE_UPDATE_DELAY_KEY) != null) { throw new ConflictingInitParamsException( @@ -643,9 +643,9 @@ public class FreemarkerServlet extends HttpServlet { // Intentionally ignored } } else if (name.equals(DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER)) { // BC - if (getInitParameter(Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY) != null) { + if (getInitParameter(MutableProcessingConfiguration.TEMPLATE_EXCEPTION_HANDLER_KEY) != null) { throw new ConflictingInitParamsException( - Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY, DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER); + MutableProcessingConfiguration.TEMPLATE_EXCEPTION_HANDLER_KEY, DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER); } if (DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_RETHROW.equals(value)) { @@ -1279,13 +1279,13 @@ public class FreemarkerServlet extends HttpServlet { * should override {@link #createDefaultObjectWrapper()} instead. Overriding this method is necessary when you want * to customize how the {@link ObjectWrapper} is created <em>from the init-param values</em>, or you want to do some * post-processing (like checking) on the created {@link ObjectWrapper}. To customize init-param interpretation, - * call {@link #getInitParameter(String)} with {@link Configurable#OBJECT_WRAPPER_KEY} as argument, and see if it + * call {@link #getInitParameter(String)} with {@link MutableProcessingConfiguration#OBJECT_WRAPPER_KEY} as argument, and see if it * returns a value that you want to interpret yourself. If was {@code null} or you don't want to interpret the * value, fall back to the super method. * * <p> * The default implementation interprets the {@code object_wrapper} servlet init-param with - * calling {@link Configurable#setSetting(String, String)} (see valid values there), or if there's no such servlet + * calling {@link MutableProcessingConfiguration#setSetting(String, String)} (see valid values there), or if there's no such servlet * init-param, then it calls {@link #createDefaultObjectWrapper()}. * * @return The {@link ObjectWrapper} that will be used for adapting request, session, and servlet context attributes @@ -1294,9 +1294,9 @@ public class FreemarkerServlet extends HttpServlet { protected ObjectWrapperAndUnwrapper createObjectWrapper() { String wrapper = getServletConfig().getInitParameter(DEPR_INITPARAM_OBJECT_WRAPPER); if (wrapper != null) { // BC - if (getInitParameter(Configurable.OBJECT_WRAPPER_KEY) != null) { + if (getInitParameter(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY) != null) { throw new RuntimeException("Conflicting init-params: " - + Configurable.OBJECT_WRAPPER_KEY + " and " + + MutableProcessingConfiguration.OBJECT_WRAPPER_KEY + " and " + DEPR_INITPARAM_OBJECT_WRAPPER); } if (DEPR_INITPARAM_WRAPPER_RESTRICTED.equals(wrapper)) { @@ -1304,7 +1304,7 @@ public class FreemarkerServlet extends HttpServlet { } return createDefaultObjectWrapper(); } else { - wrapper = getInitParameter(Configurable.OBJECT_WRAPPER_KEY); + wrapper = getInitParameter(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY); if (wrapper == null) { if (!config.isObjectWrapperExplicitlySet()) { return createDefaultObjectWrapper(); @@ -1313,9 +1313,9 @@ public class FreemarkerServlet extends HttpServlet { } } else { try { - config.setSetting(Configurable.OBJECT_WRAPPER_KEY, wrapper); + config.setSetting(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, wrapper); } catch (ConfigurationException e) { - throw new RuntimeException("Failed to set " + Configurable.OBJECT_WRAPPER_KEY, e); + throw new RuntimeException("Failed to set " + MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, e); } return asObjectWrapperAndUnwrapper(config.getObjectWrapper()); } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/053afbf5/src/manual/en_US/FM3-CHANGE-LOG.txt ---------------------------------------------------------------------- diff --git a/src/manual/en_US/FM3-CHANGE-LOG.txt b/src/manual/en_US/FM3-CHANGE-LOG.txt index 5330a6a..9a149b3 100644 --- a/src/manual/en_US/FM3-CHANGE-LOG.txt +++ b/src/manual/en_US/FM3-CHANGE-LOG.txt @@ -170,4 +170,19 @@ the FreeMarer 3 changelog here: again, the charset of a template file is independent of how you access it.) - Removed Configuration.setEncoding(java.util.Locale, String) and the related other methods. Because of the new logic of template encodings, the locale to encoding mapping doesn't make much sense anymore. -- Require customLookupCondition-s to be Serializable. \ No newline at end of file +- Require customLookupCondition-s to be Serializable. +- Various refactorings of Configurable and its subclasses. This is part of the preparation for making such classes immutable, and offer + builders to create them. + - Removed CustomAttribute class. Custom attribute keys can be anything at the moment (this will be certainly restricted later) + - As customAttributes won't be modifiable after Builder.build(), they can't be used for on-demand created data structures anymore (such as + Template-scoped caches) anymore. To fulfill that role, the CustomStateKey class and the CustomStateScope interface was introduced, which + is somewhat similar to the now removed CustomAttribute. CustomStateScope contains one method, Object getCustomState(CustomStateKey), which + may calls CustomStateKey.create() to lazily create the state object for the key. Configuration, Template and Environment implements + CustomStateScope. + - Added getter/setter to access custom attributes as a Map. (This is to make it less an exceptional setting.) + - Environment.setCustomState(Object, Object) and getCustomState(Object) was replaced with CustomStateScope.getCustomState(CustomStateKey). + - Added ProcessingConfiguration interface for the read-only access of template processing settings. This is similar to the + already existing (in FM2) ParserConfiguration interface. + - Renamed Configurable to MutableProcessingAndParserConfiguration. Made it abstract too. + - Renamed Configuration.defaultEncoding to encoding, also added encoding ParserConfiguration. Before this, defaultEncoding was exclusive + to Configuration, but now it's like any other ParserConfiguration setting. \ No newline at end of file
