You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/06/06 22:49:18 UTC
[1/2] incubator-freemarker git commit: Added the `templateResolver`
Configuration setting. This allows replacing the whole template lookup,
loading and caching logic with a custom implementation,
giving total control over this aspect of FreeMarker, in ca
Repository: incubator-freemarker
Updated Branches:
refs/heads/3 2f1f291dd -> 8915ac9bd
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
index 574fa82..356e6ed 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
@@ -19,6 +19,8 @@
package org.apache.freemarker.core;
+import static org.apache.freemarker.core.Configuration.ExtendableBuilder.*;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
@@ -76,7 +78,6 @@ import org.apache.freemarker.core.templateresolver.impl.MruCacheStorage;
import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage;
import org.apache.freemarker.core.util.BugException;
import org.apache.freemarker.core.util.CaptureOutput;
-import org.apache.freemarker.core.util.CommonBuilder;
import org.apache.freemarker.core.util.HtmlEscape;
import org.apache.freemarker.core.util.NormalizeNewlines;
import org.apache.freemarker.core.util.StandardCompress;
@@ -137,8 +138,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
* <p>The setting reader methods of this class don't throw {@link CoreSettingValueNotSetException}, because all settings
* are set on the {@link Configuration} level (even if they were just initialized to a default value).
*/
-public final class Configuration
- implements TopLevelConfiguration, CustomStateScope {
+public final class Configuration implements TopLevelConfiguration, CustomStateScope {
private static final String VERSION_PROPERTIES_PATH = "org/apache/freemarker/core/version.properties";
@@ -237,8 +237,14 @@ public final class Configuration
// Configuration-specific settings:
private final Version incompatibleImprovements;
- private final DefaultTemplateResolver templateResolver;
- private final boolean localizedLookup;
+ private final TemplateResolver templateResolver;
+ private final TemplateLoader templateLoader;
+ private final CacheStorage cacheStorage;
+ private final TemplateLookupStrategy templateLookupStrategy;
+ private final TemplateNameFormat templateNameFormat;
+ private final TemplateConfigurationFactory templateConfigurations;
+ private final Long templateUpdateDelayMilliseconds;
+ private final Boolean localizedLookup;
private final List<OutputFormat> registeredCustomOutputFormats;
private final Map<String, OutputFormat> registeredCustomOutputFormatsByName;
private final Map<String, Object> sharedVariables;
@@ -291,20 +297,9 @@ public final class Configuration
private <SelfT extends ExtendableBuilder<SelfT>> Configuration(ExtendableBuilder<SelfT> builder)
throws ConfigurationException {
- // Configuration-specific settings:
-
+ // Configuration-specific settings (except templateResolver):
incompatibleImprovements = builder.getIncompatibleImprovements();
- templateResolver = new DefaultTemplateResolver(
- builder.getTemplateLoader(),
- builder.getCacheStorage(), builder.getTemplateUpdateDelayMilliseconds(),
- builder.getTemplateLookupStrategy(), builder.getLocalizedLookup(),
- builder.getTemplateNameFormat(),
- builder.getTemplateConfigurations(),
- this);
-
- localizedLookup = builder.getLocalizedLookup();
-
{
Collection<OutputFormat> registeredCustomOutputFormats = builder.getRegisteredCustomOutputFormats();
@@ -438,6 +433,67 @@ public final class Configuration
lazyImports = builder.getLazyImports();
lazyAutoImports = builder.getLazyAutoImports();
customSettings = builder.getCustomSettings(false);
+
+ // Configuration-specific settings continued... templateResolver):
+
+ templateResolver = builder.getTemplateResolver();
+
+ templateLoader = builder.getTemplateLoader();
+ if (!templateResolver.supportsTemplateLoaderSetting()) {
+ checkSettingIsNullForThisTemplateResolver(
+ templateResolver, TEMPLATE_LOADER_KEY, templateLoader);
+ }
+
+ cacheStorage = builder.getCacheStorage();
+ if (!templateResolver.supportsCacheStorageSetting()) {
+ checkSettingIsNullForThisTemplateResolver(
+ templateResolver, CACHE_STORAGE_KEY, cacheStorage);
+ }
+
+ templateUpdateDelayMilliseconds = builder.getTemplateUpdateDelayMilliseconds();
+ if (!templateResolver.supportsTemplateUpdateDelayMillisecondsSetting()) {
+ checkSettingIsNullForThisTemplateResolver(
+ templateResolver, TEMPLATE_UPDATE_DELAY_KEY, templateUpdateDelayMilliseconds);
+ }
+
+ templateLookupStrategy = builder.getTemplateLookupStrategy();
+ if (!templateResolver.supportsTemplateLookupStrategySetting()) {
+ checkSettingIsNullForThisTemplateResolver(
+ templateResolver, TEMPLATE_LOOKUP_STRATEGY_KEY, templateLookupStrategy);
+ }
+
+ localizedLookup = builder.getLocalizedLookup();
+ if (!templateResolver.supportsLocalizedLookupSetting()) {
+ checkSettingIsNullForThisTemplateResolver(
+ templateResolver, LOCALIZED_LOOKUP_KEY, localizedLookup);
+ }
+
+ templateNameFormat = builder.getTemplateNameFormat();
+ if (!templateResolver.supportsTemplateNameFormatSetting()) {
+ checkSettingIsNullForThisTemplateResolver(
+ templateResolver, TEMPLATE_NAME_FORMAT_KEY, templateNameFormat);
+ }
+
+ templateConfigurations = builder.getTemplateConfigurations();
+ if (!templateResolver.supportsTemplateConfigurationsSetting()) {
+ checkSettingIsNullForThisTemplateResolver(
+ templateResolver, TEMPLATE_CONFIGURATIONS_KEY, templateConfigurations);
+ }
+
+ templateResolver.setDependencies(new TemplateResolverDependenciesImpl(this, templateResolver));
+ }
+
+ private void checkSettingIsNullForThisTemplateResolver(
+ TemplateResolver templateResolver,
+ String settingName, Object value) {
+ if (value != null) {
+ throw new ConfigurationSettingValueException(
+ settingName, null, false,
+ "The templateResolver is a "
+ + templateResolver.getClass().getName() + ", which doesn't support this setting, hence it "
+ + "mustn't be set or must be set to null.",
+ null);
+ }
}
private <SelfT extends ExtendableBuilder<SelfT>> void wrapAndPutSharedVariables(
@@ -478,11 +534,24 @@ public final class Configuration
}
@Override
+ public TemplateResolver getTemplateResolver() {
+ return templateResolver;
+ }
+
+
+
+ /**
+ * Always {@code true} in {@link Configuration}-s; even if this setting wasn't set in the builder, it gets a default
+ * value in the {@link Configuration}.
+ */
+ @Override
+ public boolean isTemplateResolverSet() {
+ return true;
+ }
+
+ @Override
public TemplateLoader getTemplateLoader() {
- if (templateResolver == null) {
- return null;
- }
- return templateResolver.getTemplateLoader();
+ return templateLoader;
}
/**
@@ -496,10 +565,7 @@ public final class Configuration
@Override
public TemplateLookupStrategy getTemplateLookupStrategy() {
- if (templateResolver == null) {
- return null;
- }
- return templateResolver.getTemplateLookupStrategy();
+ return templateLookupStrategy;
}
/**
@@ -513,10 +579,7 @@ public final class Configuration
@Override
public TemplateNameFormat getTemplateNameFormat() {
- if (templateResolver == null) {
- return null;
- }
- return templateResolver.getTemplateNameFormat();
+ return templateNameFormat;
}
/**
@@ -530,10 +593,7 @@ public final class Configuration
@Override
public TemplateConfigurationFactory getTemplateConfigurations() {
- if (templateResolver == null) {
- return null;
- }
- return templateResolver.getTemplateConfigurations();
+ return templateConfigurations;
}
/**
@@ -547,7 +607,7 @@ public final class Configuration
@Override
public CacheStorage getCacheStorage() {
- return templateResolver.getCacheStorage();
+ return cacheStorage;
}
/**
@@ -560,8 +620,8 @@ public final class Configuration
}
@Override
- public long getTemplateUpdateDelayMilliseconds() {
- return templateResolver.getTemplateUpdateDelayMilliseconds();
+ public Long getTemplateUpdateDelayMilliseconds() {
+ return templateUpdateDelayMilliseconds;
}
/**
@@ -1350,7 +1410,7 @@ public final class Configuration
if (locale == null) {
locale = getLocale();
}
- final GetTemplateResult maybeTemp = templateResolver.getTemplate(name, locale, customLookupCondition);
+ final GetTemplateResult maybeTemp = getTemplateResolver().getTemplate(name, locale, customLookupCondition);
final Template temp = maybeTemp.getTemplate();
if (temp == null) {
if (ignoreMissing) {
@@ -1455,7 +1515,7 @@ public final class Configuration
* <p>This method is thread-safe and can be called while the engine processes templates.
*/
public void clearTemplateCache() {
- templateResolver.clearTemplateCache();
+ getTemplateResolver().clearTemplateCache();
}
/**
@@ -1472,12 +1532,12 @@ public final class Configuration
*/
public void removeTemplateFromCache(String name, Locale locale, Serializable customLookupCondition)
throws IOException {
- templateResolver.removeTemplateFromCache(name, locale, customLookupCondition);
+ getTemplateResolver().removeTemplateFromCache(name, locale, customLookupCondition);
}
@Override
- public boolean getLocalizedLookup() {
- return templateResolver.getLocalizedLookup();
+ public Boolean getLocalizedLookup() {
+ return localizedLookup;
}
/**
@@ -1600,7 +1660,7 @@ public final class Configuration
*/
public abstract static class ExtendableBuilder<SelfT extends ExtendableBuilder<SelfT>>
extends MutableParsingAndProcessingConfiguration<SelfT>
- implements TopLevelConfiguration, CommonBuilder<Configuration> {
+ implements TopLevelConfiguration, org.apache.freemarker.core.util.CommonBuilder<Configuration> {
/** Legacy, snake case ({@code like_this}) variation of the setting name. */
public static final String SOURCE_ENCODING_KEY_SNAKE_CASE = "source_encoding";
@@ -1726,16 +1786,23 @@ public final class Configuration
// Set early in the constructor to non-null
private Version incompatibleImprovements = Configuration.VERSION_3_0_0;
+ private TemplateResolver templateResolver;
+ private TemplateResolver cachedDefaultTemplateResolver;
private TemplateLoader templateLoader;
private boolean templateLoaderSet;
private CacheStorage cacheStorage;
+ private boolean cacheStorageSet;
private CacheStorage cachedDefaultCacheStorage;
private TemplateLookupStrategy templateLookupStrategy;
+ private boolean templateLookupStrategySet;
private TemplateNameFormat templateNameFormat;
+ private boolean templateNameFormatSet;
private TemplateConfigurationFactory templateConfigurations;
private boolean templateConfigurationsSet;
private Long templateUpdateDelayMilliseconds;
+ private boolean templateUpdateDelayMillisecondsSet;
private Boolean localizedLookup;
+ private boolean localizedLookupSet;
private Collection<OutputFormat> registeredCustomOutputFormats;
private Map<String, Object> sharedVariables;
@@ -2024,8 +2091,48 @@ public final class Configuration
}
@Override
+ public TemplateResolver getTemplateResolver() {
+ return isTemplateResolverSet() ? templateResolver : getDefaultTemplateResolver();
+ }
+
+ @Override
+ public boolean isTemplateResolverSet() {
+ return templateResolver != null;
+ }
+
+ protected TemplateResolver getDefaultTemplateResolver() {
+ if (cachedDefaultTemplateResolver == null) {
+ cachedDefaultTemplateResolver = new DefaultTemplateResolver();
+ }
+ return cachedDefaultTemplateResolver;
+ }
+
+ /**
+ * Setter pair of {@link Configuration#getTemplateResolver()}; note {@code null}.
+ */
+ public void setTemplateResolver(TemplateResolver templateResolver) {
+ _NullArgumentException.check("templateResolver", templateResolver);
+ this.templateResolver = templateResolver;
+ }
+
+ /**
+ * Fluent API equivalent of {@link #setTemplateResolver(TemplateResolver)}
+ */
+ public SelfT templateResolver(TemplateResolver templateResolver) {
+ setTemplateResolver(templateResolver);
+ return self();
+ }
+
+ /**
+ * Resets this setting to its initial state, as if it was never set.
+ */
+ public void unsetTemplateResolver() {
+ templateResolver = null;
+ }
+
+ @Override
public TemplateLoader getTemplateLoader() {
- return isTemplateLoaderSet() ? templateLoader : getDefaultTemplateLoader();
+ return isTemplateLoaderSet() ? templateLoader : getDefaultTemplateLoaderTRAware();
}
@Override
@@ -2033,12 +2140,21 @@ public final class Configuration
return templateLoaderSet;
}
+ private TemplateLoader getDefaultTemplateLoaderTRAware() {
+ return isTemplateResolverSet() && !getTemplateResolver().supportsTemplateLoaderSetting() ?
+ null : getDefaultTemplateLoader();
+ }
+
+ /**
+ * The default value when the {@link #getTemplateResolver() templateResolver} supports this setting (otherwise
+ * the default is hardwired to be {@code null} and this method isn't called).
+ */
protected TemplateLoader getDefaultTemplateLoader() {
return null;
}
/**
- * Setter pair of {@link Configuration#getTemplateLoader()}.
+ * Setter pair of {@link Configuration#getTemplateLoader()}. Note that {@code null} is a valid value.
*/
public void setTemplateLoader(TemplateLoader templateLoader) {
this.templateLoader = templateLoader;
@@ -2063,14 +2179,23 @@ public final class Configuration
@Override
public CacheStorage getCacheStorage() {
- return isCacheStorageSet() ? cacheStorage : getDefaultCacheStorage();
+ return isCacheStorageSet() ? cacheStorage : getDefaultCacheStorageTRAware();
}
@Override
public boolean isCacheStorageSet() {
- return cacheStorage != null;
+ return cacheStorageSet;
}
+ private CacheStorage getDefaultCacheStorageTRAware() {
+ return isTemplateResolverSet() && !getTemplateResolver().supportsCacheStorageSetting() ? null
+ : getDefaultCacheStorage();
+ }
+
+ /**
+ * The default value when the {@link #getTemplateResolver() templateResolver} supports this setting (otherwise
+ * the default is hardwired to be {@code null} and this method isn't called).
+ */
protected CacheStorage getDefaultCacheStorage() {
if (cachedDefaultCacheStorage == null) {
// If this will depend on incompatibleImprovements, null it out in onIncompatibleImprovementsChanged()!
@@ -2084,6 +2209,7 @@ public final class Configuration
*/
public void setCacheStorage(CacheStorage cacheStorage) {
this.cacheStorage = cacheStorage;
+ this.cacheStorageSet = true;
cachedDefaultCacheStorage = null;
}
@@ -2100,19 +2226,29 @@ public final class Configuration
*/
public void unsetCacheStorage() {
cacheStorage = null;
+ cacheStorageSet = false;
}
@Override
public TemplateLookupStrategy getTemplateLookupStrategy() {
- return isTemplateLookupStrategySet() ? templateLookupStrategy : getDefaultTemplateLookupStrategySet();
+ return isTemplateLookupStrategySet() ? templateLookupStrategy : getDefaultTemplateLookupStrategyTRAware();
}
@Override
public boolean isTemplateLookupStrategySet() {
- return templateLookupStrategy != null;
+ return templateLookupStrategySet;
+ }
+
+ private TemplateLookupStrategy getDefaultTemplateLookupStrategyTRAware() {
+ return isTemplateResolverSet() && !getTemplateResolver().supportsTemplateLookupStrategySetting() ? null :
+ getDefaultTemplateLookupStrategy();
}
- protected TemplateLookupStrategy getDefaultTemplateLookupStrategySet() {
+ /**
+ * The default value when the {@link #getTemplateResolver() templateResolver} supports this setting (otherwise
+ * the default is hardwired to be {@code null} and this method isn't called).
+ */
+ protected TemplateLookupStrategy getDefaultTemplateLookupStrategy() {
return DefaultTemplateLookupStrategy.INSTANCE;
}
@@ -2120,8 +2256,8 @@ public final class Configuration
* Setter pair of {@link Configuration#getTemplateLookupStrategy()}.
*/
public void setTemplateLookupStrategy(TemplateLookupStrategy templateLookupStrategy) {
- _NullArgumentException.check("templateLookupStrategy", templateLookupStrategy);
this.templateLookupStrategy = templateLookupStrategy;
+ templateLookupStrategySet = true;
}
/**
@@ -2137,11 +2273,12 @@ public final class Configuration
*/
public void unsetTemplateLookupStrategy() {
templateLookupStrategy = null;
+ templateLookupStrategySet = false;
}
@Override
public TemplateNameFormat getTemplateNameFormat() {
- return isTemplateNameFormatSet() ? templateNameFormat : getDefaultTemplateNameFormat();
+ return isTemplateNameFormatSet() ? templateNameFormat : getDefaultTemplateNameFormatTRAware();
}
/**
@@ -2149,9 +2286,18 @@ public final class Configuration
*/
@Override
public boolean isTemplateNameFormatSet() {
- return templateNameFormat != null;
+ return templateNameFormatSet;
+ }
+
+ private TemplateNameFormat getDefaultTemplateNameFormatTRAware() {
+ return isTemplateResolverSet() && !getTemplateResolver().supportsTemplateNameFormatSetting() ? null
+ : getDefaultTemplateNameFormat();
}
+ /**
+ * The default value when the {@link #getTemplateResolver() templateResolver} supports this setting (otherwise
+ * the default is hardwired to be {@code null} and this method isn't called).
+ */
protected TemplateNameFormat getDefaultTemplateNameFormat() {
return DefaultTemplateNameFormatFM2.INSTANCE;
}
@@ -2160,8 +2306,8 @@ public final class Configuration
* Setter pair of {@link Configuration#getTemplateNameFormat()}.
*/
public void setTemplateNameFormat(TemplateNameFormat templateNameFormat) {
- _NullArgumentException.check("templateNameFormat", templateNameFormat);
this.templateNameFormat = templateNameFormat;
+ templateNameFormatSet = true;
}
/**
@@ -2177,11 +2323,12 @@ public final class Configuration
*/
public void unsetTemplateNameFormat() {
this.templateNameFormat = null;
+ templateNameFormatSet = false;
}
@Override
public TemplateConfigurationFactory getTemplateConfigurations() {
- return isTemplateConfigurationsSet() ? templateConfigurations : getDefaultTemplateConfigurations();
+ return isTemplateConfigurationsSet() ? templateConfigurations : getDefaultTemplateConfigurationsTRAware();
}
@Override
@@ -2189,6 +2336,15 @@ public final class Configuration
return templateConfigurationsSet;
}
+ private TemplateConfigurationFactory getDefaultTemplateConfigurationsTRAware() {
+ return isTemplateResolverSet() && !getTemplateResolver().supportsTemplateConfigurationsSetting() ? null
+ : getDefaultTemplateConfigurations();
+ }
+
+ /**
+ * The default value when the {@link #getTemplateResolver() templateResolver} supports this setting (otherwise
+ * the default is hardwired to be {@code null} and this method isn't called).
+ */
protected TemplateConfigurationFactory getDefaultTemplateConfigurations() {
return null;
}
@@ -2218,31 +2374,41 @@ public final class Configuration
}
@Override
- public long getTemplateUpdateDelayMilliseconds() {
+ public Long getTemplateUpdateDelayMilliseconds() {
return isTemplateUpdateDelayMillisecondsSet() ? templateUpdateDelayMilliseconds
- : getDefaultTemplateUpdateDelayMilliseconds();
+ : getDefaultTemplateUpdateDelayMillisecondsTRAware();
}
@Override
public boolean isTemplateUpdateDelayMillisecondsSet() {
- return templateUpdateDelayMilliseconds != null;
+ return templateUpdateDelayMillisecondsSet;
+ }
+
+ private Long getDefaultTemplateUpdateDelayMillisecondsTRAware() {
+ return isTemplateResolverSet() && !getTemplateResolver().supportsTemplateUpdateDelayMillisecondsSetting()
+ ? null : getDefaultTemplateUpdateDelayMilliseconds();
}
- protected long getDefaultTemplateUpdateDelayMilliseconds() {
- return 5000;
+ /**
+ * The default value when the {@link #getTemplateResolver() templateResolver} supports this setting (otherwise
+ * the default is hardwired to be {@code null} and this method isn't called).
+ */
+ protected Long getDefaultTemplateUpdateDelayMilliseconds() {
+ return 5000L;
}
/**
* Setter pair of {@link Configuration#getTemplateUpdateDelayMilliseconds()}.
*/
- public void setTemplateUpdateDelayMilliseconds(long templateUpdateDelayMilliseconds) {
+ public void setTemplateUpdateDelayMilliseconds(Long templateUpdateDelayMilliseconds) {
this.templateUpdateDelayMilliseconds = templateUpdateDelayMilliseconds;
+ templateUpdateDelayMillisecondsSet = true;
}
/**
- * Fluent API equivalent of {@link #setTemplateUpdateDelayMilliseconds(long)}
+ * Fluent API equivalent of {@link #setTemplateUpdateDelayMilliseconds(Long)}
*/
- public SelfT templateUpdateDelayMilliseconds(long templateUpdateDelayMilliseconds) {
+ public SelfT templateUpdateDelayMilliseconds(Long templateUpdateDelayMilliseconds) {
setTemplateUpdateDelayMilliseconds(templateUpdateDelayMilliseconds);
return self();
}
@@ -2252,19 +2418,29 @@ public final class Configuration
*/
public void unsetTemplateUpdateDelayMilliseconds() {
templateUpdateDelayMilliseconds = null;
+ templateUpdateDelayMillisecondsSet = false;
}
@Override
- public boolean getLocalizedLookup() {
- return isLocalizedLookupSet() ? localizedLookup : getDefaultLocalizedLookup();
+ public Boolean getLocalizedLookup() {
+ return isLocalizedLookupSet() ? localizedLookup : getDefaultLocalizedLookupTRAware();
}
@Override
public boolean isLocalizedLookupSet() {
- return localizedLookup != null;
+ return localizedLookupSet;
+ }
+
+ private Boolean getDefaultLocalizedLookupTRAware() {
+ return isTemplateResolverSet() && !getTemplateResolver().supportsLocalizedLookupSetting() ? null
+ : getDefaultLocalizedLookup();
}
- protected boolean getDefaultLocalizedLookup() {
+ /**
+ * The default value when the {@link #getTemplateResolver() templateResolver} supports this setting (otherwise
+ * the default is hardwired to be {@code null} and this method isn't called).
+ */
+ protected Boolean getDefaultLocalizedLookup() {
return true;
}
@@ -2273,6 +2449,7 @@ public final class Configuration
*/
public void setLocalizedLookup(Boolean localizedLookup) {
this.localizedLookup = localizedLookup;
+ localizedLookupSet = true;
}
/**
@@ -2288,6 +2465,7 @@ public final class Configuration
*/
public void unsetLocalizedLookup() {
this.localizedLookup = null;
+ localizedLookupSet = false;
}
public Collection<OutputFormat> getRegisteredCustomOutputFormats() {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/ConfigurationSettingValueException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ConfigurationSettingValueException.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ConfigurationSettingValueException.java
index 3ed6512..193ec96 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ConfigurationSettingValueException.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ConfigurationSettingValueException.java
@@ -57,7 +57,7 @@ public class ConfigurationSettingValueException extends ConfigurationException {
Throwable cause) {
super(
createMessage(
- name, value, true,
+ name, value, showValue,
reason != null ? ", because: " : (cause != null ? "; see cause exception." : null),
reason),
cause);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
index b3c4150..316bd00 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
@@ -61,9 +61,7 @@ import org.apache.freemarker.core.model.TemplateTransformModel;
import org.apache.freemarker.core.model.TransformControl;
import org.apache.freemarker.core.model.impl.SimpleHash;
import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
-import org.apache.freemarker.core.templateresolver.TemplateNameFormat;
import org.apache.freemarker.core.templateresolver.TemplateResolver;
-import org.apache.freemarker.core.templateresolver._CacheAPI;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2;
import org.apache.freemarker.core.util.UndeclaredThrowableException;
@@ -2778,8 +2776,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
// We can't cause a template lookup here (see TemplateLookupStrategy), as that can be expensive. We exploit
// that (at least in 2.3.x) the name used for eager import namespace key isn't the template.sourceName, but
// the looked up name (template.name), which we can get quickly:
- TemplateNameFormat tnf = getConfiguration().getTemplateNameFormat();
- templateName = _CacheAPI.normalizeRootBasedName(tnf, templateName);
+ templateName = getConfiguration().getTemplateResolver().normalizeRootBasedName(templateName);
}
if (loadedLibs == null) {
@@ -2857,19 +2854,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
if (baseName == null) {
return targetName;
}
- return _CacheAPI.toRootBasedName(configuration.getTemplateNameFormat(), baseName, targetName);
- }
-
- String renderElementToString(ASTElement te) throws IOException, TemplateException {
- Writer prevOut = out;
- try {
- StringWriter sw = new StringWriter();
- out = sw;
- visit(te);
- return sw.toString();
- } finally {
- out = prevOut;
- }
+ return configuration.getTemplateResolver().toRootBasedName(baseName, targetName);
}
void importMacros(Template template) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java
index 60a99ab..18e17f6 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java
@@ -195,9 +195,8 @@ public interface ParsingConfiguration {
/**
* Tells if the "file" extension part of the source name ({@link Template#getSourceName()}) will influence certain
- * parsing settings. For backward compatibility, it defaults to {@code false} if
- * {@link #getIncompatibleImprovements()} is less than 2.3.24. Starting from {@code incompatibleImprovements}
- * 2.3.24, it defaults to {@code true}, so the following standard file extensions take their effect:
+ * parsing settings. Defaults to {@code true}. When {@code true}, the following standard file extensions take
+ * their effect:
*
* <ul>
* <li>{@code ftlh}: Sets the {@link #getOutputFormat() outputFormat} setting to {@code "HTML"}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/SettingValueNotSetException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/SettingValueNotSetException.java b/freemarker-core/src/main/java/org/apache/freemarker/core/SettingValueNotSetException.java
index 766669e..dc136e8 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/SettingValueNotSetException.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/SettingValueNotSetException.java
@@ -25,10 +25,6 @@ package org.apache.freemarker.core;
*/
public abstract class SettingValueNotSetException extends RuntimeException {
- public SettingValueNotSetException(String message) {
- super(message);
- }
-
public SettingValueNotSetException(String message, Throwable cause) {
super(message, cause);
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateResolverDependenciesImpl.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateResolverDependenciesImpl.java b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateResolverDependenciesImpl.java
new file mode 100644
index 0000000..10b219f
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateResolverDependenciesImpl.java
@@ -0,0 +1,120 @@
+/*
+ * 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 static org.apache.freemarker.core.Configuration.ExtendableBuilder.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.charset.Charset;
+
+import org.apache.freemarker.core.templateresolver.CacheStorage;
+import org.apache.freemarker.core.templateresolver.TemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.TemplateLoader;
+import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
+import org.apache.freemarker.core.templateresolver.TemplateNameFormat;
+import org.apache.freemarker.core.templateresolver.TemplateResolver;
+import org.apache.freemarker.core.templateresolver.TemplateResolverDependencies;
+import org.apache.freemarker.core.util._NullArgumentException;
+
+/**
+ * Used internally by {@link Configuration}.
+ */
+class TemplateResolverDependenciesImpl extends TemplateResolverDependencies {
+
+ private final TemplateResolver templateResolver;
+ private final Configuration configuration;
+
+ public TemplateResolverDependenciesImpl(Configuration configuration, TemplateResolver templateResolver) {
+ _NullArgumentException.check("configuration", configuration);
+ _NullArgumentException.check("templateResolver", templateResolver);
+ this.templateResolver = templateResolver;
+ this.configuration = configuration;
+ }
+
+ @Override
+ public TemplateLoader getTemplateLoader() {
+ checkSettingSupported(TEMPLATE_LOADER_KEY, templateResolver.supportsTemplateLoaderSetting());
+ return configuration.getTemplateLoader();
+ }
+
+ @Override
+ public CacheStorage getCacheStorage() {
+ checkSettingSupported(CACHE_STORAGE_KEY, templateResolver.supportsCacheStorageSetting());
+ return configuration.getCacheStorage();
+ }
+
+ @Override
+ public TemplateLookupStrategy getTemplateLookupStrategy() {
+ checkSettingSupported(TEMPLATE_LOOKUP_STRATEGY_KEY, templateResolver.supportsTemplateLookupStrategySetting());
+ return configuration.getTemplateLookupStrategy();
+ }
+
+ @Override
+ public TemplateNameFormat getTemplateNameFormat() {
+ checkSettingSupported(TEMPLATE_NAME_FORMAT_KEY, templateResolver.supportsTemplateNameFormatSetting());
+ return configuration.getTemplateNameFormat();
+ }
+
+ @Override
+ public TemplateConfigurationFactory getTemplateConfigurations() {
+ checkSettingSupported(TEMPLATE_CONFIGURATIONS_KEY, templateResolver.supportsTemplateConfigurationsSetting());
+ return configuration.getTemplateConfigurations();
+ }
+
+ @Override
+ public Long getTemplateUpdateDelayMilliseconds() {
+ checkSettingSupported(
+ TEMPLATE_UPDATE_DELAY_KEY, templateResolver.supportsTemplateUpdateDelayMillisecondsSetting());
+ return configuration.getTemplateUpdateDelayMilliseconds();
+ }
+
+ @Override
+ public Boolean getLocalizedLookup() {
+ checkSettingSupported(LOCALIZED_LOOKUP_KEY, templateResolver.supportsLocalizedLookupSetting());
+ return configuration.getLocalizedLookup();
+ }
+
+ @Override
+ public Charset getSourceEncoding() {
+ return configuration.getSourceEncoding();
+ }
+
+ @Override
+ public TemplateLanguage getTemplateLanguage() {
+ return configuration.getTemplateLanguage();
+ }
+
+ private void checkSettingSupported(String name, boolean supported) {
+ if (!supported) {
+ throw new IllegalStateException(templateResolver.getClass().getName() + " reported that it doesn't support "
+ + "this setting, so you aren't allowed to get it: " + name);
+ }
+ }
+
+ @Override
+ public Template parse(TemplateLanguage templateLanguage, String name, String sourceName, Reader reader,
+ TemplateConfiguration templateConfiguration, Charset encoding, InputStream streamToUnmarkWhenEncEstabd)
+ throws IOException, ParseException {
+ return templateLanguage.parse(name, sourceName, reader,
+ configuration, templateConfiguration, encoding, streamToUnmarkWhenEncEstabd);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java
index 5ad4490..18e705b 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java
@@ -27,10 +27,11 @@ import org.apache.freemarker.core.templateresolver.TemplateConfigurationFactory;
import org.apache.freemarker.core.templateresolver.TemplateLoader;
import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
import org.apache.freemarker.core.templateresolver.TemplateNameFormat;
+import org.apache.freemarker.core.templateresolver.TemplateResolver;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2;
-import org.apache.freemarker.core.templateresolver.impl.FileTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver;
import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader;
import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage;
@@ -43,16 +44,24 @@ import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage;
public interface TopLevelConfiguration extends ParsingAndProcessingConfiguration {
/**
- * The {@link TemplateLoader} that is used to look up and load templates.
+ * The {@link TemplateResolver} to use; defaults to a {@link DefaultTemplateResolver}.
+ */
+ TemplateResolver getTemplateResolver();
+
+ /**
+ * Tells if this setting was explicitly set (otherwise its value will be the default value).
+ */
+ boolean isTemplateResolverSet();
+
+ /**
+ * The {@link TemplateLoader} that is used to look up and load templates; defaults to {@code null}.
* By providing your own {@link TemplateLoader} implementation, you can load templates from whatever kind of
* storages, like from relational databases, NoSQL-storages, etc.
*
* <p>You can chain several {@link TemplateLoader}-s together with {@link MultiTemplateLoader}.
*
- * <p>Default value: You should always set the template loader instead of relying on the default value.
- * (But if you still care what it is, before "incompatible improvements" 2.3.21 it's a {@link FileTemplateLoader}
- * that uses the current directory as its root; as it's hard tell what that directory will be, it's not very useful
- * and dangerous. Starting with "incompatible improvements" 2.3.21 the default is {@code null}.)
+ * <p>If the {@link #getTemplateResolver() templateResolver} doesn't support this setting, then it must be {@code
+ * null}. This check is postponed until the {@link Configuration} instance is created.
*/
TemplateLoader getTemplateLoader();
@@ -63,7 +72,11 @@ public interface TopLevelConfiguration extends ParsingAndProcessingConfiguration
/**
* The {@link TemplateLookupStrategy} that is used to look up templates based on the requested name, locale and
- * custom lookup condition. Its default is {@link DefaultTemplateLookupStrategy#INSTANCE}.
+ * custom lookup condition. Its default is {@link DefaultTemplateLookupStrategy#INSTANCE}, except when the
+ * {@link #getTemplateResolver() templateResolver} doesn't support this setting, in which case it's {@code null}.
+ *
+ * <p>If the {@link #getTemplateResolver() templateResolver} doesn't support this setting, then it must be {@code
+ * null}. This check is postponed until the {@link Configuration} instance is created.
*/
TemplateLookupStrategy getTemplateLookupStrategy();
@@ -74,8 +87,12 @@ public interface TopLevelConfiguration extends ParsingAndProcessingConfiguration
/**
* The template name format used; see {@link TemplateNameFormat}. The default is
- * {@link DefaultTemplateNameFormatFM2#INSTANCE}, while the recommended value for new projects is
- * {@link DefaultTemplateNameFormat#INSTANCE}.
+ * {@link DefaultTemplateNameFormatFM2#INSTANCE} (while the recommended value for new projects is
+ * {@link DefaultTemplateNameFormat#INSTANCE}), except when the {@link #getTemplateResolver() templateResolver}
+ * doesn't support this setting, in which case it's {@code null}.
+ *
+ * <p>If the {@link #getTemplateResolver() templateResolver} doesn't support this setting, then it must be {@code
+ * null}. This check is postponed until the {@link Configuration} instance is created.
*/
TemplateNameFormat getTemplateNameFormat();
@@ -86,14 +103,17 @@ public interface TopLevelConfiguration extends ParsingAndProcessingConfiguration
/**
* The {@link TemplateConfigurationFactory} that will configure individual templates where their settings differ
- * from those coming from the common {@link Configuration} object. A typical use case for that is specifying the
- * {@link #getOutputFormat() outputFormat} or {@link #getSourceEncoding() sourceEncoding} for templates based on
- * their file extension or parent directory.
+ * from those coming from the common {@link Configuration} object. Defaults to {@code null}.
+ * A typical use case for that is specifying the {@link #getOutputFormat() outputFormat} or
+ * {@link #getSourceEncoding() sourceEncoding} for templates based on their file extension or parent directory.
* <p>
* Note that the settings suggested by standard file extensions are stronger than that you set here. See
* {@link #getRecognizeStandardFileExtensions()} for more information about standard file extensions.
* <p>
* See "Template configurations" in the FreeMarker Manual for examples.
+ *
+ * <p>If the {@link #getTemplateResolver() templateResolver} doesn't support this setting, then it must be {@code
+ * null}. This check is postponed until the {@link Configuration} instance is created.
*/
TemplateConfigurationFactory getTemplateConfigurations();
@@ -103,8 +123,12 @@ public interface TopLevelConfiguration extends ParsingAndProcessingConfiguration
boolean isTemplateConfigurationsSet();
/**
- * The map-like object used for caching templates to avoid repeated loading and parsing of the template "files".
- * Its {@link Configuration}-level default is a {@link SoftCacheStorage}.
+ * The map-like object used for caching templates to avoid repeated loading and parsing of the template "files" to
+ * {@link Template} objects. The default is a {@link SoftCacheStorage}, except when the
+ * {@link #getTemplateResolver() templateResolver} doesn't support this setting, in which case it's {@code null}.
+ *
+ * <p>If the {@link #getTemplateResolver() templateResolver} doesn't support this setting, then it must be {@code
+ * null}. This check is postponed until the {@link Configuration} instance is created.
*/
CacheStorage getCacheStorage();
@@ -115,9 +139,13 @@ public interface TopLevelConfiguration extends ParsingAndProcessingConfiguration
/**
* The time in milliseconds that must elapse before checking whether there is a newer version of a template
- * "file" than the cached one. Defaults to 5000 ms.
+ * "file" than the cached one. The defaults is 5000 ms, except when the
+ * {@link #getTemplateResolver() templateResolver} doesn't support this setting, in which case it's {@code null}.
+ *
+ * <p>If the {@link #getTemplateResolver() templateResolver} doesn't support this setting, then it must be {@code
+ * null}. This check is postponed until the {@link Configuration} instance is created.
*/
- long getTemplateUpdateDelayMilliseconds();
+ Long getTemplateUpdateDelayMilliseconds();
/**
* Tells if this setting was explicitly set (otherwise its value will be the default value).
@@ -158,8 +186,8 @@ public interface TopLevelConfiguration extends ParsingAndProcessingConfiguration
Version getIncompatibleImprovements();
/**
- * Whether localized template lookup is enabled. Enabled by default.
- *
+ * Whether localized template lookup is enabled . The default is {@code true}, except when the
+ * {@link #getTemplateResolver() templateResolver} doesn't support this setting, in which case it's {@code null}.
* <p>
* With the default {@link TemplateLookupStrategy}, localized lookup works like this: Let's say your locale setting
* is {@code Locale("en", "AU")}, and you call {@link Configuration#getTemplate(String) cfg.getTemplate("foo.ftl")}.
@@ -168,8 +196,11 @@ public interface TopLevelConfiguration extends ParsingAndProcessingConfiguration
* {@link #getTemplateLookupStrategy()} for a more details. If you need to generate different
* template names, set your own a {@link TemplateLookupStrategy} implementation as the value of the
* {@link #getTemplateLookupStrategy() templateLookupStrategy} setting.
+ * <p>
+ * If the {@link #getTemplateResolver() templateResolver} doesn't support this setting, then it must be {@code
+ * null}. This check is postponed until the {@link Configuration} instance is created.
*/
- boolean getLocalizedLookup();
+ Boolean getLocalizedLookup();
/**
* Tells if this setting was explicitly set (otherwise its value will be the default value).
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactory.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactory.java
index e61bb23..b78f49b 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactory.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactory.java
@@ -22,6 +22,7 @@ import java.io.IOException;
import org.apache.freemarker.core.Template;
import org.apache.freemarker.core.TemplateConfiguration;
+import org.apache.freemarker.core.TopLevelConfiguration;
/**
* Creates (or returns) {@link TemplateConfiguration}-s for template sources.
@@ -35,7 +36,10 @@ public abstract class TemplateConfigurationFactory {
* The name (path) that was used for {@link TemplateLoader#load}. See
* {@link Template#getSourceName()} for details.
* @param templateLoadingSource
- * The object returned by {@link TemplateLoadingResult#getSource()}.
+ * The object returned by {@link TemplateLoadingResult#getSource()}. For a
+ * {@link TopLevelConfiguration#getTemplateResolver()} that doesn't use {@link TemplateLoader}-s
+ * this is maybe {@code null}, or some other object wrapped into {@link TemplateLoadingSource} to
+ * satisfy this contract.
*
* @return The {@link TemplateConfiguration} to apply, or {@code null} if the there's no {@link TemplateConfiguration} for
* this template source.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateLoadingSource.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateLoadingSource.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateLoadingSource.java
index bfe47e4..5cb5e34 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateLoadingSource.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateLoadingSource.java
@@ -44,7 +44,7 @@ import org.apache.freemarker.core.templateresolver.impl.FileTemplateLoader;
*
* <li>{@link Object#equals(Object)} must still work properly if there are multiple instances of the same
* {@link TemplateLoader} implementation. Like if you have an implementation that loads from a database table, the
- * {@link TemplateLoadingSource} should certain contain the JDBC connection string, the table name and the row ID, not
+ * {@link TemplateLoadingSource} should certainly contain the JDBC connection string, the table name and the row ID, not
* just the row ID.
*
* <li>Together with {@link Object#equals(Object)}, {@link Object#hashCode()} must be also overridden. The template
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateResolver.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateResolver.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateResolver.java
index c2c5c61..de70101 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateResolver.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateResolver.java
@@ -23,45 +23,93 @@ import java.io.Serializable;
import java.util.Locale;
import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.ConfigurationException;
import org.apache.freemarker.core.ParseException;
import org.apache.freemarker.core.Template;
import org.apache.freemarker.core.TemplateNotFoundException;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver;
+import org.apache.freemarker.core.util._NullArgumentException;
/**
- * This class was introduced to allow users to fully implement the template lookup, loading and caching logic,
- * in case the standard mechanism ({@link DefaultTemplateResolver}) is not flexible enough. By implementing this class,
- * you can take over the duty of the following {@link Configuration} settings, and it's up to the implementation if you
- * delegate some of those duties back to the {@link Configuration} setting:
- *
- * <ul>
- * <li>{@link Configuration#getTemplateLoader() templateLoader}
- * <li>{@link Configuration#getTemplateNameFormat() templateNameFormat}
- * <li>{@link Configuration#getTemplateLookupStrategy() templateLookupStrategy}
- * <li>{@link Configuration#getCacheStorage() cacheStorage}
- * </ul>
+ * This class allows user to fully implement the template lookup, loading and caching logic,
+ * in case the standard mechanism (a {@link DefaultTemplateResolver} combined with all the {@link Configuration}
+ * settings like {@link Configuration#getTemplateLoader() templateLoader},
+ * {@link Configuration#getTemplateConfigurations() templateConfigurations}, etc.) is not flexible enough.
+ * <p>
+ * A custom {@link TemplateResolver} can depend on a selected set of {@link Configuration} settings; the same ones that
+ * {@link DefaultTemplateResolver} depends on. These settings are collected into the
+ * {@link TemplateResolverDependencies} class, and the {@link TemplateResolver} should get them in {@link #initialize()}
+ * via {@link #getDependencies()}. It's possible that the custom {@link TemplateResolver} only uses some of these
+ * settings, which should be reflected by the return value of the {@code supportsXxxDependency} methods (like
+ * {@link #supportsTemplateLoaderSetting()}). (Note that there's no {@code supportsXxxDependency} method for
+ * {@link Configuration#getTemplateLanguage() templateLanguage} and {@link Configuration#getSourceEncoding()
+ * sourceEncoding} and these settings are always exposed.) {@link TemplateResolverDependencies} will also expose the
+ * {@link TemplateResolverDependencies#parse} method, which is used to create a {@link Template} from its source code.
*/
-//TODO DRAFT only [FM3]
public abstract class TemplateResolver {
- private final Configuration configuration;
+ private TemplateResolverDependencies dependencies;
+ private boolean initialized;
- protected TemplateResolver(Configuration configuration) {
- this.configuration = configuration;
+ /**
+ * Called by FreeMarker when the {@link Configuration} is built; normally you do not call it yourself.
+ * This automatically calls {@link #initialize()}.
+ *
+ * @throws IllegalStateException If this method was already called with another {@link Configuration} instance.
+ */
+ public final void setDependencies(TemplateResolverDependencies dependencies) {
+ _NullArgumentException.check("dependencies", dependencies);
+ synchronized (this) {
+ // Note that this doesn't make the TemplateResolver safely published (as par Java Memory Model). It only
+ // guarantees that the configuration won't be changed once it was set.
+ if (this.dependencies != null) {
+ if (this.dependencies == dependencies) {
+ return;
+ }
+ throw new IllegalStateException(
+ "This TemplateResolver is already bound to another Configuration instance.");
+ }
+ this.dependencies = dependencies;
+
+ initialize();
+
+ initialized = true;
+ } // sync.
}
- public Configuration getConfiguration() {
- return configuration;
+ /**
+ * Returns {@code null} before {@link #initialize()}
+ */
+ protected TemplateResolverDependencies getDependencies() {
+ return dependencies;
+ }
+
+ /**
+ * You meant to initialize the instance here instead of in the constructor. This is called only once (by
+ * FreeMarker at least), when the {@link #setDependencies(TemplateResolverDependencies)} dependencies} is called.
+ */
+ protected abstract void initialize() throws ConfigurationException;
+
+ /**
+ * Checks if the {@link TemplateResolver} was fully initialized.
+ * It's a good practice to call this at the beginning of most method.
+ */
+ protected void checkInitialized() {
+ if (!initialized) {
+ throw new IllegalStateException(
+ "TemplateResolver wasn't properly initialized; ensure that initialize() was called and did not "
+ + "throw an exception.");
+ }
}
/**
* Retrieves the parsed template with the given name (and according the specified further parameters), or returns a
* result that indicates that no such template exists. The result should come from a cache most of the time
* (avoiding I/O and template parsing), as this method is typically called frequently.
- *
* <p>
* All parameters must be non-{@code null}, except {@code customLookupCondition}. For the meaning of the parameters
- * see {@link Configuration#getTemplate(String, Locale, Serializable, boolean)}.
+ * see {@link Configuration#getTemplate(String, Locale, Serializable, boolean)}. Note that {@code name} parameter
+ * is not normalized; you are supposed to call {@link #normalizeRootBasedName(String)} internally.
*
* @return A {@link GetTemplateResult} object that contains the {@link Template}, or a
* {@link GetTemplateResult} object that contains {@code null} as the {@link Template} and information
@@ -80,18 +128,15 @@ public abstract class TemplateResolver {
* should never be a {@link TemplateNotFoundException}, as that condition is indicated in the return
* value.
*/
- // [FM3] This parameters will be removed: String encoding
public abstract GetTemplateResult getTemplate(String name, Locale locale, Serializable customLookupCondition)
throws MalformedTemplateNameException, ParseException, IOException;
/**
* Clears the cache of templates, to enforce re-loading templates when they are get next time; this is an optional
* operation.
- *
* <p>
* Note that if the {@link TemplateResolver} implementation uses {@link TemplateLoader}-s, it should also call
* {@link TemplateLoader#resetState()} on them.
- *
* <p>
* This method is thread-safe and can be called while the engine processes templates.
*
@@ -104,10 +149,8 @@ public abstract class TemplateResolver {
* Removes a template from the template cache, hence forcing the re-loading of it when it's next time requested;
* this is an optional operation. This is to give the application finer control over cache updating than the
* {@link Configuration#getTemplateUpdateDelayMilliseconds() templateUpdateDelayMilliseconds} setting alone gives.
- *
* <p>
* For the meaning of the parameters, see {@link #getTemplate(String, Locale, Serializable)}
- *
* <p>
* This method is thread-safe and can be called while the engine processes templates.
*
@@ -121,10 +164,9 @@ public abstract class TemplateResolver {
* Converts a name to a template root directory based name, so that it can be used to find a template without
* knowing what (like which template) has referred to it. The rules depend on the name format, but a typical example
* is converting "t.ftl" with base "sub/contex.ftl" to "sub/t.ftl".
- *
* <p>
- * Some implementations, notably {@link DefaultTemplateResolver}, delegates this check to the
- * {@link TemplateNameFormat} coming from the {@link Configuration}.
+ * Some implementations, notably {@link DefaultTemplateResolver}, delegate this task to a
+ * {@link TemplateNameFormat}.
*
* @param baseName
* Maybe a file name, maybe a directory name. The meaning of file name VS directory name depends on the
@@ -147,12 +189,11 @@ public abstract class TemplateResolver {
* Normalizes a template root directory based name (relative to the root or absolute), so that equivalent names
* become equivalent according {@link String#equals(Object)} too. The rules depend on the name format, but typical
* examples are "sub/../t.ftl" to "t.ftl", "sub/./t.ftl" to "sub/t.ftl" and "/t.ftl" to "t.ftl".
- *
* <p>
- * Some implementations, notably {@link DefaultTemplateResolver}, delegates this check to the {@link TemplateNameFormat}
- * coming from the {@link Configuration}. The standard {@link TemplateNameFormat} implementations shipped with
- * FreeMarker always returns a root relative path (except if the name starts with an URI schema, in which case a
- * full URI is returned), for example, "/foo.ftl" becomes to "foo.ftl".
+ * Some implementations, notably {@link DefaultTemplateResolver}, delegates this check to a
+ * {@link TemplateNameFormat}. The standard {@link TemplateNameFormat} implementations shipped with FreeMarker
+ * always return a root relative path (except if the name starts with an URI schema, in which case a full URI is
+ * returned), for example, "/foo.ftl" becomes to "foo.ftl".
*
* @param name
* The root based name. Not {@code null}.
@@ -161,4 +202,53 @@ public abstract class TemplateResolver {
*/
public abstract String normalizeRootBasedName(String name) throws MalformedTemplateNameException;
+ /**
+ * Tells whether the {@link TemplateResolver} implementation depends on the
+ * {@link Configuration#getTemplateLoader() templateLoader} {@link Configuration}. If it returns {@code false}
+ * then this {@link TemplateResolver} must not call {@link TemplateResolverDependencies#getTemplateLoader()}, or
+ * else that will throw {@link IllegalStateException}. Furthermore if the user sets the {@code templateLoader} in
+ * the {@link Configuration} to non-{@code null} value (the default is {@code null}), then the
+ * {@link Configuration} constructor will throw an exception to tell the user that the {@code templateLoader}
+ * setting is not supported by this {@link TemplateResolver} class. Some may feel tempted to return {@code true}
+ * to avoid such error, but consider that as the user has explicitly set this setting, they certainly expect it
+ * have an effect, and will be frustrated when its ignored.
+ */
+ public abstract boolean supportsTemplateLoaderSetting();
+
+ /**
+ * Works like {@link #supportsTemplateLoaderSetting()}, but for the
+ * {@link Configuration#getCacheStorage() cacheStorage} setting.
+ */
+ public abstract boolean supportsCacheStorageSetting();
+
+ /**
+ * Works like {@link #supportsTemplateLoaderSetting()}, but for the
+ * {@link Configuration#getTemplateLookupStrategy() templateLookupStrategy} setting.
+ */
+ public abstract boolean supportsTemplateLookupStrategySetting();
+
+ /**
+ * Works like {@link #supportsTemplateLoaderSetting()}, but for the
+ * {@link Configuration#getTemplateNameFormat() templateNameFormat} setting.
+ */
+ public abstract boolean supportsTemplateNameFormatSetting();
+
+ /**
+ * Works like {@link #supportsTemplateLoaderSetting()}, but for the
+ * {@link Configuration#getTemplateConfigurations() templateConfigurations} setting.
+ */
+ public abstract boolean supportsTemplateConfigurationsSetting();
+
+ /**
+ * Works like {@link #supportsTemplateUpdateDelayMillisecondsSetting()}, but for the
+ * {@link Configuration#getTemplateUpdateDelayMilliseconds() templateUpdateDelayMilliseconds} setting.
+ */
+ public abstract boolean supportsTemplateUpdateDelayMillisecondsSetting();
+
+ /**
+ * Works like {@link #supportsTemplateLoaderSetting()}, but for the
+ * {@link Configuration#getLocalizedLookup() localizedLookup} setting.
+ */
+ public abstract boolean supportsLocalizedLookupSetting();
+
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateResolverDependencies.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateResolverDependencies.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateResolverDependencies.java
new file mode 100644
index 0000000..13820c3
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/TemplateResolverDependencies.java
@@ -0,0 +1,91 @@
+/*
+ * 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.templateresolver;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.charset.Charset;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.ParseException;
+import org.apache.freemarker.core.Template;
+import org.apache.freemarker.core.TemplateConfiguration;
+import org.apache.freemarker.core.TemplateLanguage;
+
+/**
+ * Stores the dependencies of a {@link TemplateResolver}. See {@link TemplateResolver} for more.
+ * This is normally implemented by FreeMarker internally.
+ */
+public abstract class TemplateResolverDependencies {
+
+ /**
+ * @throws IllegalStateException if {@link TemplateResolver#supportsTemplateLoaderSetting()} return {@code false}.
+ */
+ public abstract TemplateLoader getTemplateLoader();
+
+ /**
+ * @throws IllegalStateException if {@link TemplateResolver#supportsCacheStorageSetting()} return {@code false}.
+ */
+ public abstract CacheStorage getCacheStorage();
+
+ /**
+ * @throws IllegalStateException if {@link TemplateResolver#supportsTemplateLookupStrategySetting()} return
+ * {@code false}.
+ */
+ public abstract TemplateLookupStrategy getTemplateLookupStrategy();
+
+ /**
+ * @throws IllegalStateException if {@link TemplateResolver#supportsTemplateNameFormatSetting()} return
+ * {@code false}.
+ */
+ public abstract TemplateNameFormat getTemplateNameFormat();
+
+ /**
+ * @throws IllegalStateException if {@link TemplateResolver#supportsTemplateConfigurationsSetting()}
+ * return {@code false}.
+ */
+ public abstract TemplateConfigurationFactory getTemplateConfigurations();
+
+ /**
+ * @throws IllegalStateException if {@link TemplateResolver#supportsTemplateUpdateDelayMillisecondsSetting()}
+ * return {@code false}.
+ */
+ public abstract Long getTemplateUpdateDelayMilliseconds();
+
+ /**
+ * @throws IllegalStateException if {@link TemplateResolver#supportsLocalizedLookupSetting()} return {@code false}.
+ */
+ public abstract Boolean getLocalizedLookup();
+
+ public abstract Charset getSourceEncoding();
+
+ public abstract TemplateLanguage getTemplateLanguage();
+
+ /**
+ * This simply calls {@link TemplateLanguage#parse(String, String, Reader, Configuration, TemplateConfiguration,
+ * Charset, InputStream)} without exposing the {@link Configuration}.
+ */
+ public abstract Template parse(
+ TemplateLanguage templateLanguage, String name, String sourceName, Reader reader,
+ TemplateConfiguration templateConfiguration, Charset encoding,
+ InputStream streamToUnmarkWhenEncEstabd) throws IOException, ParseException;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/_CacheAPI.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/_CacheAPI.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/_CacheAPI.java
deleted file mode 100644
index 09b216f..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/_CacheAPI.java
+++ /dev/null
@@ -1,43 +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.templateresolver;
-
-/**
- * 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 final class _CacheAPI {
-
- private _CacheAPI() {
- // Not meant to be instantiated
- }
-
- public static String toRootBasedName(TemplateNameFormat templateNameFormat, String baseName, String targetName)
- throws MalformedTemplateNameException {
- return templateNameFormat.toRootBasedName(baseName, targetName);
- }
-
- public static String normalizeRootBasedName(TemplateNameFormat templateNameFormat, String name)
- throws MalformedTemplateNameException {
- return templateNameFormat.normalizeRootBasedName(name);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java
index 400693e..a4ac768 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java
@@ -19,6 +19,8 @@
package org.apache.freemarker.core.templateresolver.impl;
+import static org.apache.freemarker.core.Configuration.ExtendableBuilder.*;
+
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -33,6 +35,8 @@ import java.util.Locale;
import java.util.StringTokenizer;
import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.ConfigurationException;
+import org.apache.freemarker.core.ConfigurationSettingValueException;
import org.apache.freemarker.core.Template;
import org.apache.freemarker.core.TemplateConfiguration;
import org.apache.freemarker.core.TemplateLanguage;
@@ -52,6 +56,7 @@ import org.apache.freemarker.core.templateresolver.TemplateLoadingSource;
import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
import org.apache.freemarker.core.templateresolver.TemplateNameFormat;
import org.apache.freemarker.core.templateresolver.TemplateResolver;
+import org.apache.freemarker.core.templateresolver.TemplateResolverDependencies;
import org.apache.freemarker.core.util.BugException;
import org.apache.freemarker.core.util.UndeclaredThrowableException;
import org.apache.freemarker.core.util._NullArgumentException;
@@ -83,100 +88,58 @@ public class DefaultTemplateResolver extends TemplateResolver {
private static final Logger LOG = _CoreLogs.TEMPLATE_RESOLVER;
/** Maybe {@code null}. */
- private final TemplateLoader templateLoader;
+ private TemplateLoader templateLoader;
/** Here we keep our cached templates */
- private final CacheStorage cacheStorage;
- private final TemplateLookupStrategy templateLookupStrategy;
- private final TemplateNameFormat templateNameFormat;
- private final TemplateConfigurationFactory templateConfigurations;
- private final long templateUpdateDelayMilliseconds;
- private final boolean localizedLookup;
-
- private Configuration config;
-
- /**
- * @param templateLoader
- * The {@link TemplateLoader} to use. Can be {@code null}, though then every request will result in
- * {@link TemplateNotFoundException}.
- * @param cacheStorage
- * The {@link CacheStorage} to use. Can't be {@code null}.
- * @param templateLookupStrategy
- * The {@link TemplateLookupStrategy} to use. Can't be {@code null}.
- * @param templateUpdateDelayMilliseconds
- * See {@link Configuration#getTemplateUpdateDelayMilliseconds()}
- * @param templateNameFormat
- * The {@link TemplateNameFormat} to use. Can't be {@code null}.
- * @param templateConfigurations
- * The {@link TemplateConfigurationFactory} to use. Can be {@code null} (then all templates will use the
- * settings coming from the {@link Configuration} as is, except in the very rare case where a
- * {@link TemplateLoader} itself specifies a {@link TemplateConfiguration}).
- * @param config
- * The {@link Configuration} this cache will be used for. Can't be {@code null}.
- */
- public DefaultTemplateResolver(
- TemplateLoader templateLoader,
- CacheStorage cacheStorage, long templateUpdateDelayMilliseconds,
- TemplateLookupStrategy templateLookupStrategy, boolean localizedLookup,
- TemplateNameFormat templateNameFormat,
- TemplateConfigurationFactory templateConfigurations,
- Configuration config) {
- super(config);
-
- this.templateLoader = templateLoader;
-
- _NullArgumentException.check("cacheStorage", cacheStorage);
- this.cacheStorage = cacheStorage;
+ private CacheStorage cacheStorage;
+ private TemplateLookupStrategy templateLookupStrategy;
+ private TemplateNameFormat templateNameFormat;
+ private TemplateConfigurationFactory templateConfigurations;
+ private long templateUpdateDelayMilliseconds;
+ private Charset sourceEncoding;
+ private TemplateLanguage templateLanguage;
+ private boolean localizedLookup;
+
+ @Override
+ protected void initialize() throws ConfigurationException {
+ TemplateResolverDependencies deps = getDependencies();
+
+ this.templateLoader = deps.getTemplateLoader();
+ this.cacheStorage = deps.getCacheStorage();
+ checkDependencyNotNull(CACHE_STORAGE_KEY, this.cacheStorage);
+
+ Long templateUpdateDelayMilliseconds = deps.getTemplateUpdateDelayMilliseconds();
+ checkDependencyNotNull(TEMPLATE_UPDATE_DELAY_KEY, templateUpdateDelayMilliseconds);
this.templateUpdateDelayMilliseconds = templateUpdateDelayMilliseconds;
-
+
+ Boolean localizedLookup = deps.getLocalizedLookup();
+ checkDependencyNotNull(LOCALIZED_LOOKUP_KEY, localizedLookup);
this.localizedLookup = localizedLookup;
-
- _NullArgumentException.check("templateLookupStrategy", templateLookupStrategy);
- this.templateLookupStrategy = templateLookupStrategy;
- _NullArgumentException.check("templateNameFormat", templateNameFormat);
- this.templateNameFormat = templateNameFormat;
+ this.templateLookupStrategy = deps.getTemplateLookupStrategy();
+ checkDependencyNotNull(TEMPLATE_LOOKUP_STRATEGY_KEY, this.templateLookupStrategy);
+
+ this.templateNameFormat = deps.getTemplateNameFormat();
+ checkDependencyNotNull(TEMPLATE_NAME_FORMAT_KEY, this.templateNameFormat);
// Can be null
- this.templateConfigurations = templateConfigurations;
-
- _NullArgumentException.check("config", config);
- this.config = config;
- }
-
- /**
- * Returns the configuration for internal usage.
- */
- @Override
- public Configuration getConfiguration() {
- return config;
- }
+ this.templateConfigurations = deps.getTemplateConfigurations();
- public TemplateLoader getTemplateLoader() {
- return templateLoader;
- }
+ this.sourceEncoding = deps.getSourceEncoding();
+ checkDependencyNotNull(SOURCE_ENCODING_KEY, this.sourceEncoding);
- public CacheStorage getCacheStorage() {
- return cacheStorage;
+ this.templateLanguage = deps.getTemplateLanguage();
+ checkDependencyNotNull(TEMPLATE_LANGUAGE_KEY, this.templateLanguage);
}
-
- /**
- */
- public TemplateLookupStrategy getTemplateLookupStrategy() {
- return templateLookupStrategy;
- }
-
- /**
- */
- public TemplateNameFormat getTemplateNameFormat() {
- return templateNameFormat;
- }
-
- /**
- */
- public TemplateConfigurationFactory getTemplateConfigurations() {
- return templateConfigurations;
+
+ private void checkDependencyNotNull(String name, Object value) {
+ if (value == null) {
+ throw new ConfigurationSettingValueException(
+ name, null, false,
+ "This Configuration setting must be set and non-null when the TemplateResolver is a(n) "
+ + this.getClass().getName() + ".", null);
+ }
}
/**
@@ -213,6 +176,8 @@ public class DefaultTemplateResolver extends TemplateResolver {
_NullArgumentException.check("name", name);
_NullArgumentException.check("locale", locale);
+ checkInitialized();
+
name = templateNameFormat.normalizeRootBasedName(name);
if (templateLoader == null) {
@@ -233,6 +198,41 @@ public class DefaultTemplateResolver extends TemplateResolver {
return templateNameFormat.normalizeRootBasedName(name);
}
+ @Override
+ public boolean supportsTemplateLoaderSetting() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsCacheStorageSetting() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsTemplateLookupStrategySetting() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsTemplateNameFormatSetting() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsTemplateConfigurationsSetting() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsTemplateUpdateDelayMillisecondsSetting() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsLocalizedLookupSetting() {
+ return true;
+ }
+
private Template getTemplateInternal(
final String name, final Locale locale, final Serializable customLookupCondition)
throws IOException {
@@ -533,9 +533,9 @@ public class DefaultTemplateResolver extends TemplateResolver {
locale = tc.getLocale();
}
Charset initialEncoding = tc != null && tc.isSourceEncodingSet() ? tc.getSourceEncoding()
- : config.getSourceEncoding();
+ : this.sourceEncoding;
TemplateLanguage templateLanguage = tc != null && tc.isTemplateLanguageSet() ? tc.getTemplateLanguage()
- : config.getTemplateLanguage();
+ : this.templateLanguage;
Template template;
{
@@ -572,7 +572,8 @@ public class DefaultTemplateResolver extends TemplateResolver {
try {
try {
- template = templateLanguage.parse(name, sourceName, reader, config, tc,
+ template = getDependencies().parse(
+ templateLanguage, name, sourceName, reader, tc,
initialEncoding, markedInputStream);
} catch (WrongTemplateCharsetException charsetException) {
final Charset templateSpecifiedEncoding = charsetException.getTemplateSpecifiedEncoding();
@@ -590,7 +591,8 @@ public class DefaultTemplateResolver extends TemplateResolver {
+ ", but its canSpecifyCharsetInContent property is false.");
}
- template = templateLanguage.parse(name, sourceName, reader, config, tc,
+ template = getDependencies().parse(
+ templateLanguage, name, sourceName, reader, tc,
templateSpecifiedEncoding, markedInputStream);
}
} finally {
@@ -604,28 +606,6 @@ public class DefaultTemplateResolver extends TemplateResolver {
}
/**
- * Gets the delay in milliseconds between checking for newer versions of a
- * template source.
- * @return the current value of the delay
- */
- public long getTemplateUpdateDelayMilliseconds() {
- // synchronized was moved here so that we don't advertise that it's thread-safe, as it's not.
- synchronized (this) {
- return templateUpdateDelayMilliseconds;
- }
- }
-
- /**
- * Returns if localized template lookup is enabled or not.
- */
- public boolean getLocalizedLookup() {
- // synchronized was moved here so that we don't advertise that it's thread-safe, as it's not.
- synchronized (this) {
- return localizedLookup;
- }
- }
-
- /**
* Removes all entries from the cache, forcing reloading of templates on subsequent
* {@link #getTemplate(String, Locale, Serializable)} calls.
*
@@ -654,14 +634,6 @@ public class DefaultTemplateResolver extends TemplateResolver {
}
}
- /**
- * Removes an entry from the cache, hence forcing the re-loading of it when it's next time requested. (It doesn't
- * delete the template file itself.) This is to give the application finer control over cache updating than the
- * update delay ({@link #getTemplateUpdateDelayMilliseconds()}) alone does.
- *
- * For the meaning of the parameters, see
- * {@link Configuration#getTemplate(String, Locale, Serializable, boolean)}
- */
@Override
public void removeTemplateFromCache(
String name, Locale locale, Serializable customLookupCondition)
[2/2] incubator-freemarker git commit: Added the `templateResolver`
Configuration setting. This allows replacing the whole template lookup,
loading and caching logic with a custom implementation,
giving total control over this aspect of FreeMarker, in ca
Posted by dd...@apache.org.
Added the `templateResolver` Configuration setting. This allows replacing the whole template lookup, loading and caching logic with a custom implementation, giving total control over this aspect of FreeMarker, in case replacing Configuration settings like `templateLoader` or `cacheStorage` wasn't enough. The `TemplateResolver` implementation declares which of the template resolution related Configuration settings it supports (for example, it may still want to rely on the `templateLoader`, but doesn't use the other settings). It's a template resolution related settings that the TemplateResolver doesn't support. The default implementation, `DefaultTemplateResolver`, supports all of them of course. Note that `TemplateCache` was removed, and was basically replaced by `DefaultTemplateResolver`.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/8915ac9b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/8915ac9b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/8915ac9b
Branch: refs/heads/3
Commit: 8915ac9bd89ab75d187afd71b6b16619ee8b42c4
Parents: 2f1f291
Author: ddekany <dd...@apache.org>
Authored: Sun Jun 4 17:41:44 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Wed Jun 7 00:48:23 2017 +0200
----------------------------------------------------------------------
FM3-CHANGE-LOG.txt | 11 +-
.../freemarker/core/ConfigurationTest.java | 98 +++--
.../core/CustomTemplateResolverTest.java | 390 +++++++++++++++++++
.../freemarker/core/IncludeAndImportTest.java | 79 ++--
.../freemarker/core/OutputFormatTest.java | 98 +++--
.../apache/freemarker/core/SQLTimeZoneTest.java | 26 +-
.../freemarker/core/SpecialVariableTest.java | 46 ++-
.../core/TemplateLookupStrategyTest.java | 12 +-
.../DefaultTemplateResolverTest.java | 162 ++++----
.../impl/ExtendedDecimalFormatTest.java | 11 +-
.../apache/freemarker/core/Configuration.java | 310 +++++++++++----
.../ConfigurationSettingValueException.java | 2 +-
.../org/apache/freemarker/core/Environment.java | 19 +-
.../freemarker/core/ParsingConfiguration.java | 5 +-
.../core/SettingValueNotSetException.java | 4 -
.../core/TemplateResolverDependenciesImpl.java | 120 ++++++
.../freemarker/core/TopLevelConfiguration.java | 69 +++-
.../TemplateConfigurationFactory.java | 6 +-
.../templateresolver/TemplateLoadingSource.java | 2 +-
.../core/templateresolver/TemplateResolver.java | 154 ++++++--
.../TemplateResolverDependencies.java | 91 +++++
.../core/templateresolver/_CacheAPI.java | 43 --
.../impl/DefaultTemplateResolver.java | 206 +++++-----
23 files changed, 1411 insertions(+), 553 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/FM3-CHANGE-LOG.txt
----------------------------------------------------------------------
diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt
index b3676a9..7c4cfcf 100644
--- a/FM3-CHANGE-LOG.txt
+++ b/FM3-CHANGE-LOG.txt
@@ -80,9 +80,14 @@ the FreeMarer 3 changelog here:
- Removed SimpleObjectWrapper deprecated paramerless constructor
- Removed ResourceBundleLocalizedString and LocalizedString: Hardly anybody has discovered these, and they had no
JUnit coverage.
-- Added early draft of TemplateResolver, renamed TemplateCache to DefaultTemplateResolver. TemplateResolver is not
- yet directly used in Configuration. This was only added in a hurry, so that it's visible why the
- o.a.f.core.templateresolver subpackage name makes sense.
+- Added the org.apache.freemarker.core.templateresolver.TemplateResolver class and the `templateResolver` Configuration
+ setting. This allows replacing the whole template lookup, loading and caching logic with a custom implementation,
+ giving total control over this aspect of FreeMarker, in case replacing Configuration settings like `templateLoader`
+ or `cacheStorage` wasn't enough. The `TemplateResolver` implementation declares which of the template resolution
+ related Configuration settings it supports (for example, it may still want to rely on the `templateLoader`, but
+ doesn't use the other settings). It's a template resolution related settings that the TemplateResolver doesn't
+ support. The default implementation, `DefaultTemplateResolver`, supports all of them of course. Note that the
+ `TemplateCache` was removed, and was basically replaced by `DefaultTemplateResolver`.
- Marked most static utility classes as internal, and renamed them to start with "_" (for example StringUtils was
renamed to _StringUtil, thus people won't accidentally use it when they wanted to autocomplete to Apache Commons
StringUtil). Created published static utility class, o.a.f.core.util.FTLUtil, which contains some methods moved
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
index 8dccb2f..bbc542d 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
@@ -103,20 +103,14 @@ public class ConfigurationTest extends TestCase {
//
cfgB.setLogTemplateExceptions(true);
{
- Configuration cfg = cfgB.build();
assertTrue(cfgB.isLogTemplateExceptionsSet());
- assertTrue(cfg.isLogTemplateExceptionsSet());
assertTrue(cfgB.getLogTemplateExceptions());
- assertTrue(cfg.getLogTemplateExceptions());
}
//
for (int i = 0; i < 2; i++) {
cfgB.unsetLogTemplateExceptions();
- Configuration cfg = cfgB.build();
assertFalse(cfgB.isLogTemplateExceptionsSet());
- assertTrue(cfg.isLogTemplateExceptionsSet());
assertFalse(cfgB.getLogTemplateExceptions());
- assertFalse(cfg.getLogTemplateExceptions());
}
DefaultObjectWrapper dow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
@@ -408,20 +402,23 @@ public class ConfigurationTest extends TestCase {
tl.putTemplate("a/b.ftl", "In a/b.ftl");
tl.putTemplate("b.ftl", "In b.ftl");
- Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
- .templateLoader(tl);
-
{
- cfgB.setTemplateNameFormat(DefaultTemplateNameFormatFM2.INSTANCE);
- final Template template = cfgB.build().getTemplate("a/./../b.ftl");
+ Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateLoader(tl)
+ .templateNameFormat(DefaultTemplateNameFormatFM2.INSTANCE)
+ .build();
+ final Template template = cfg.getTemplate("a/./../b.ftl");
assertEquals("a/b.ftl", template.getLookupName());
assertEquals("a/b.ftl", template.getSourceName());
assertEquals("In a/b.ftl", template.toString());
}
{
- cfgB.setTemplateNameFormat(DefaultTemplateNameFormat.INSTANCE);
- final Template template = cfgB.build().getTemplate("a/./../b.ftl");
+ Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateLoader(tl)
+ .templateNameFormat(DefaultTemplateNameFormat.INSTANCE)
+ .build();
+ final Template template = cfg.getTemplate("a/./../b.ftl");
assertEquals("b.ftl", template.getLookupName());
assertEquals("b.ftl", template.getSourceName());
assertEquals("In b.ftl", template.toString());
@@ -455,30 +452,28 @@ public class ConfigurationTest extends TestCase {
}
}
- public void testTemplateLookupStrategyDefaultAndSet() throws Exception {
- Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
- assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.getTemplateLookupStrategy());
- assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.build().getTemplateLookupStrategy());
-
- cfgB.setTemplateLoader(new ClassTemplateLoader(ConfigurationTest.class, ""));
- assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.getTemplateLookupStrategy());
- Configuration cfg = cfgB.build();
+ public void testTemplateLookupStrategyDefault() throws Exception {
+ Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateLoader(new ClassTemplateLoader(ConfigurationTest.class, ""))
+ .build();
assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfg.getTemplateLookupStrategy());
- cfg.getTemplate("toCache1.ftl");
+ assertEquals("toCache1.ftl", cfg.getTemplate("toCache1.ftl").getSourceName());
+ }
+ public void testTemplateLookupStrategyCustom() throws Exception {
final TemplateLookupStrategy myStrategy = new TemplateLookupStrategy() {
@Override
public TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException {
return ctx.lookupWithAcquisitionStrategy("toCache2.ftl");
}
};
- cfgB.setTemplateLookupStrategy(myStrategy);
- assertSame(myStrategy, cfgB.getTemplateLookupStrategy());
- cfg = cfgB.build();
- cfg.clearTemplateCache();
+
+ Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateLoader(new ClassTemplateLoader(ConfigurationTest.class, ""))
+ .templateLookupStrategy(myStrategy)
+ .build();
assertSame(myStrategy, cfg.getTemplateLookupStrategy());
- Template template = cfg.getTemplate("toCache1.ftl");
- assertEquals("toCache2.ftl", template.getSourceName());
+ assertEquals("toCache2.ftl", cfg.getTemplate("toCache1.ftl").getSourceName());
}
public void testSetTemplateConfigurations() throws Exception {
@@ -903,48 +898,50 @@ public class ConfigurationTest extends TestCase {
public void testTemplateUpdateDelay() throws Exception {
Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
- assertEquals(DefaultTemplateResolver.DEFAULT_TEMPLATE_UPDATE_DELAY_MILLIS, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(
+ DefaultTemplateResolver.DEFAULT_TEMPLATE_UPDATE_DELAY_MILLIS,
+ (Object) cfgB.getTemplateUpdateDelayMilliseconds());
- cfgB.setTemplateUpdateDelayMilliseconds(4000);
- assertEquals(4000L, cfgB.getTemplateUpdateDelayMilliseconds());
+ cfgB.setTemplateUpdateDelayMilliseconds(4000L);
+ assertEquals(4000L, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
- cfgB.setTemplateUpdateDelayMilliseconds(100);
- assertEquals(100L, cfgB.getTemplateUpdateDelayMilliseconds());
+ cfgB.setTemplateUpdateDelayMilliseconds(100L);
+ assertEquals(100L, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
try {
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "5");
- assertEquals(5000L, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(5000L, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
} catch (ConfigurationSettingValueException e) {
assertThat(e.getMessage(), containsStringIgnoringCase("unit must be specified"));
}
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "0");
- assertEquals(0L, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(0L, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
try {
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "5 foo");
- assertEquals(5000L, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(5000L, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
} catch (ConfigurationSettingValueException e) {
assertThat(e.getMessage(), containsStringIgnoringCase("\"foo\""));
}
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "3 ms");
- assertEquals(3L, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(3L, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "4ms");
- assertEquals(4L, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(4L, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "3 s");
- assertEquals(3000L, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(3000L, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "4s");
- assertEquals(4000L, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(4000L, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "3 m");
- assertEquals(1000L * 60 * 3, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(1000L * 60 * 3, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "4m");
- assertEquals(1000L * 60 * 4, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(1000L * 60 * 4, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "1 h");
- assertEquals(1000L * 60 * 60, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(1000L * 60 * 60, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "2h");
- assertEquals(1000L * 60 * 60 * 2, cfgB.getTemplateUpdateDelayMilliseconds());
+ assertEquals(1000L * 60 * 60 * 2, (Object) cfgB.getTemplateUpdateDelayMilliseconds());
}
@Test
@@ -1025,34 +1022,33 @@ public class ConfigurationTest extends TestCase {
@Test
public void testSetTabSize() throws Exception {
- Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
String ftl = "${\t}";
try {
- new Template(null, ftl, cfgB.build());
+ new Template(null, ftl,
+ new Configuration.Builder(Configuration.VERSION_3_0_0).build());
fail();
} catch (ParseException e) {
assertEquals(9, e.getColumnNumber());
}
- cfgB.setTabSize(1);
try {
- new Template(null, ftl, cfgB.build());
+ new Template(null, ftl,
+ new Configuration.Builder(Configuration.VERSION_3_0_0).tabSize(1).build());
fail();
} catch (ParseException e) {
assertEquals(4, e.getColumnNumber());
}
try {
- cfgB.setTabSize(0);
+ new Configuration.Builder(Configuration.VERSION_3_0_0).tabSize(0);
fail();
} catch (IllegalArgumentException e) {
// Expected
}
try {
- cfgB.setTabSize(257);
+ new Configuration.Builder(Configuration.VERSION_3_0_0).tabSize(257);
fail();
} catch (IllegalArgumentException e) {
// Expected
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CustomTemplateResolverTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/CustomTemplateResolverTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CustomTemplateResolverTest.java
new file mode 100644
index 0000000..5658ac9
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CustomTemplateResolverTest.java
@@ -0,0 +1,390 @@
+/*
+ * 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 static junit.framework.TestCase.*;
+import static org.apache.freemarker.core.Configuration.ExtendableBuilder.*;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Locale;
+
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.GetTemplateResult;
+import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
+import org.apache.freemarker.core.templateresolver.PathGlobMatcher;
+import org.apache.freemarker.core.templateresolver.TemplateResolver;
+import org.apache.freemarker.core.templateresolver.TemplateResolverDependencies;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
+import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.core.util.BugException;
+import org.junit.Test;
+
+public class CustomTemplateResolverTest {
+
+ @Test
+ public void testPositive() throws IOException, TemplateException {
+ Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateResolver(new CustomTemplateResolver(null))
+ .build();
+ Template template = cfg.getTemplate(":foo::includes");
+
+ assertEquals("foo:includes", template.getLookupName());
+
+ StringWriter sw = new StringWriter();
+ template.process(null, sw);
+ assertEquals("In foo:includes, included: In foo:inc", sw.toString());
+
+ try {
+ cfg.removeTemplateFromCache("foo", null, null);
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // Expected
+ }
+
+ try {
+ cfg.clearTemplateCache();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testConfigurationDefaultForDefaultTemplateResolver() {
+ Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
+
+ assertNotNull(cfg.getTemplateLookupStrategy());
+ assertNotNull(cfg.getLocalizedLookup());
+ assertNotNull(cfg.getCacheStorage());
+ assertNotNull(cfg.getTemplateUpdateDelayMilliseconds());
+ assertNotNull(cfg.getNamingConvention());
+
+ assertNull(cfg.getTemplateLoader());
+ assertNull(cfg.getTemplateConfigurations());
+
+ assertNotNull(cfg.getTemplateLanguage());
+ assertNotNull(cfg.getSourceEncoding());
+ }
+
+ @Test
+ public void testConfigurationDefaultForCustomTemplateResolver() {
+ Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateResolver(new CustomTemplateResolver(null))
+ .build();
+
+ assertNull(cfg.getTemplateLookupStrategy());
+ assertNull(cfg.getLocalizedLookup());
+ assertNull(cfg.getCacheStorage());
+ assertNull(cfg.getTemplateUpdateDelayMilliseconds());
+ assertNull(cfg.getTemplateNameFormat());
+
+ assertNull(cfg.getTemplateLoader());
+ assertNull(cfg.getTemplateConfigurations());
+
+ assertNotNull(cfg.getTemplateLanguage());
+ assertNotNull(cfg.getSourceEncoding());
+ }
+
+
+ @Test
+ public void testConfigurationDefaultForCustomTemplateResolver2() {
+ Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateResolver(new CustomTemplateResolver(NAMING_CONVENTION_KEY))
+ .build();
+
+ assertNull(cfg.getTemplateLookupStrategy());
+ assertNull(cfg.getLocalizedLookup());
+ assertNull(cfg.getCacheStorage());
+ assertNull(cfg.getTemplateUpdateDelayMilliseconds());
+ assertNotNull(cfg.getNamingConvention()); //!
+
+ assertNull(cfg.getTemplateLoader());
+ assertNull(cfg.getTemplateConfigurations());
+
+ assertNotNull(cfg.getTemplateLanguage());
+ assertNotNull(cfg.getSourceEncoding());
+ }
+
+ @Test
+ public void testInvalidConfigurationForDefaultTemplateResolver() {
+ try {
+ new Configuration.Builder(Configuration.VERSION_3_0_0).cacheStorage(null).build();
+ fail();
+ } catch (ConfigurationSettingValueException e) {
+ // Expected
+ }
+ try {
+ new Configuration.Builder(Configuration.VERSION_3_0_0).templateUpdateDelayMilliseconds(null).build();
+ fail();
+ } catch (ConfigurationSettingValueException e) {
+ // Expected
+ }
+ try {
+ new Configuration.Builder(Configuration.VERSION_3_0_0).templateLookupStrategy(null).build();
+ fail();
+ } catch (ConfigurationSettingValueException e) {
+ // Expected
+ }
+ try {
+ new Configuration.Builder(Configuration.VERSION_3_0_0).localizedLookup(null).build();
+ fail();
+ } catch (ConfigurationSettingValueException e) {
+ // Expected
+ }
+ try {
+ new Configuration.Builder(Configuration.VERSION_3_0_0).templateNameFormat(null).build();
+ fail();
+ } catch (ConfigurationSettingValueException e) {
+ // Expected
+ }
+
+ new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(null).build();
+ new Configuration.Builder(Configuration.VERSION_3_0_0).templateConfigurations(null).build();
+ }
+
+ @Test
+ public void testConfigurationValidityForCustomTemplateResolver() {
+ for (String supportedSetting : new String[]{
+ TEMPLATE_LOADER_KEY, TEMPLATE_LOOKUP_STRATEGY_KEY, LOCALIZED_LOOKUP_KEY, TEMPLATE_NAME_FORMAT_KEY,
+ CACHE_STORAGE_KEY, TEMPLATE_UPDATE_DELAY_KEY, TEMPLATE_CONFIGURATIONS_KEY }) {
+ {
+ Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateResolver(new CustomTemplateResolver(supportedSetting));
+ setSetting(cfgB, supportedSetting);
+ cfgB.build();
+ }
+ {
+ Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateResolver(new CustomTemplateResolver(null));
+ setSetting(cfgB, supportedSetting);
+ try {
+ cfgB.build();
+ fail();
+ } catch (ConfigurationSettingValueException e) {
+ // Expected
+ }
+ }
+ }
+ }
+
+ private void setSetting(Configuration.Builder cfgB, String setting) {
+ if (TEMPLATE_LOADER_KEY.equals(setting)) {
+ cfgB.setTemplateLoader(new StringTemplateLoader());
+ } else if (TEMPLATE_LOOKUP_STRATEGY_KEY.equals(setting)) {
+ cfgB.setTemplateLookupStrategy(DefaultTemplateLookupStrategy.INSTANCE);
+ } else if (LOCALIZED_LOOKUP_KEY.equals(setting)) {
+ cfgB.setLocalizedLookup(true);
+ } else if (TEMPLATE_NAME_FORMAT_KEY.equals(setting)) {
+ cfgB.setTemplateNameFormat(DefaultTemplateNameFormat.INSTANCE);
+ } else if (CACHE_STORAGE_KEY.equals(setting)) {
+ cfgB.setCacheStorage(new SoftCacheStorage());
+ } else if (TEMPLATE_UPDATE_DELAY_KEY.equals(setting)) {
+ cfgB.setTemplateUpdateDelayMilliseconds(1234L);
+ } else if (TEMPLATE_CONFIGURATIONS_KEY.equals(setting)) {
+ cfgB.setTemplateConfigurations(new ConditionalTemplateConfigurationFactory(
+ new PathGlobMatcher("*.x"),
+ new TemplateConfiguration.Builder().build()));
+ } else {
+ throw new BugException("Unsupported setting: " + setting);
+ }
+ }
+
+ static class CustomTemplateResolver extends TemplateResolver {
+
+ private final String supportedSetting;
+ private TemplateLanguage templateLanguage;
+
+ CustomTemplateResolver(String supportedSetting) {
+ this.supportedSetting = supportedSetting;
+ }
+
+ @Override
+ protected void initialize() throws ConfigurationException {
+ TemplateResolverDependencies deps = getDependencies();
+
+ if (TEMPLATE_LOADER_KEY.equals(supportedSetting)) {
+ assertNotNull(deps.getTemplateLoader());
+ } else {
+ try {
+ deps.getTemplateLoader();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ }
+
+ if (TEMPLATE_LOOKUP_STRATEGY_KEY.equals(supportedSetting)) {
+ assertNotNull(deps.getTemplateLookupStrategy());
+ } else {
+ try {
+ deps.getTemplateLookupStrategy();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ }
+
+ if (LOCALIZED_LOOKUP_KEY.equals(supportedSetting)) {
+ assertNotNull(deps.getLocalizedLookup());
+ } else {
+ try {
+ deps.getLocalizedLookup();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ }
+
+ if (TEMPLATE_NAME_FORMAT_KEY.equals(supportedSetting)) {
+ assertNotNull(deps.getTemplateNameFormat());
+ } else {
+ try {
+ deps.getTemplateNameFormat();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ }
+
+ if (CACHE_STORAGE_KEY.equals(supportedSetting)) {
+ assertNotNull(deps.getCacheStorage());
+ } else {
+ try {
+ deps.getCacheStorage();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ }
+
+ if (TEMPLATE_UPDATE_DELAY_KEY.equals(supportedSetting)) {
+ assertNotNull(deps.getTemplateUpdateDelayMilliseconds());
+ } else {
+ try {
+ deps.getTemplateUpdateDelayMilliseconds();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ }
+
+ if (TEMPLATE_CONFIGURATIONS_KEY.equals(supportedSetting)) {
+ assertNotNull(deps.getTemplateConfigurations());
+ } else {
+ try {
+ deps.getTemplateConfigurations();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ }
+
+ templateLanguage = deps.getTemplateLanguage();
+ deps.getSourceEncoding();
+ }
+
+ @Override
+ protected void checkInitialized() {
+ super.checkInitialized();
+ }
+
+ @Override
+ public GetTemplateResult getTemplate(String name, Locale locale, Serializable customLookupCondition)
+ throws IOException {
+ name = normalizeRootBasedName(name);
+ return new GetTemplateResult(getDependencies()
+ .parse(templateLanguage, name, name,
+ new StringReader(
+ "In " + name
+ + (name.endsWith("includes")
+ ? ", included: <#include 'inc'>"
+ : "")),
+ null, null, null));
+ }
+
+ @Override
+ public void clearTemplateCache() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeTemplateFromCache(String name, Locale locale, Serializable customLookupCondition)
+ throws IOException, UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toRootBasedName(String baseName, String targetName) throws MalformedTemplateNameException {
+ if (targetName.startsWith(":")) {
+ return targetName.substring(1);
+ } else {
+ int lastColonIdx = baseName.lastIndexOf(':');
+ return lastColonIdx == -1 ? targetName : baseName.substring(0, lastColonIdx + 1) + targetName;
+ }
+ }
+
+ @Override
+ public String normalizeRootBasedName(String name) throws MalformedTemplateNameException {
+ name = name.replaceAll("::", ":");
+ return name.startsWith(":") ? name.substring(1) : name;
+ }
+
+ @Override
+ public boolean supportsTemplateLoaderSetting() {
+ return TEMPLATE_LOADER_KEY.equals(supportedSetting);
+ }
+
+ @Override
+ public boolean supportsCacheStorageSetting() {
+ return CACHE_STORAGE_KEY.equals(supportedSetting);
+ }
+
+ @Override
+ public boolean supportsTemplateLookupStrategySetting() {
+ return TEMPLATE_LOOKUP_STRATEGY_KEY.equals(supportedSetting);
+ }
+
+ @Override
+ public boolean supportsTemplateNameFormatSetting() {
+ return TEMPLATE_NAME_FORMAT_KEY.equals(supportedSetting);
+ }
+
+ @Override
+ public boolean supportsTemplateConfigurationsSetting() {
+ return TEMPLATE_CONFIGURATIONS_KEY.equals(supportedSetting);
+ }
+
+ @Override
+ public boolean supportsTemplateUpdateDelayMillisecondsSetting() {
+ return TEMPLATE_UPDATE_DELAY_KEY.equals(supportedSetting);
+ }
+
+ @Override
+ public boolean supportsLocalizedLookupSetting() {
+ return LOCALIZED_LOOKUP_KEY.equals(supportedSetting);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
index 71b886b..c8a0186 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
@@ -153,59 +153,80 @@ public class IncludeAndImportTest extends TemplateTest {
@Test
public void lazyAutoImportSettings() throws IOException, TemplateException {
- TestConfigurationBuilder cfgB = new TestConfigurationBuilder()
- .autoImports(ImmutableMap.of(
- "l1", "lib1.ftl",
- "l2", "lib2.ftl",
- "l3", "lib3.ftl"
- ));
-
+ ImmutableMap<String, String> autoImports = ImmutableMap.of(
+ "l1", "lib1.ftl",
+ "l2", "lib2.ftl",
+ "l3", "lib3.ftl"
+ );
String ftl = "<@l2.m/>, <@l1.m/>; ${history}";
String expectedEagerOutput = "In lib2, In lib1; L1L2L3";
String expecedLazyOutput = "In lib2, In lib1; L2L1";
- setConfiguration(cfgB.build());
+ setConfiguration(new TestConfigurationBuilder()
+ .autoImports(autoImports)
+ .build());
assertOutput(ftl, expectedEagerOutput);
- cfgB.setLazyImports(true);
- setConfiguration(cfgB.build());
+
+ setConfiguration(new TestConfigurationBuilder()
+ .autoImports(autoImports)
+ .lazyImports(true)
+ .build());
+ assertNull(getConfiguration().getLazyAutoImports());
assertOutput(ftl, expecedLazyOutput);
- cfgB.setLazyImports(false);
- setConfiguration(cfgB.build());
+
+ setConfiguration(new TestConfigurationBuilder()
+ .autoImports(autoImports)
+ .lazyImports(false)
+ .build());
assertOutput(ftl, expectedEagerOutput);
- cfgB.setLazyAutoImports(true);
- setConfiguration(cfgB.build());
+
+ setConfiguration(new TestConfigurationBuilder()
+ .autoImports(autoImports)
+ .lazyImports(false)
+ .lazyAutoImports(true)
+ .build());
assertOutput(ftl, expecedLazyOutput);
- cfgB.setLazyAutoImports(null);
- setConfiguration(cfgB.build());
+
+ setConfiguration(new TestConfigurationBuilder()
+ .autoImports(autoImports)
+ .lazyImports(false)
+ .lazyAutoImports(null)
+ .build());
assertOutput(ftl, expectedEagerOutput);
- cfgB.setLazyImports(true);
- cfgB.setLazyAutoImports(false);
- setConfiguration(cfgB.build());
+
+ setConfiguration(new TestConfigurationBuilder()
+ .autoImports(autoImports)
+ .lazyImports(true)
+ .lazyAutoImports(false)
+ .build());
assertOutput(ftl, expectedEagerOutput);
}
@Test
public void lazyAutoImportMixedWithManualImport() throws IOException, TemplateException {
- TestConfigurationBuilder cfgB = new TestConfigurationBuilder()
- .autoImports(ImmutableMap.of(
- "l1", "lib1.ftl",
- "l2", "/./lib2.ftl",
- "l3", "lib3.ftl"))
- .lazyAutoImports(true);
-
+ ImmutableMap<String, String> autoImports = ImmutableMap.of(
+ "l1", "lib1.ftl",
+ "l2", "/./lib2.ftl",
+ "l3", "lib3.ftl");
String ftl = "<@l2.m/>, <@l1.m/>; ${history}";
String expectOutputWithoutHistory = "In lib2, In lib1; ";
String expecedOutput = expectOutputWithoutHistory + "L2L1";
- setConfiguration(cfgB.build());
+ setConfiguration(new TestConfigurationBuilder()
+ .autoImports(autoImports)
+ .lazyAutoImports(true)
+ .build());
assertOutput(ftl, expecedOutput);
assertOutput("<#import 'lib1.ftl' as l1>" + ftl, expectOutputWithoutHistory + "L1L2");
assertOutput("<#import './x/../lib1.ftl' as l1>" + ftl, expectOutputWithoutHistory + "L1L2");
assertOutput("<#import 'lib2.ftl' as l2>" + ftl, expecedOutput);
assertOutput("<#import 'lib3.ftl' as l3>" + ftl, expectOutputWithoutHistory + "L3L2L1");
- cfgB.setLazyImports(true);
- setConfiguration(cfgB.build());
+ setConfiguration(new TestConfigurationBuilder()
+ .autoImports(autoImports)
+ .lazyAutoImports(true)
+ .lazyImports(true)
+ .build());
assertOutput("<#import 'lib1.ftl' as l1>" + ftl, expecedOutput);
assertOutput("<#import './x/../lib1.ftl' as l1>" + ftl, expecedOutput);
assertOutput("<#import 'lib2.ftl' as l2>" + ftl, expecedOutput);
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
index d78c558..c656cd3 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
@@ -55,9 +55,9 @@ public class OutputFormatTest extends TemplateTest {
addTemplate("t.xml", "${.outputFormat}");
addTemplate("tWithHeader", "<#ftl outputFormat='HTML'>${.outputFormat}");
- TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
for (OutputFormat cfgOutputFormat
: new OutputFormat[] { UndefinedOutputFormat.INSTANCE, RTFOutputFormat.INSTANCE } ) {
+ TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
if (!cfgOutputFormat.equals(UndefinedOutputFormat.INSTANCE)) {
cfgB.setOutputFormat(cfgOutputFormat);
}
@@ -100,8 +100,8 @@ public class OutputFormatTest extends TemplateTest {
addTemplate("t.fTlX", commonContent);
addTemplate("tWithHeader.ftlx", "<#ftl outputFormat='HTML'>" + commonContent);
- TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
for (int setupNumber = 1; setupNumber <= 3; setupNumber++) {
+ TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
final OutputFormat cfgOutputFormat;
final OutputFormat ftlhOutputFormat;
final OutputFormat ftlxOutputFormat;
@@ -193,48 +193,38 @@ public class OutputFormatTest extends TemplateTest {
.build());
{
- TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
-
- setConfiguration(cfgB.outputFormat(HTMLOutputFormat.INSTANCE).build());
+ setConfiguration(createDefaultConfigurationBuilder().outputFormat(HTMLOutputFormat.INSTANCE).build());
assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it
- setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
+ setConfiguration(createDefaultConfigurationBuilder().templateConfigurations(tcfHTML).build());
assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it
- setConfiguration(cfgB.templateConfigurations(tcfNoAutoEsc).build());
+ setConfiguration(createDefaultConfigurationBuilder().templateConfigurations(tcfNoAutoEsc).build());
assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it
}
{
- TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
-
- setConfiguration(cfgB.recognizeStandardFileExtensions(false).build());
+ setConfiguration(createDefaultConfigurationBuilder().recognizeStandardFileExtensions(false).build());
assertErrorContainsForNamed("t.ftlx", UndefinedOutputFormat.INSTANCE.getName());
- setConfiguration(cfgB.outputFormat(HTMLOutputFormat.INSTANCE).build());
- assertOutputForNamed("t.ftlx", "' ' '");
- setConfiguration(cfgB.outputFormat(XMLOutputFormat.INSTANCE).build());
- assertOutputForNamed("t.ftlx", "' ' '");
- setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
- assertOutputForNamed("t.ftlx", "' ' '");
- setConfiguration(cfgB.templateConfigurations(tcfNoAutoEsc).build());
- assertOutputForNamed("t.ftlx", "' ' '");
- }
- {
- TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
- cfgB.setRecognizeStandardFileExtensions(true);
-
- setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
- assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it
- setConfiguration(cfgB.templateConfigurations(tcfNoAutoEsc).build());
- assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it
- }
+ setConfiguration(createDefaultConfigurationBuilder()
+ .recognizeStandardFileExtensions(false)
+ .outputFormat(HTMLOutputFormat.INSTANCE).build());
+ assertOutputForNamed("t.ftlx", "' ' '");
- {
- TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
+ setConfiguration(createDefaultConfigurationBuilder()
+ .recognizeStandardFileExtensions(false)
+ .outputFormat(XMLOutputFormat.INSTANCE).build());
+ assertOutputForNamed("t.ftlx", "' ' '");
- setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
- assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it
- setConfiguration(cfgB.recognizeStandardFileExtensions(false).build());
+ setConfiguration(createDefaultConfigurationBuilder()
+ .recognizeStandardFileExtensions(false)
+ .templateConfigurations(tcfHTML).build());
assertOutputForNamed("t.ftlx", "' ' '");
+
+ setConfiguration(createDefaultConfigurationBuilder()
+ .recognizeStandardFileExtensions(false)
+ .templateConfigurations(tcfNoAutoEsc)
+ .outputFormat(XMLOutputFormat.INSTANCE).build());
+ assertOutputForNamed("t.ftlx", "' ' '");
}
}
@@ -288,10 +278,10 @@ public class OutputFormatTest extends TemplateTest {
addTemplate("tWithHeaderFalse", "<#ftl autoEsc=false>${'a&b'}");
addTemplate("tWithHeaderTrue", "<#ftl autoEsc=true>${'a&b'}");
- TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder().outputFormat(XMLOutputFormat.INSTANCE);
- assertEquals(ENABLE_IF_DEFAULT, cfgB.getAutoEscapingPolicy());
-
for (boolean cfgAutoEscaping : new boolean[] { true, false }) {
+ TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder().outputFormat(XMLOutputFormat.INSTANCE);
+ assertEquals(ENABLE_IF_DEFAULT, cfgB.getAutoEscapingPolicy());
+
if (!cfgAutoEscaping) {
cfgB.setAutoEscapingPolicy(DISABLE);
}
@@ -778,41 +768,30 @@ public class OutputFormatTest extends TemplateTest {
@Test
public void testAutoEscPolicy() throws Exception {
- TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
- cfgB.setRegisteredCustomOutputFormats(ImmutableList.<OutputFormat>of(
- SeldomEscapedOutputFormat.INSTANCE, DummyOutputFormat.INSTANCE));
- assertEquals(ENABLE_IF_DEFAULT, cfgB.getAutoEscapingPolicy());
+ assertEquals(ENABLE_IF_DEFAULT, createDefaultConfigurationBuilder().getAutoEscapingPolicy());
String commonFTL = "${'.'} ${.autoEsc?c}";
String notEsced = ". false";
String esced = "\\. true";
-
for (AutoEscapingPolicy autoEscPolicy : new AutoEscapingPolicy[] {
ENABLE_IF_DEFAULT,
ENABLE_IF_SUPPORTED,
DISABLE }) {
- cfgB.setAutoEscapingPolicy(autoEscPolicy);
-
String sExpted = autoEscPolicy == ENABLE_IF_SUPPORTED ? esced : notEsced;
- cfgB.setOutputFormat(SeldomEscapedOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(testAutoEscPolicy_createCfg(autoEscPolicy, SeldomEscapedOutputFormat.INSTANCE));
assertOutput(commonFTL, sExpted);
- cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(testAutoEscPolicy_createCfg(autoEscPolicy, UndefinedOutputFormat.INSTANCE));
assertOutput("<#ftl outputFormat='seldomEscaped'>" + commonFTL, sExpted);
assertOutput("<#outputFormat 'seldomEscaped'>" + commonFTL + "</#outputFormat>", sExpted);
String dExpted = autoEscPolicy == DISABLE ? notEsced : esced;
- cfgB.setOutputFormat(DummyOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(testAutoEscPolicy_createCfg(autoEscPolicy, DummyOutputFormat.INSTANCE));
assertOutput(commonFTL, dExpted);
- cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(testAutoEscPolicy_createCfg(autoEscPolicy, UndefinedOutputFormat.INSTANCE));
assertOutput("<#ftl outputFormat='dummy'>" + commonFTL, dExpted);
assertOutput("<#outputFormat 'dummy'>" + commonFTL + "</#outputFormat>", dExpted);
- cfgB.setOutputFormat(DummyOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(testAutoEscPolicy_createCfg(autoEscPolicy, DummyOutputFormat.INSTANCE));
assertOutput(
commonFTL
+ "<#outputFormat 'seldomEscaped'>"
@@ -861,7 +840,18 @@ public class OutputFormatTest extends TemplateTest {
+ dExpted);
}
}
-
+
+ private Configuration testAutoEscPolicy_createCfg(AutoEscapingPolicy autoEscPolicy,
+ OutputFormat outpoutFormat)
+ throws TemplateModelException {
+ return createDefaultConfigurationBuilder()
+ .registeredCustomOutputFormats(ImmutableList.<OutputFormat>of(
+ SeldomEscapedOutputFormat.INSTANCE, DummyOutputFormat.INSTANCE))
+ .autoEscapingPolicy(autoEscPolicy)
+ .outputFormat(outpoutFormat)
+ .build();
+ }
+
@Test
public void testDynamicParsingBIsInherticContextOutputFormat() throws Exception {
// Dynamic parser BI-s are supposed to use the ParsingConfiguration of the calling template, and ignore anything
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
index cf14b93..c9877ca 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
@@ -51,27 +51,33 @@ public class SQLTimeZoneTest extends TemplateTest {
private final Timestamp sqlTimestamp = new Timestamp(utcToLong("2014-07-12T10:30:05")); // 2014-07-12T12:30:05
private final Date javaDate = new Date(utcToLong("2014-07-12T10:30:05")); // 2014-07-12T12:30:05
private final Date javaDayErrorDate = new Date(utcToLong("2014-07-11T22:00:00")); // 2014-07-12T12:30:05
-
+
+ @SuppressWarnings("unused") // Accessed from template
public TimeZone getLastDefaultTimeZone() {
return lastDefaultTimeZone;
}
+ @SuppressWarnings("unused") // Accessed from template
public void setLastDefaultTimeZone(TimeZone lastDefaultTimeZone) {
this.lastDefaultTimeZone = lastDefaultTimeZone;
}
+ @SuppressWarnings("unused") // Accessed from template
public java.sql.Date getSqlDate() {
return sqlDate;
}
+ @SuppressWarnings("unused") // Accessed from template
public Time getSqlTime() {
return sqlTime;
}
+ @SuppressWarnings("unused") // Accessed from template
public Timestamp getSqlTimestamp() {
return sqlTimestamp;
}
+ @SuppressWarnings("unused") // Accessed from template
public Date getJavaDate() {
return javaDate;
}
@@ -202,13 +208,7 @@ public class SQLTimeZoneTest extends TemplateTest {
@Test
public void testCacheFlushings() throws Exception {
- Configuration.ExtendableBuilder<?> cfgB = createConfigurationBuilder()
- .timeZone(_DateUtil.UTC)
- .dateFormat("yyyy-MM-dd E")
- .timeFormat("HH:mm:ss E")
- .dateTimeFormat("yyyy-MM-dd'T'HH:mm:ss E");
-
- setConfiguration(cfgB.build());
+ setConfiguration(testCacheFlushing_createBuilder().build());
assertOutput(
"${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+ "<#setting locale='de'>\n"
@@ -234,7 +234,7 @@ public class SQLTimeZoneTest extends TemplateTest {
"2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
+ "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05, 2014-07-12T10:30:05, 2014-07-12 Sat, 10:30:05 Sat\n");
- setConfiguration(cfgB.sqlDateAndTimeTimeZone(GMT_P02).build());
+ setConfiguration(testCacheFlushing_createBuilder().sqlDateAndTimeTimeZone(GMT_P02).build());
assertOutput(
"${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+ "<#setting locale='de'>\n"
@@ -261,6 +261,14 @@ public class SQLTimeZoneTest extends TemplateTest {
+ "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05, 2014-07-12T10:30:05, 2014-07-12 Sat, 10:30:05 Sat\n");
}
+ private Configuration.ExtendableBuilder<?> testCacheFlushing_createBuilder() {
+ return createConfigurationBuilder()
+ .timeZone(_DateUtil.UTC)
+ .dateFormat("yyyy-MM-dd E")
+ .timeFormat("HH:mm:ss E")
+ .dateTimeFormat("yyyy-MM-dd'T'HH:mm:ss E");
+ }
+
@Test
public void testDateAndTimeBuiltInsHasNoEffect() throws Exception {
setConfiguration(createConfigurationBuilder()
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
index 99aae83..c74dfd7 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
@@ -62,41 +62,51 @@ public class SpecialVariableTest extends TemplateTest {
@Test
public void testAutoEsc() throws Exception {
- Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
for (AutoEscapingPolicy autoEscaping : new AutoEscapingPolicy[] {
AutoEscapingPolicy.ENABLE_IF_DEFAULT, AutoEscapingPolicy.ENABLE_IF_SUPPORTED }) {
- cfgB.setAutoEscapingPolicy(autoEscaping);
- cfgB.setOutputFormat(HTMLOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .autoEscapingPolicy(autoEscaping)
+ .outputFormat(HTMLOutputFormat.INSTANCE)
+ .build());
assertOutput("${.autoEsc?c}", "true");
assertOutput("<#ftl autoEsc=false>${.autoEsc?c}", "false");
- cfgB.setOutputFormat(PlainTextOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .autoEscapingPolicy(autoEscaping)
+ .outputFormat(PlainTextOutputFormat.INSTANCE)
+ .build());
assertOutput("${.autoEsc?c}", "false");
- cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .autoEscapingPolicy(autoEscaping)
+ .outputFormat(UndefinedOutputFormat.INSTANCE)
+ .build());
assertOutput("${.autoEsc?c}", "false");
}
- cfgB.setAutoEscapingPolicy(AutoEscapingPolicy.DISABLE);
- cfgB.setOutputFormat(HTMLOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .autoEscapingPolicy(AutoEscapingPolicy.DISABLE)
+ .outputFormat(HTMLOutputFormat.INSTANCE)
+ .build());
assertOutput("${.autoEsc?c}", "false");
assertOutput("<#ftl autoEsc=true>${.autoEsc?c}", "true");
- cfgB.setOutputFormat(PlainTextOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .autoEscapingPolicy(AutoEscapingPolicy.DISABLE)
+ .outputFormat(PlainTextOutputFormat.INSTANCE)
+ .build());
assertOutput("${.autoEsc?c}", "false");
- cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
- setConfiguration(cfgB.build());
+ setConfiguration(new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .autoEscapingPolicy(AutoEscapingPolicy.DISABLE)
+ .outputFormat(UndefinedOutputFormat.INSTANCE)
+ .build());
assertOutput("${.autoEsc?c}", "false");
- cfgB.setAutoEscapingPolicy(AutoEscapingPolicy.ENABLE_IF_DEFAULT);
- setConfiguration(cfgB.build());
+ setConfiguration(new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .autoEscapingPolicy(AutoEscapingPolicy.ENABLE_IF_DEFAULT)
+ .outputFormat(UndefinedOutputFormat.INSTANCE)
+ .build());
assertOutput(
"${.autoEsc?c} "
+ "<#outputFormat 'HTML'>${.autoEsc?c}</#outputFormat> "
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
index f0e63a8..ba6c806 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
@@ -309,11 +309,15 @@ public class TemplateLookupStrategyTest {
final Configuration cfg;
final Configuration cfgNoLocLU;
{
- Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
.templateLoader(tl)
- .templateLookupStrategy(new DomainTemplateLookupStrategy());
- cfg = cfgB.build();
- cfgNoLocLU = cfgB.localizedLookup(false).build();
+ .templateLookupStrategy(new DomainTemplateLookupStrategy())
+ .build();
+ cfgNoLocLU = new Configuration.Builder(Configuration.VERSION_3_0_0)
+ .templateLoader(tl)
+ .templateLookupStrategy(new DomainTemplateLookupStrategy())
+ .localizedLookup(false)
+ .build();
}
final String iAtDefaultContent = "i at default";
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
index f51ba86..70254ba 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
@@ -19,6 +19,7 @@
package org.apache.freemarker.core.templateresolver;
+import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
@@ -28,7 +29,6 @@ import java.util.Locale;
import org.apache.freemarker.core.Configuration;
import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver;
import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
@@ -48,13 +48,14 @@ public class DefaultTemplateResolverTest {
@Test
public void testCachedException() throws Exception {
MockTemplateLoader loader = new MockTemplateLoader();
- DefaultTemplateResolver tr = new DefaultTemplateResolver(
- loader,
- new StrongCacheStorage(), 100L,
- DefaultTemplateLookupStrategy.INSTANCE, true,
- DefaultTemplateNameFormat.INSTANCE,
- null,
- new TestConfigurationBuilder().build());
+ Configuration cfg = new TestConfigurationBuilder()
+ .templateLoader(loader)
+ .cacheStorage(new StrongCacheStorage())
+ .templateUpdateDelayMilliseconds(100L)
+ .build();
+ TemplateResolver tr = cfg.getTemplateResolver();
+ assertThat(tr, instanceOf(DefaultTemplateResolver.class));
+
loader.setThrowException(true);
try {
tr.getTemplate("t", Locale.getDefault(), null).getTemplate();
@@ -88,19 +89,22 @@ public class DefaultTemplateResolverTest {
@Test
public void testCachedNotFound() throws Exception {
MockTemplateLoader loader = new MockTemplateLoader();
- DefaultTemplateResolver cache = new DefaultTemplateResolver(
- loader,
- new StrongCacheStorage(), 100L,
- DefaultTemplateLookupStrategy.INSTANCE, false,
- DefaultTemplateNameFormat.INSTANCE,
- null, new TestConfigurationBuilder().build());
- assertNull(cache.getTemplate("t", Locale.getDefault(), null).getTemplate());
+ Configuration cfg = new TestConfigurationBuilder()
+ .templateLoader(loader)
+ .cacheStorage(new StrongCacheStorage())
+ .templateUpdateDelayMilliseconds(100L)
+ .localizedLookup(false)
+ .build();
+ TemplateResolver tr = cfg.getTemplateResolver();
+ assertThat(tr, instanceOf(DefaultTemplateResolver.class));
+
+ assertNull(tr.getTemplate("t", Locale.getDefault(), null).getTemplate());
assertEquals(1, loader.getLoadAttemptCount());
- assertNull(cache.getTemplate("t", Locale.getDefault(), null).getTemplate());
+ assertNull(tr.getTemplate("t", Locale.getDefault(), null).getTemplate());
// Still 1 - returned cached exception
assertEquals(1, loader.getLoadAttemptCount());
Thread.sleep(132L);
- assertNull(cache.getTemplate("t", Locale.getDefault(), null).getTemplate());
+ assertNull(tr.getTemplate("t", Locale.getDefault(), null).getTemplate());
// Cache had to retest
assertEquals(2, loader.getLoadAttemptCount());
}
@@ -211,69 +215,77 @@ public class DefaultTemplateResolverTest {
@Test
public void testZeroUpdateDelay() throws Exception {
MonitoredTemplateLoader loader = new MonitoredTemplateLoader();
- TestConfigurationBuilder cfgB = new TestConfigurationBuilder()
- .cacheStorage(new StrongCacheStorage())
- .templateLoader(loader)
- .templateUpdateDelayMilliseconds(0);
- Configuration cfg = cfgB.build();
+ {
+ Configuration cfg = new TestConfigurationBuilder()
+ .cacheStorage(new StrongCacheStorage())
+ .templateLoader(loader)
+ .templateUpdateDelayMilliseconds(0L)
+ .build();
+ for (int i = 1; i <= 3; i++) {
+ loader.putTextTemplate("t.ftl", "v" + i);
+ assertEquals("v" + i, cfg.getTemplate("t.ftl").toString());
+ }
+
+ loader.clearEvents();
+ loader.putTextTemplate("t.ftl", "v8");
+ assertEquals("v8", cfg.getTemplate("t.ftl").toString());
+ assertEquals("v8", cfg.getTemplate("t.ftl").toString());
+ loader.putTextTemplate("t.ftl", "v9");
+ assertEquals("v9", cfg.getTemplate("t.ftl").toString());
+ assertEquals("v9", cfg.getTemplate("t.ftl").toString());
+ assertEquals(
+ ImmutableList.of(
+ new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v8
+ new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED),
- for (int i = 1; i <= 3; i++) {
- loader.putTextTemplate("t.ftl", "v" + i);
- assertEquals("v" + i, cfg.getTemplate("t.ftl").toString());
- }
+ new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v8
+ new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
- loader.clearEvents();
- loader.putTextTemplate("t.ftl", "v8");
- assertEquals("v8", cfg.getTemplate("t.ftl").toString());
- assertEquals("v8", cfg.getTemplate("t.ftl").toString());
- loader.putTextTemplate("t.ftl", "v9");
- assertEquals("v9", cfg.getTemplate("t.ftl").toString());
- assertEquals("v9", cfg.getTemplate("t.ftl").toString());
- assertEquals(
- ImmutableList.of(
- new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v8
- new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED),
+ new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v9
+ new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED),
- new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v8
- new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
-
- new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v9
- new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED),
+ new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v9
+ new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED)
+ ),
+ loader.getEvents(LoadEvent.class));
+ }
- new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v9
- new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED)
- ),
- loader.getEvents(LoadEvent.class));
-
- cfg = cfgB.localizedLookup(false).build();
- loader.clearEvents();
- loader.putTextTemplate("t.ftl", "v10");
- assertEquals("v10", cfg.getTemplate("t.ftl").toString());
- loader.putTextTemplate("t.ftl", "v11"); // same time stamp, different content
- assertEquals("v11", cfg.getTemplate("t.ftl").toString());
- assertEquals("v11", cfg.getTemplate("t.ftl").toString());
- assertEquals("v11", cfg.getTemplate("t.ftl").toString());
- Thread.sleep(17L);
- assertEquals("v11", cfg.getTemplate("t.ftl").toString());
- loader.putTextTemplate("t.ftl", "v12");
- assertEquals("v12", cfg.getTemplate("t.ftl").toString());
- assertEquals("v12", cfg.getTemplate("t.ftl").toString());
- assertEquals(
- ImmutableList.of(
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v10
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v11
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v12
- new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED)
- ),
- loader.getEvents(LoadEvent.class));
+ {
+ Configuration cfg = new TestConfigurationBuilder()
+ .cacheStorage(new StrongCacheStorage())
+ .templateLoader(loader)
+ .templateUpdateDelayMilliseconds(0L)
+ .localizedLookup(false)
+ .build();
+ loader.clearEvents();
+ loader.putTextTemplate("t.ftl", "v10");
+ assertEquals("v10", cfg.getTemplate("t.ftl").toString());
+ loader.putTextTemplate("t.ftl", "v11"); // same time stamp, different content
+ assertEquals("v11", cfg.getTemplate("t.ftl").toString());
+ assertEquals("v11", cfg.getTemplate("t.ftl").toString());
+ assertEquals("v11", cfg.getTemplate("t.ftl").toString());
+ Thread.sleep(17L);
+ assertEquals("v11", cfg.getTemplate("t.ftl").toString());
+ loader.putTextTemplate("t.ftl", "v12");
+ assertEquals("v12", cfg.getTemplate("t.ftl").toString());
+ assertEquals("v12", cfg.getTemplate("t.ftl").toString());
+ assertEquals(
+ ImmutableList.of(
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v10
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v11
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v12
+ new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED)
+ ),
+ loader.getEvents(LoadEvent.class));
+ }
}
@Test
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/8915ac9b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
index 76c0bfc..9637205 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
@@ -276,15 +276,14 @@ public class ExtendedDecimalFormatTest extends TemplateTest {
@Test
public void testTemplates() throws IOException, TemplateException {
- TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
-
- setConfiguration(cfgB.numberFormat(",000.#").build());
+ setConfiguration(new TestConfigurationBuilder().numberFormat(",000.#").build());
assertOutput("${1000.15} ${1000.25}", "1,000.2 1,000.2");
- setConfiguration(cfgB.numberFormat(",000.#;; roundingMode=halfUp groupingSeparator=_").build());;
+ String numberFormat = ",000.#;; roundingMode=halfUp groupingSeparator=_";
+ setConfiguration(new TestConfigurationBuilder().numberFormat(numberFormat).build());;
assertOutput("${1000.15} ${1000.25}", "1_000.2 1_000.3");
- setConfiguration(cfgB.locale(Locale.GERMANY).build());;
+ setConfiguration(new TestConfigurationBuilder().numberFormat(numberFormat).locale(Locale.GERMANY).build());;
assertOutput("${1000.15} ${1000.25}", "1_000,2 1_000,3");
- setConfiguration(cfgB.locale(Locale.US).build());;
+ setConfiguration(new TestConfigurationBuilder().numberFormat(numberFormat).locale(Locale.US).build());;
assertOutput(
"${1000.15}; "
+ "${1000.15?string(',##.#;;groupingSeparator=\" \"')}; "