diff --git a/README.md b/README.md index 7489e5273..e1285fa37 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ You will likely want to provide your own implementation of `ResourceLoader` to hook into your application's template repository, and then tell jinjava about it: ```java -JinjavaConfig config = new JinjavaConfig(); +JinjavaConfig config = JinjavaConfig.builder().build(); Jinjava jinjava = new Jinjava(config); jinjava.setResourceLocator(new MyCustomResourceLocator()); @@ -87,7 +87,7 @@ jinjava.setResourceLocator(new MyCustomResourceLocator()); To use more than one `ResourceLocator`, use a `CascadingResourceLocator`. ```java -JinjavaConfig config = new JinjavaConfig(); +JinjavaConfig config = JinjavaConfig.builder().build(); Jinjava jinjava = new Jinjava(config); jinjava.setResourceLocator(new MyCustomResourceLocator(), new FileResourceLocator()); diff --git a/pom.xml b/pom.xml index 27b09a6e3..4f50a5f71 100644 --- a/pom.xml +++ b/pom.xml @@ -184,6 +184,7 @@ com.google.errorprone error_prone_annotations + runtime @@ -216,19 +217,11 @@ value provided - - com.hubspot.immutables - hubspot-style - provided - - - com.hubspot.immutables - immutables-exceptions - com.hubspot algebra + diff --git a/src/main/java/com/hubspot/jinjava/Jinjava.java b/src/main/java/com/hubspot/jinjava/Jinjava.java index 8ef3f2153..a5d834b48 100644 --- a/src/main/java/com/hubspot/jinjava/Jinjava.java +++ b/src/main/java/com/hubspot/jinjava/Jinjava.java @@ -73,7 +73,7 @@ public class Jinjava { * Create a new Jinjava processor instance with the default global config */ public Jinjava() { - this(new JinjavaConfig()); + this(JinjavaConfig.builder().build()); } /** diff --git a/src/main/java/com/hubspot/jinjava/JinjavaConfig.java b/src/main/java/com/hubspot/jinjava/JinjavaConfig.java index 343df63a8..4f1887272 100644 --- a/src/main/java/com/hubspot/jinjava/JinjavaConfig.java +++ b/src/main/java/com/hubspot/jinjava/JinjavaConfig.java @@ -20,14 +20,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import com.google.common.collect.ImmutableSet; import com.hubspot.jinjava.el.JinjavaInterpreterResolver; import com.hubspot.jinjava.el.JinjavaObjectUnwrapper; import com.hubspot.jinjava.el.JinjavaProcessors; import com.hubspot.jinjava.el.ObjectUnwrapper; import com.hubspot.jinjava.features.FeatureConfig; import com.hubspot.jinjava.features.Features; -import com.hubspot.jinjava.interpret.Context; import com.hubspot.jinjava.interpret.Context.Library; import com.hubspot.jinjava.interpret.InterpreterFactory; import com.hubspot.jinjava.interpret.JinjavaInterpreter; @@ -44,533 +42,203 @@ import java.nio.charset.StandardCharsets; import java.time.ZoneId; import java.time.ZoneOffset; -import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.BiConsumer; -import javax.annotation.Nullable; import javax.el.ELResolver; +import org.immutables.value.Value; -public class JinjavaConfig { - - private final Charset charset; - private final Locale locale; - private final ZoneId timeZone; - private final int maxRenderDepth; - private final long maxOutputSize; - - private final boolean trimBlocks; - private final boolean lstripBlocks; - - private final boolean enableRecursiveMacroCalls; - private final int maxMacroRecursionDepth; - - private final Map> disabled; - - private final Set restrictedMethods; - - private final Set restrictedProperties; - - private final boolean failOnUnknownTokens; - private final boolean nestedInterpretationEnabled; - private final RandomNumberGeneratorStrategy randomNumberGenerator; - private final boolean validationMode; - private final long maxStringLength; - private final int maxListSize; - private final int maxMapSize; - private final int rangeLimit; - private final int maxNumDeferredTokens; - private final InterpreterFactory interpreterFactory; - private final DateTimeProvider dateTimeProvider; - private TokenScannerSymbols tokenScannerSymbols; - private final ELResolver elResolver; - private final ExecutionMode executionMode; - private final LegacyOverrides legacyOverrides; - private final boolean enablePreciseDivideFilter; - private final boolean enableFilterChainOptimization; - private final ObjectMapper objectMapper; - - private final Features features; - - private final ObjectUnwrapper objectUnwrapper; - private final JinjavaProcessors processors; - - public static Builder newBuilder() { - return new Builder(); +@Value.Immutable(singleton = true) +@JinjavaImmutableStyle.WithStyle +public interface JinjavaConfig { + @Value.Default + default Charset getCharset() { + return StandardCharsets.UTF_8; } - public JinjavaConfig() { - this(newBuilder()); - } - - public JinjavaConfig(InterpreterFactory interpreterFactory) { - this(newBuilder().withInterperterFactory(interpreterFactory)); - } - - public JinjavaConfig( - Charset charset, - Locale locale, - ZoneId timeZone, - int maxRenderDepth - ) { - this( - newBuilder() - .withCharset(charset) - .withLocale(locale) - .withTimeZone(timeZone) - .withMaxRenderDepth(maxRenderDepth) - ); - } - - private JinjavaConfig(Builder builder) { - charset = builder.charset; - locale = builder.locale; - timeZone = builder.timeZone; - maxRenderDepth = builder.maxRenderDepth; - disabled = builder.disabled; - restrictedMethods = builder.restrictedMethods; - restrictedProperties = builder.restrictedProperties; - trimBlocks = builder.trimBlocks; - lstripBlocks = builder.lstripBlocks; - enableRecursiveMacroCalls = builder.enableRecursiveMacroCalls; - maxMacroRecursionDepth = builder.maxMacroRecursionDepth; - failOnUnknownTokens = builder.failOnUnknownTokens; - maxOutputSize = builder.maxOutputSize; - nestedInterpretationEnabled = builder.nestedInterpretationEnabled; - randomNumberGenerator = builder.randomNumberGeneratorStrategy; - validationMode = builder.validationMode; - maxStringLength = builder.maxStringLength; - maxListSize = builder.maxListSize; - maxMapSize = builder.maxMapSize; - rangeLimit = builder.rangeLimit; - maxNumDeferredTokens = builder.maxNumDeferredTokens; - interpreterFactory = builder.interpreterFactory; - tokenScannerSymbols = builder.tokenScannerSymbols; - elResolver = builder.elResolver; - executionMode = builder.executionMode; - legacyOverrides = builder.legacyOverrides; - dateTimeProvider = builder.dateTimeProvider; - enablePreciseDivideFilter = builder.enablePreciseDivideFilter; - enableFilterChainOptimization = builder.enableFilterChainOptimization; - objectMapper = setupObjectMapper(builder.objectMapper); - objectUnwrapper = builder.objectUnwrapper; - processors = builder.processors; - features = new Features(builder.featureConfig); - } - - private ObjectMapper setupObjectMapper(@Nullable ObjectMapper objectMapper) { - if (objectMapper == null) { - objectMapper = new ObjectMapper().registerModule(new Jdk8Module()); - if (legacyOverrides.isUseSnakeCasePropertyNaming()) { - objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); - } - } - return objectMapper; + @Value.Default + default Locale getLocale() { + return Locale.ENGLISH; } - public Charset getCharset() { - return charset; + @Value.Default + default ZoneId getTimeZone() { + return ZoneOffset.UTC; } - public Locale getLocale() { - return locale; + @Value.Default + default int getMaxRenderDepth() { + return 10; } - public ZoneId getTimeZone() { - return timeZone; + @Value.Default + default long getMaxOutputSize() { + return 0; } - public int getMaxRenderDepth() { - return maxRenderDepth; + @Value.Default + default boolean isTrimBlocks() { + return false; } - public long getMaxOutputSize() { - return maxOutputSize; + @Value.Default + default boolean isLstripBlocks() { + return false; } - public int getMaxListSize() { - return maxListSize; + @Value.Default + default boolean isEnableRecursiveMacroCalls() { + return false; } - public int getMaxMapSize() { - return maxMapSize; + @Value.Default + default int getMaxMacroRecursionDepth() { + return 0; } - public int getRangeLimit() { - return rangeLimit; - } + Map> getDisabled(); + Set getRestrictedMethods(); + Set getRestrictedProperties(); - public int getMaxNumDeferredTokens() { - return maxNumDeferredTokens; + @Value.Default + default boolean isFailOnUnknownTokens() { + return false; } - public RandomNumberGeneratorStrategy getRandomNumberGeneratorStrategy() { - return randomNumberGenerator; + @Value.Default + default boolean isNestedInterpretationEnabled() { + return true; } - public boolean isTrimBlocks() { - return trimBlocks; + @Value.Default + default RandomNumberGeneratorStrategy getRandomNumberGeneratorStrategy() { + return RandomNumberGeneratorStrategy.THREAD_LOCAL; } - public boolean isLstripBlocks() { - return lstripBlocks; + @Value.Default + default boolean isValidationMode() { + return false; } - public boolean isEnableRecursiveMacroCalls() { - return enableRecursiveMacroCalls; + @Value.Default + default long getMaxStringLength() { + return getMaxOutputSize(); } - public int getMaxMacroRecursionDepth() { - return maxMacroRecursionDepth; + @Value.Default + default int getMaxListSize() { + return Integer.MAX_VALUE; } - public Map> getDisabled() { - return disabled; + @Value.Default + default int getMaxMapSize() { + return Integer.MAX_VALUE; } - public Set getRestrictedMethods() { - return restrictedMethods; + @Value.Default + default int getRangeLimit() { + return DEFAULT_RANGE_LIMIT; } - public Set getRestrictedProperties() { - return restrictedProperties; + @Value.Default + default int getMaxNumDeferredTokens() { + return 1000; } - public boolean isFailOnUnknownTokens() { - return failOnUnknownTokens; + @Value.Default + default InterpreterFactory getInterpreterFactory() { + return new JinjavaInterpreterFactory(); } - public boolean isNestedInterpretationEnabled() { - return nestedInterpretationEnabled; + @Value.Default + default DateTimeProvider getDateTimeProvider() { + return new CurrentDateTimeProvider(); } - public boolean isValidationMode() { - return validationMode; + @Value.Default + default TokenScannerSymbols getTokenScannerSymbols() { + return new DefaultTokenScannerSymbols(); } - public long getMaxStringLength() { - return maxStringLength == 0 ? getMaxOutputSize() : maxStringLength; + @Value.Default + default ELResolver getElResolver() { + return isDefaultReadOnlyResolver() + ? JinjavaInterpreterResolver.DEFAULT_RESOLVER_READ_ONLY + : JinjavaInterpreterResolver.DEFAULT_RESOLVER_READ_WRITE; } - public InterpreterFactory getInterpreterFactory() { - return interpreterFactory; + @Value.Default + default boolean isDefaultReadOnlyResolver() { + return true; } - public TokenScannerSymbols getTokenScannerSymbols() { - return tokenScannerSymbols; + @Value.Default + default ExecutionMode getExecutionMode() { + return DefaultExecutionMode.instance(); } - public void setTokenScannerSymbols(TokenScannerSymbols tokenScannerSymbols) { - this.tokenScannerSymbols = tokenScannerSymbols; + @Value.Default + default LegacyOverrides getLegacyOverrides() { + return LegacyOverrides.NONE; } - public ELResolver getElResolver() { - return elResolver; + @Value.Default + default boolean getEnablePreciseDivideFilter() { + return false; } - public ObjectMapper getObjectMapper() { - return objectMapper; - } - - public ObjectUnwrapper getObjectUnwrapper() { - return objectUnwrapper; + @Value.Default + default boolean isEnableFilterChainOptimization() { + return false; } - /** - * @deprecated Use {@link #getProcessors()} and {@link JinjavaProcessors#getNodePreProcessor()} - */ - @Deprecated - public BiConsumer getNodePreProcessor() { - return processors.getNodePreProcessor(); + @Value.Default + default ObjectMapper getObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper().registerModule(new Jdk8Module()); + if (getLegacyOverrides().isUseSnakeCasePropertyNaming()) { + objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); + } + return objectMapper; } - public JinjavaProcessors getProcessors() { - return processors; + @Value.Default + default ObjectUnwrapper getObjectUnwrapper() { + return new JinjavaObjectUnwrapper(); } - /** - * @deprecated Replaced by {@link LegacyOverrides#isIterateOverMapKeys()} - */ - @Deprecated - public boolean isIterateOverMapKeys() { - return legacyOverrides.isIterateOverMapKeys(); + @Value.Derived + default Features getFeatures() { + return new Features(getFeatureConfig()); } - public ExecutionMode getExecutionMode() { - return executionMode; + @Value.Default + default FeatureConfig getFeatureConfig() { + return FeatureConfig.newBuilder().build(); } - public LegacyOverrides getLegacyOverrides() { - return legacyOverrides; + @Value.Default + default JinjavaProcessors getProcessors() { + return JinjavaProcessors.newBuilder().build(); } - public boolean getEnablePreciseDivideFilter() { - return enablePreciseDivideFilter; + @Deprecated + default BiConsumer getNodePreProcessor() { + return getProcessors().getNodePreProcessor(); } - public boolean isEnableFilterChainOptimization() { - return enableFilterChainOptimization; + @Deprecated + default boolean isIterateOverMapKeys() { + return getLegacyOverrides().isIterateOverMapKeys(); } - public DateTimeProvider getDateTimeProvider() { - return dateTimeProvider; - } + class Builder extends ImmutableJinjavaConfig.Builder {} - public Features getFeatures() { - return features; + static Builder builder() { + return new Builder(); } - public static class Builder { - - private Charset charset = StandardCharsets.UTF_8; - private Locale locale = Locale.ENGLISH; - private ZoneId timeZone = ZoneOffset.UTC; - private int maxRenderDepth = 10; - private long maxOutputSize = 0; // in bytes - private Map> disabled = new HashMap<>(); - - private Set restrictedMethods = ImmutableSet.of(); - private Set restrictedProperties = ImmutableSet.of(); - - private boolean trimBlocks; - private boolean lstripBlocks; - - private boolean enableRecursiveMacroCalls; - private int maxMacroRecursionDepth; - private boolean failOnUnknownTokens; - private boolean nestedInterpretationEnabled = true; - private RandomNumberGeneratorStrategy randomNumberGeneratorStrategy = - RandomNumberGeneratorStrategy.THREAD_LOCAL; - private DateTimeProvider dateTimeProvider = new CurrentDateTimeProvider(); - private boolean validationMode = false; - private long maxStringLength = 0; - private int rangeLimit = DEFAULT_RANGE_LIMIT; - private int maxNumDeferredTokens = 1000; - private InterpreterFactory interpreterFactory = new JinjavaInterpreterFactory(); - private TokenScannerSymbols tokenScannerSymbols = new DefaultTokenScannerSymbols(); - private ELResolver elResolver = JinjavaInterpreterResolver.DEFAULT_RESOLVER_READ_ONLY; - private int maxListSize = Integer.MAX_VALUE; - private int maxMapSize = Integer.MAX_VALUE; - private ExecutionMode executionMode = DefaultExecutionMode.instance(); - private LegacyOverrides legacyOverrides = LegacyOverrides.NONE; - private boolean enablePreciseDivideFilter = false; - private boolean enableFilterChainOptimization = false; - private ObjectMapper objectMapper = null; - - private ObjectUnwrapper objectUnwrapper = new JinjavaObjectUnwrapper(); - private JinjavaProcessors processors = JinjavaProcessors.newBuilder().build(); - private FeatureConfig featureConfig = FeatureConfig.newBuilder().build(); - - private Builder() {} - - public Builder withCharset(Charset charset) { - this.charset = charset; - return this; - } - - public Builder withLocale(Locale locale) { - this.locale = locale; - return this; - } - - public Builder withTimeZone(ZoneId timeZone) { - this.timeZone = timeZone; - return this; - } - - public Builder withDisabled(Map> disabled) { - this.disabled = disabled; - return this; - } - - public Builder withRestrictedMethods(Set restrictedMethods) { - this.restrictedMethods = ImmutableSet.copyOf(restrictedMethods); - return this; - } - - public Builder withRestrictedProperties(Set restrictedProperties) { - this.restrictedProperties = ImmutableSet.copyOf(restrictedProperties); - return this; - } - - public Builder withMaxRenderDepth(int maxRenderDepth) { - this.maxRenderDepth = maxRenderDepth; - return this; - } - - public Builder withRandomNumberGeneratorStrategy( - RandomNumberGeneratorStrategy randomNumberGeneratorStrategy - ) { - this.randomNumberGeneratorStrategy = randomNumberGeneratorStrategy; - return this; - } - - public Builder withDateTimeProvider(DateTimeProvider dateTimeProvider) { - this.dateTimeProvider = dateTimeProvider; - return this; - } - - public Builder withTrimBlocks(boolean trimBlocks) { - this.trimBlocks = trimBlocks; - return this; - } - - public Builder withLstripBlocks(boolean lstripBlocks) { - this.lstripBlocks = lstripBlocks; - return this; - } - - public Builder withEnableRecursiveMacroCalls(boolean enableRecursiveMacroCalls) { - this.enableRecursiveMacroCalls = enableRecursiveMacroCalls; - return this; - } - - public Builder withMaxMacroRecursionDepth(int maxMacroRecursionDepth) { - this.maxMacroRecursionDepth = maxMacroRecursionDepth; - return this; - } - - public Builder withReadOnlyResolver(boolean readOnlyResolver) { - this.elResolver = - readOnlyResolver - ? JinjavaInterpreterResolver.DEFAULT_RESOLVER_READ_ONLY - : JinjavaInterpreterResolver.DEFAULT_RESOLVER_READ_WRITE; - return this; - } - - public Builder withElResolver(ELResolver elResolver) { - this.elResolver = elResolver; - return this; - } - - public Builder withFailOnUnknownTokens(boolean failOnUnknownTokens) { - this.failOnUnknownTokens = failOnUnknownTokens; - return this; - } - - public Builder withMaxOutputSize(long maxOutputSize) { - this.maxOutputSize = maxOutputSize; - return this; - } - - public Builder withNestedInterpretationEnabled(boolean nestedInterpretationEnabled) { - this.nestedInterpretationEnabled = nestedInterpretationEnabled; - return this; - } - - public Builder withValidationMode(boolean validationMode) { - this.validationMode = validationMode; - return this; - } - - public Builder withMaxStringLength(long maxStringLength) { - this.maxStringLength = maxStringLength; - return this; - } - - public Builder withMaxListSize(int maxListSize) { - this.maxListSize = maxListSize; - return this; - } - - public Builder withMaxMapSize(int maxMapSize) { - this.maxMapSize = maxMapSize; - return this; - } - - public Builder withRangeLimit(int rangeLimit) { - this.rangeLimit = rangeLimit; - return this; - } - - public Builder withMaxNumDeferredTokens(int maxNumDeferredTokens) { - this.maxNumDeferredTokens = maxNumDeferredTokens; - return this; - } - - public Builder withInterperterFactory(InterpreterFactory interperterFactory) { - this.interpreterFactory = interperterFactory; - return this; - } - - public Builder withTokenScannerSymbols(TokenScannerSymbols tokenScannerSymbols) { - this.tokenScannerSymbols = tokenScannerSymbols; - return this; - } - - /** - * @deprecated Replaced by {@link LegacyOverrides.Builder#withIterateOverMapKeys(boolean)}} - */ - @Deprecated - public Builder withIterateOverMapKeys(boolean iterateOverMapKeys) { - return withLegacyOverrides( - LegacyOverrides.Builder - .from(legacyOverrides) - .withIterateOverMapKeys(iterateOverMapKeys) - .build() - ); - } - - public Builder withExecutionMode(ExecutionMode executionMode) { - this.executionMode = executionMode; - return this; - } - - public Builder withLegacyOverrides(LegacyOverrides legacyOverrides) { - this.legacyOverrides = legacyOverrides; - return this; - } - - public Builder withEnablePreciseDivideFilter(boolean enablePreciseDivideFilter) { - this.enablePreciseDivideFilter = enablePreciseDivideFilter; - return this; - } - - public Builder withEnableFilterChainOptimization( - boolean enableFilterChainOptimization - ) { - this.enableFilterChainOptimization = enableFilterChainOptimization; - return this; - } - - public Builder withObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - public Builder withObjectUnwrapper(ObjectUnwrapper objectUnwrapper) { - this.objectUnwrapper = objectUnwrapper; - return this; - } - - @Deprecated - /** - * @deprecated use {@link #withProcessors(JinjavaProcessors)} - */ - public Builder withNodePreProcessor( - BiConsumer nodePreProcessor - ) { - this.processors = - JinjavaProcessors - .newBuilder(processors) - .withNodePreProcessor(nodePreProcessor) - .build(); - return this; - } - - public Builder withProcessors(JinjavaProcessors jinjavaProcessors) { - this.processors = jinjavaProcessors; - return this; - } - - public Builder withFeatureConfig(FeatureConfig featureConfig) { - this.featureConfig = featureConfig; - return this; - } - - public JinjavaConfig build() { - return new JinjavaConfig(this); - } + static Builder newBuilder() { + return builder(); } } diff --git a/src/main/java/com/hubspot/jinjava/JinjavaImmutableStyle.java b/src/main/java/com/hubspot/jinjava/JinjavaImmutableStyle.java new file mode 100644 index 000000000..4a38d3789 --- /dev/null +++ b/src/main/java/com/hubspot/jinjava/JinjavaImmutableStyle.java @@ -0,0 +1,16 @@ +package com.hubspot.jinjava; + +import org.immutables.value.Value; + +@Value.Style( + init = "set*", + get = { "is*", "get*" } // Detect 'get' and 'is' prefixes in accessor methods +) +public @interface JinjavaImmutableStyle { + @Value.Style( + init = "with*", + get = { "is*", "get*" } // Detect 'get' and 'is' prefixes in accessor methods + ) + @interface WithStyle { + } +} diff --git a/src/main/java/com/hubspot/jinjava/LegacyOverrides.java b/src/main/java/com/hubspot/jinjava/LegacyOverrides.java index 0cb6e661a..9d3e7ebe7 100644 --- a/src/main/java/com/hubspot/jinjava/LegacyOverrides.java +++ b/src/main/java/com/hubspot/jinjava/LegacyOverrides.java @@ -1,14 +1,17 @@ package com.hubspot.jinjava; +import org.immutables.value.Value; + /** * This class allows Jinjava to be configured to override legacy behaviour. * LegacyOverrides.NONE signifies that none of the legacy functionality will be overridden. * LegacyOverrides.ALL signifies that all new functionality will be used; avoid legacy "bugs". */ -public class LegacyOverrides { - - public static final LegacyOverrides NONE = new LegacyOverrides.Builder().build(); - public static final LegacyOverrides ALL = new LegacyOverrides.Builder() +@Value.Immutable(singleton = true) +@JinjavaImmutableStyle.WithStyle +public interface LegacyOverrides extends WithLegacyOverrides { + LegacyOverrides NONE = new Builder().build(); + LegacyOverrides ALL = new Builder() .withEvaluateMapKeys(true) .withIterateOverMapKeys(true) .withUsePyishObjectMapper(true) @@ -20,172 +23,64 @@ public class LegacyOverrides { .withUseTrimmingForNotesAndExpressions(true) .withKeepNullableLoopValues(true) .build(); - private final boolean evaluateMapKeys; - private final boolean iterateOverMapKeys; - private final boolean usePyishObjectMapper; - private final boolean useSnakeCasePropertyNaming; - private final boolean whitespaceRequiredWithinTokens; - private final boolean useNaturalOperatorPrecedence; - private final boolean parseWhitespaceControlStrictly; - private final boolean allowAdjacentTextNodes; - private final boolean useTrimmingForNotesAndExpressions; - private final boolean keepNullableLoopValues; - private LegacyOverrides(Builder builder) { - evaluateMapKeys = builder.evaluateMapKeys; - iterateOverMapKeys = builder.iterateOverMapKeys; - usePyishObjectMapper = builder.usePyishObjectMapper; - useSnakeCasePropertyNaming = builder.useSnakeCasePropertyNaming; - whitespaceRequiredWithinTokens = builder.whitespaceRequiredWithinTokens; - useNaturalOperatorPrecedence = builder.useNaturalOperatorPrecedence; - parseWhitespaceControlStrictly = builder.parseWhitespaceControlStrictly; - allowAdjacentTextNodes = builder.allowAdjacentTextNodes; - useTrimmingForNotesAndExpressions = builder.useTrimmingForNotesAndExpressions; - keepNullableLoopValues = builder.keepNullableLoopValues; + @Value.Default + default boolean isEvaluateMapKeys() { + return false; } - public static Builder newBuilder() { - return new Builder(); + @Value.Default + default boolean isIterateOverMapKeys() { + return false; } - public boolean isEvaluateMapKeys() { - return evaluateMapKeys; + @Value.Default + default boolean isUsePyishObjectMapper() { + return false; } - public boolean isIterateOverMapKeys() { - return iterateOverMapKeys; + @Value.Default + default boolean isUseSnakeCasePropertyNaming() { + return false; } - public boolean isUsePyishObjectMapper() { - return usePyishObjectMapper; + @Value.Default + default boolean isWhitespaceRequiredWithinTokens() { + return false; } - public boolean isUseSnakeCasePropertyNaming() { - return useSnakeCasePropertyNaming; + @Value.Default + default boolean isUseNaturalOperatorPrecedence() { + return false; } - public boolean isWhitespaceRequiredWithinTokens() { - return whitespaceRequiredWithinTokens; + @Value.Default + default boolean isParseWhitespaceControlStrictly() { + return false; } - public boolean isUseNaturalOperatorPrecedence() { - return useNaturalOperatorPrecedence; + @Value.Default + default boolean isAllowAdjacentTextNodes() { + return false; } - public boolean isParseWhitespaceControlStrictly() { - return parseWhitespaceControlStrictly; + @Value.Default + default boolean isUseTrimmingForNotesAndExpressions() { + return false; } - public boolean isAllowAdjacentTextNodes() { - return allowAdjacentTextNodes; + @Value.Default + default boolean isKeepNullableLoopValues() { + return false; } - public boolean isUseTrimmingForNotesAndExpressions() { - return useTrimmingForNotesAndExpressions; - } + class Builder extends ImmutableLegacyOverrides.Builder {} - public boolean isKeepNullableLoopValues() { - return keepNullableLoopValues; + static Builder newBuilder() { + return builder(); } - public static class Builder { - - private boolean evaluateMapKeys = false; - private boolean iterateOverMapKeys = false; - private boolean usePyishObjectMapper = false; - private boolean useSnakeCasePropertyNaming = false; - private boolean whitespaceRequiredWithinTokens = false; - private boolean useNaturalOperatorPrecedence = false; - private boolean parseWhitespaceControlStrictly = false; - private boolean allowAdjacentTextNodes = false; - private boolean useTrimmingForNotesAndExpressions = false; - private boolean keepNullableLoopValues = false; - - private Builder() {} - - public LegacyOverrides build() { - return new LegacyOverrides(this); - } - - public static Builder from(LegacyOverrides legacyOverrides) { - return new Builder() - .withEvaluateMapKeys(legacyOverrides.evaluateMapKeys) - .withIterateOverMapKeys(legacyOverrides.iterateOverMapKeys) - .withUsePyishObjectMapper(legacyOverrides.usePyishObjectMapper) - .withUseSnakeCasePropertyNaming(legacyOverrides.useSnakeCasePropertyNaming) - .withWhitespaceRequiredWithinTokens( - legacyOverrides.whitespaceRequiredWithinTokens - ) - .withUseNaturalOperatorPrecedence(legacyOverrides.useNaturalOperatorPrecedence) - .withParseWhitespaceControlStrictly( - legacyOverrides.parseWhitespaceControlStrictly - ) - .withAllowAdjacentTextNodes(legacyOverrides.allowAdjacentTextNodes) - .withUseTrimmingForNotesAndExpressions( - legacyOverrides.useTrimmingForNotesAndExpressions - ); - } - - public Builder withEvaluateMapKeys(boolean evaluateMapKeys) { - this.evaluateMapKeys = evaluateMapKeys; - return this; - } - - public Builder withIterateOverMapKeys(boolean iterateOverMapKeys) { - this.iterateOverMapKeys = iterateOverMapKeys; - return this; - } - - public Builder withUsePyishObjectMapper(boolean usePyishObjectMapper) { - this.usePyishObjectMapper = usePyishObjectMapper; - return this; - } - - public Builder withUseSnakeCasePropertyNaming(boolean useSnakeCasePropertyNaming) { - this.useSnakeCasePropertyNaming = useSnakeCasePropertyNaming; - return this; - } - - /** - * Use {@link com.hubspot.jinjava.features.BuiltInFeatures#WHITESPACE_REQUIRED_WITHIN_TOKENS} instead - */ - @Deprecated - public Builder withWhitespaceRequiredWithinTokens( - boolean whitespaceRequiredWithinTokens - ) { - this.whitespaceRequiredWithinTokens = whitespaceRequiredWithinTokens; - return this; - } - - public Builder withUseNaturalOperatorPrecedence( - boolean useNaturalOperatorPrecedence - ) { - this.useNaturalOperatorPrecedence = useNaturalOperatorPrecedence; - return this; - } - - public Builder withParseWhitespaceControlStrictly( - boolean parseWhitespaceControlStrictly - ) { - this.parseWhitespaceControlStrictly = parseWhitespaceControlStrictly; - return this; - } - - public Builder withAllowAdjacentTextNodes(boolean allowAdjacentTextNodes) { - this.allowAdjacentTextNodes = allowAdjacentTextNodes; - return this; - } - - public Builder withUseTrimmingForNotesAndExpressions( - boolean useTrimmingForNotesAndExpressions - ) { - this.useTrimmingForNotesAndExpressions = useTrimmingForNotesAndExpressions; - return this; - } - - public Builder withKeepNullableLoopValues(boolean keepNullableLoopValues) { - this.keepNullableLoopValues = keepNullableLoopValues; - return this; - } + static Builder builder() { + return new Builder(); } } diff --git a/src/main/java/com/hubspot/jinjava/interpret/Context.java b/src/main/java/com/hubspot/jinjava/interpret/Context.java index a9892c060..a2d83f983 100644 --- a/src/main/java/com/hubspot/jinjava/interpret/Context.java +++ b/src/main/java/com/hubspot/jinjava/interpret/Context.java @@ -22,7 +22,6 @@ import com.google.common.collect.SetMultimap; import com.google.common.collect.Sets; import com.hubspot.jinjava.interpret.AutoCloseableSupplier.AutoCloseableImpl; -import com.hubspot.jinjava.interpret.ContextConfigurationIF.ErrorHandlingStrategyIF.TemplateErrorTypeHandlingStrategy; import com.hubspot.jinjava.lib.Importable; import com.hubspot.jinjava.lib.expression.ExpressionStrategy; import com.hubspot.jinjava.lib.exptest.ExpTest; @@ -796,7 +795,7 @@ public boolean getThrowInterpreterErrors() { ErrorHandlingStrategy errorHandlingStrategy = getErrorHandlingStrategy(); return ( errorHandlingStrategy.getFatalErrorStrategy() == - TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION + ErrorHandlingStrategy.TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION ); } @@ -808,13 +807,13 @@ public void setThrowInterpreterErrors(boolean throwInterpreterErrors) { .builder() .setFatalErrorStrategy( throwInterpreterErrors - ? TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION - : TemplateErrorTypeHandlingStrategy.ADD_ERROR + ? ErrorHandlingStrategy.TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION + : ErrorHandlingStrategy.TemplateErrorTypeHandlingStrategy.ADD_ERROR ) .setNonFatalErrorStrategy( throwInterpreterErrors - ? TemplateErrorTypeHandlingStrategy.IGNORE // Deprecated, warnings are ignored when doing eager expression resolving - : TemplateErrorTypeHandlingStrategy.ADD_ERROR + ? ErrorHandlingStrategy.TemplateErrorTypeHandlingStrategy.IGNORE // Deprecated, warnings are ignored when doing eager expression resolving + : ErrorHandlingStrategy.TemplateErrorTypeHandlingStrategy.ADD_ERROR ) .build() ); diff --git a/src/main/java/com/hubspot/jinjava/interpret/ContextConfiguration.java b/src/main/java/com/hubspot/jinjava/interpret/ContextConfiguration.java new file mode 100644 index 000000000..b902efdef --- /dev/null +++ b/src/main/java/com/hubspot/jinjava/interpret/ContextConfiguration.java @@ -0,0 +1,54 @@ +package com.hubspot.jinjava.interpret; + +import com.hubspot.jinjava.JinjavaImmutableStyle; +import com.hubspot.jinjava.lib.expression.DefaultExpressionStrategy; +import com.hubspot.jinjava.lib.expression.ExpressionStrategy; +import javax.annotation.Nullable; +import org.immutables.value.Value.Default; +import org.immutables.value.Value.Immutable; + +@Immutable(singleton = true) +@JinjavaImmutableStyle +public interface ContextConfiguration extends WithContextConfiguration { + @Default + default ExpressionStrategy getExpressionStrategy() { + return new DefaultExpressionStrategy(); + } + + @Nullable + DynamicVariableResolver getDynamicVariableResolver(); + + @Default + default boolean isValidationMode() { + return false; + } + + @Default + default boolean isDeferredExecutionMode() { + return false; + } + + @Default + default boolean isDeferLargeObjects() { + return false; + } + + @Default + default boolean isPartialMacroEvaluation() { + return false; + } + + @Default + default boolean isUnwrapRawOverride() { + return false; + } + + @Default + default ErrorHandlingStrategy getErrorHandlingStrategy() { + return ImmutableErrorHandlingStrategy.of(); + } + + static ContextConfiguration of() { + return ImmutableContextConfiguration.of(); + } +} diff --git a/src/main/java/com/hubspot/jinjava/interpret/ContextConfigurationIF.java b/src/main/java/com/hubspot/jinjava/interpret/ContextConfigurationIF.java deleted file mode 100644 index daefd5981..000000000 --- a/src/main/java/com/hubspot/jinjava/interpret/ContextConfigurationIF.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.hubspot.jinjava.interpret; - -import com.hubspot.immutables.style.HubSpotImmutableStyle; -import com.hubspot.jinjava.lib.expression.DefaultExpressionStrategy; -import com.hubspot.jinjava.lib.expression.ExpressionStrategy; -import javax.annotation.Nullable; -import org.immutables.value.Value.Default; -import org.immutables.value.Value.Immutable; - -@Immutable(singleton = true) -@HubSpotImmutableStyle -public interface ContextConfigurationIF { - @Default - default ExpressionStrategy getExpressionStrategy() { - return new DefaultExpressionStrategy(); - } - - @Nullable - DynamicVariableResolver getDynamicVariableResolver(); - - @Default - default boolean isValidationMode() { - return false; - } - - @Default - default boolean isDeferredExecutionMode() { - return false; - } - - @Default - default boolean isDeferLargeObjects() { - return false; - } - - @Default - default boolean isPartialMacroEvaluation() { - return false; - } - - @Default - default boolean isUnwrapRawOverride() { - return false; - } - - @Default - default ErrorHandlingStrategy getErrorHandlingStrategy() { - return ErrorHandlingStrategy.of(); - } - - @Immutable(singleton = true) - @HubSpotImmutableStyle - interface ErrorHandlingStrategyIF { - @Default - default TemplateErrorTypeHandlingStrategy getFatalErrorStrategy() { - return TemplateErrorTypeHandlingStrategy.ADD_ERROR; - } - - @Default - default TemplateErrorTypeHandlingStrategy getNonFatalErrorStrategy() { - return TemplateErrorTypeHandlingStrategy.ADD_ERROR; - } - - enum TemplateErrorTypeHandlingStrategy { - IGNORE, - ADD_ERROR, - THROW_EXCEPTION, - } - - static ErrorHandlingStrategy throwAll() { - return ErrorHandlingStrategy - .of() - .withFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION) - .withNonFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION); - } - - static ErrorHandlingStrategy ignoreAll() { - return ErrorHandlingStrategy - .of() - .withFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.IGNORE) - .withNonFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.IGNORE); - } - } -} diff --git a/src/main/java/com/hubspot/jinjava/interpret/ErrorHandlingStrategy.java b/src/main/java/com/hubspot/jinjava/interpret/ErrorHandlingStrategy.java new file mode 100644 index 000000000..23df9c977 --- /dev/null +++ b/src/main/java/com/hubspot/jinjava/interpret/ErrorHandlingStrategy.java @@ -0,0 +1,46 @@ +package com.hubspot.jinjava.interpret; + +import com.hubspot.jinjava.JinjavaImmutableStyle; +import org.immutables.value.Value; + +@Value.Immutable(singleton = true) +@JinjavaImmutableStyle +public interface ErrorHandlingStrategy { + @Value.Default + default TemplateErrorTypeHandlingStrategy getFatalErrorStrategy() { + return TemplateErrorTypeHandlingStrategy.ADD_ERROR; + } + + @Value.Default + default TemplateErrorTypeHandlingStrategy getNonFatalErrorStrategy() { + return TemplateErrorTypeHandlingStrategy.ADD_ERROR; + } + + enum TemplateErrorTypeHandlingStrategy { + IGNORE, + ADD_ERROR, + THROW_EXCEPTION, + } + + class Builder extends ImmutableErrorHandlingStrategy.Builder {} + + static Builder builder() { + return new Builder(); + } + + static ErrorHandlingStrategy throwAll() { + return ErrorHandlingStrategy + .builder() + .setFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION) + .setNonFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION) + .build(); + } + + static ErrorHandlingStrategy ignoreAll() { + return ErrorHandlingStrategy + .builder() + .setFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.IGNORE) + .setNonFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.IGNORE) + .build(); + } +} diff --git a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java index 3577a8729..22b404318 100644 --- a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java +++ b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java @@ -33,8 +33,6 @@ import com.hubspot.jinjava.features.BuiltInFeatures; import com.hubspot.jinjava.interpret.AutoCloseableSupplier.AutoCloseableImpl; import com.hubspot.jinjava.interpret.Context.TemporaryValueClosable; -import com.hubspot.jinjava.interpret.ContextConfigurationIF.ErrorHandlingStrategyIF; -import com.hubspot.jinjava.interpret.ContextConfigurationIF.ErrorHandlingStrategyIF.TemplateErrorTypeHandlingStrategy; import com.hubspot.jinjava.interpret.TemplateError.ErrorItem; import com.hubspot.jinjava.interpret.TemplateError.ErrorReason; import com.hubspot.jinjava.interpret.TemplateError.ErrorType; @@ -291,7 +289,7 @@ private TemporaryValueClosable ignoreParseErrorsIfActivat .getFeatures() .getActivationStrategy(BuiltInFeatures.IGNORE_NESTED_INTERPRETATION_PARSE_ERRORS) .isActive(context) - ? context.withErrorHandlingStrategy(ErrorHandlingStrategyIF.ignoreAll()) + ? context.withErrorHandlingStrategy(ErrorHandlingStrategy.ignoreAll()) : TemporaryValueClosable.noOp(); } @@ -868,7 +866,7 @@ public void addError(TemplateError templateError) { return; } ErrorHandlingStrategy errorHandlingStrategy = context.getErrorHandlingStrategy(); - TemplateErrorTypeHandlingStrategy errorTypeHandlingStrategy = + ErrorHandlingStrategy.TemplateErrorTypeHandlingStrategy errorTypeHandlingStrategy = templateError.getSeverity() == ErrorType.FATAL ? errorHandlingStrategy.getFatalErrorStrategy() : errorHandlingStrategy.getNonFatalErrorStrategy(); diff --git a/src/main/java/com/hubspot/jinjava/lib/expression/EagerExpressionStrategy.java b/src/main/java/com/hubspot/jinjava/lib/expression/EagerExpressionStrategy.java index c1f6d15b0..35a184f52 100644 --- a/src/main/java/com/hubspot/jinjava/lib/expression/EagerExpressionStrategy.java +++ b/src/main/java/com/hubspot/jinjava/lib/expression/EagerExpressionStrategy.java @@ -3,7 +3,6 @@ import com.google.common.annotations.Beta; import com.hubspot.jinjava.JinjavaConfig; import com.hubspot.jinjava.interpret.Context.TemporaryValueClosable; -import com.hubspot.jinjava.interpret.ContextConfigurationIF.ErrorHandlingStrategyIF; import com.hubspot.jinjava.interpret.ErrorHandlingStrategy; import com.hubspot.jinjava.interpret.JinjavaInterpreter; import com.hubspot.jinjava.interpret.TemplateSyntaxException; @@ -109,7 +108,7 @@ public static String postProcessResult( try ( TemporaryValueClosable c = interpreter .getContext() - .withErrorHandlingStrategy(ErrorHandlingStrategyIF.throwAll()) + .withErrorHandlingStrategy(ErrorHandlingStrategy.throwAll()) ) { interpreter.parse(result); } diff --git a/src/main/java/com/hubspot/jinjava/util/EagerExpressionResolver.java b/src/main/java/com/hubspot/jinjava/util/EagerExpressionResolver.java index a2efeeebc..88763eb73 100644 --- a/src/main/java/com/hubspot/jinjava/util/EagerExpressionResolver.java +++ b/src/main/java/com/hubspot/jinjava/util/EagerExpressionResolver.java @@ -6,7 +6,6 @@ import com.hubspot.jinjava.el.ext.DeferredParsingException; import com.hubspot.jinjava.el.ext.ExtendedParser; import com.hubspot.jinjava.interpret.Context.TemporaryValueClosable; -import com.hubspot.jinjava.interpret.ContextConfigurationIF.ErrorHandlingStrategyIF.TemplateErrorTypeHandlingStrategy; import com.hubspot.jinjava.interpret.DeferredValueException; import com.hubspot.jinjava.interpret.ErrorHandlingStrategy; import com.hubspot.jinjava.interpret.JinjavaInterpreter; @@ -132,8 +131,12 @@ public static Set findDeferredWords( .withErrorHandlingStrategy( ErrorHandlingStrategy .builder() - .setFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION) - .setNonFatalErrorStrategy(TemplateErrorTypeHandlingStrategy.IGNORE) + .setFatalErrorStrategy( + ErrorHandlingStrategy.TemplateErrorTypeHandlingStrategy.THROW_EXCEPTION + ) + .setNonFatalErrorStrategy( + ErrorHandlingStrategy.TemplateErrorTypeHandlingStrategy.IGNORE + ) .build() ) ) { diff --git a/src/test/java/com/hubspot/jinjava/lib/filter/FloatFilterTest.java b/src/test/java/com/hubspot/jinjava/lib/filter/FloatFilterTest.java index 82cd59a88..5d6011e42 100644 --- a/src/test/java/com/hubspot/jinjava/lib/filter/FloatFilterTest.java +++ b/src/test/java/com/hubspot/jinjava/lib/filter/FloatFilterTest.java @@ -30,12 +30,12 @@ public class FloatFilterTest extends BaseInterpretingTest { private static final Locale FRENCH_LOCALE = new Locale("fr", "FR"); - private static final JinjavaConfig FRENCH_LOCALE_CONFIG = new JinjavaConfig( - StandardCharsets.UTF_8, - FRENCH_LOCALE, - ZoneOffset.UTC, - 10 - ); + private static final JinjavaConfig FRENCH_LOCALE_CONFIG = JinjavaConfig + .builder() + .withCharset(StandardCharsets.UTF_8) + .withLocale(FRENCH_LOCALE) + .withTimeZone(ZoneOffset.UTC) + .build(); FloatFilter filter; diff --git a/src/test/java/com/hubspot/jinjava/lib/filter/IntFilterTest.java b/src/test/java/com/hubspot/jinjava/lib/filter/IntFilterTest.java index 65d2b4733..3874e5fb9 100644 --- a/src/test/java/com/hubspot/jinjava/lib/filter/IntFilterTest.java +++ b/src/test/java/com/hubspot/jinjava/lib/filter/IntFilterTest.java @@ -15,12 +15,12 @@ public class IntFilterTest extends BaseInterpretingTest { private static final Locale FRENCH_LOCALE = new Locale("fr", "FR"); - private static final JinjavaConfig FRENCH_LOCALE_CONFIG = new JinjavaConfig( - StandardCharsets.UTF_8, - FRENCH_LOCALE, - ZoneOffset.UTC, - 10 - ); + private static final JinjavaConfig FRENCH_LOCALE_CONFIG = JinjavaConfig + .builder() + .withCharset(StandardCharsets.UTF_8) + .withLocale(FRENCH_LOCALE) + .withTimeZone(ZoneOffset.UTC) + .build(); IntFilter filter; diff --git a/src/test/java/com/hubspot/jinjava/tree/TreeParserTest.java b/src/test/java/com/hubspot/jinjava/tree/TreeParserTest.java index c54a33735..74a3ed821 100644 --- a/src/test/java/com/hubspot/jinjava/tree/TreeParserTest.java +++ b/src/test/java/com/hubspot/jinjava/tree/TreeParserTest.java @@ -8,7 +8,6 @@ import com.hubspot.jinjava.JinjavaConfig; import com.hubspot.jinjava.LegacyOverrides; import com.hubspot.jinjava.interpret.Context.TemporaryValueClosable; -import com.hubspot.jinjava.interpret.ContextConfigurationIF.ErrorHandlingStrategyIF; import com.hubspot.jinjava.interpret.ErrorHandlingStrategy; import com.hubspot.jinjava.interpret.TemplateError.ErrorType; import java.nio.charset.StandardCharsets; @@ -381,7 +380,7 @@ public void itDoesNotAddErrorWhenParseErrorsAreIgnored() { try ( TemporaryValueClosable c = interpreter .getContext() - .withErrorHandlingStrategy(ErrorHandlingStrategyIF.ignoreAll()) + .withErrorHandlingStrategy(ErrorHandlingStrategy.ignoreAll()) ) { String expression = "{% if "; final Node tree = new TreeParser(interpreter, expression).buildTree(); diff --git a/src/test/java/com/hubspot/jinjava/util/ObjectIteratorTest.java b/src/test/java/com/hubspot/jinjava/util/ObjectIteratorTest.java index 82797da17..0d09183d3 100644 --- a/src/test/java/com/hubspot/jinjava/util/ObjectIteratorTest.java +++ b/src/test/java/com/hubspot/jinjava/util/ObjectIteratorTest.java @@ -20,6 +20,7 @@ import com.hubspot.jinjava.Jinjava; import com.hubspot.jinjava.JinjavaConfig; +import com.hubspot.jinjava.LegacyOverrides; import com.hubspot.jinjava.interpret.Context; import com.hubspot.jinjava.interpret.JinjavaInterpreter; import java.util.ArrayList; @@ -101,7 +102,7 @@ public void testItIteratesOverValues() { public void testItIteratesOverKeys() throws Exception { JinjavaConfig config = JinjavaConfig .newBuilder() - .withIterateOverMapKeys(true) + .withLegacyOverrides(LegacyOverrides.builder().withIterateOverMapKeys(true).build()) .build(); JinjavaInterpreter.pushCurrent( new JinjavaInterpreter(new Jinjava(), new Context(), config)