diff --git a/src/main/java/com/hubspot/jinjava/el/NoInvokeELResolver.java b/src/main/java/com/hubspot/jinjava/el/NoInvokeELResolver.java index cdc1030cb..41f2256c0 100644 --- a/src/main/java/com/hubspot/jinjava/el/NoInvokeELResolver.java +++ b/src/main/java/com/hubspot/jinjava/el/NoInvokeELResolver.java @@ -1,6 +1,6 @@ package com.hubspot.jinjava.el; -import com.hubspot.jinjava.el.ext.DeferredParsingException; +import com.hubspot.jinjava.interpret.DeferredValueException; import java.beans.FeatureDescriptor; import java.util.Iterator; import javax.el.ELContext; @@ -49,7 +49,7 @@ public boolean isReadOnly(ELContext elContext, Object base, Object property) { @Override public void setValue(ELContext elContext, Object base, Object property, Object value) { - throw new DeferredParsingException("NoInvokeELResolver"); + throw new DeferredValueException("NoInvokeELResolver"); } @Override @@ -60,6 +60,6 @@ public Object invoke( Class[] paramTypes, Object[] params ) { - throw new DeferredParsingException("NoInvokeELResolver"); + throw new DeferredValueException("NoInvokeELResolver"); } } diff --git a/src/main/java/com/hubspot/jinjava/el/ext/DeferredParsingException.java b/src/main/java/com/hubspot/jinjava/el/ext/DeferredParsingException.java index dc9314412..b03d1e6e0 100644 --- a/src/main/java/com/hubspot/jinjava/el/ext/DeferredParsingException.java +++ b/src/main/java/com/hubspot/jinjava/el/ext/DeferredParsingException.java @@ -8,13 +8,6 @@ public class DeferredParsingException extends DeferredValueException { private final Object sourceNode; private final IdentifierPreservationStrategy identifierPreservationStrategy; - public DeferredParsingException(String message) { - super(message); - this.deferredEvalResult = message; - this.sourceNode = null; - this.identifierPreservationStrategy = IdentifierPreservationStrategy.RESOLVING; - } - public DeferredParsingException(Object sourceNode, String deferredEvalResult) { super( String.format( diff --git a/src/main/java/com/hubspot/jinjava/el/ext/eager/RenderFlatTempVariable.java b/src/main/java/com/hubspot/jinjava/el/ext/eager/RenderFlatTempVariable.java new file mode 100644 index 000000000..682d3d5ca --- /dev/null +++ b/src/main/java/com/hubspot/jinjava/el/ext/eager/RenderFlatTempVariable.java @@ -0,0 +1,40 @@ +package com.hubspot.jinjava.el.ext.eager; + +import com.hubspot.jinjava.objects.serialization.PyishBlockSetSerializable; +import java.util.Objects; + +public class RenderFlatTempVariable implements PyishBlockSetSerializable { + + private static final String CONTEXT_KEY_PREFIX = "__render_%d_temp_variable__"; + private final String deferredResult; + + public RenderFlatTempVariable(String deferredResult) { + this.deferredResult = deferredResult; + } + + public static String getVarName(String result) { + return String.format(CONTEXT_KEY_PREFIX, Math.abs(result.hashCode() >> 1)); + } + + @Override + public String getBlockSetBody() { + return deferredResult; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RenderFlatTempVariable that = (RenderFlatTempVariable) o; + return deferredResult.equals(that.deferredResult); + } + + @Override + public int hashCode() { + return Objects.hash(deferredResult); + } +} diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java index 0c98c982a..837c091ca 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java @@ -4,6 +4,8 @@ import com.hubspot.jinjava.doc.annotations.JinjavaDoc; import com.hubspot.jinjava.doc.annotations.JinjavaParam; import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; +import com.hubspot.jinjava.el.ext.DeferredInvocationResolutionException; +import com.hubspot.jinjava.el.ext.eager.RenderFlatTempVariable; import com.hubspot.jinjava.interpret.JinjavaInterpreter; import java.util.Objects; import org.apache.commons.lang3.math.NumberUtils; @@ -26,16 +28,29 @@ public String getName() { @Override public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { + int numDeferredTokensStart = interpreter.getContext().getDeferredTokens().size(); + String result; if (args.length > 0) { String firstArg = args[0]; - return interpreter.renderFlat( - Objects.toString(var), - NumberUtils.toLong( - firstArg, - JinjavaConfig.newBuilder().build().getMaxOutputSize() - ) - ); + result = + interpreter.renderFlat( + Objects.toString(var), + NumberUtils.toLong( + firstArg, + JinjavaConfig.newBuilder().build().getMaxOutputSize() + ) + ); + } else { + result = interpreter.renderFlat(Objects.toString(var)); } - return interpreter.renderFlat(Objects.toString(var)); + if (interpreter.getContext().getDeferredTokens().size() > numDeferredTokensStart) { + String tempVarName = RenderFlatTempVariable.getVarName(result); + interpreter + .getContext() + .getParent() + .put(tempVarName, new RenderFlatTempVariable(result)); + throw new DeferredInvocationResolutionException(tempVarName); + } + return result; } } diff --git a/src/main/java/com/hubspot/jinjava/lib/tag/ForTag.java b/src/main/java/com/hubspot/jinjava/lib/tag/ForTag.java index 6f79cb68d..b8753539d 100644 --- a/src/main/java/com/hubspot/jinjava/lib/tag/ForTag.java +++ b/src/main/java/com/hubspot/jinjava/lib/tag/ForTag.java @@ -21,7 +21,6 @@ import com.hubspot.jinjava.doc.annotations.JinjavaParam; import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; import com.hubspot.jinjava.doc.annotations.JinjavaTextMateSnippet; -import com.hubspot.jinjava.el.ext.DeferredParsingException; import com.hubspot.jinjava.interpret.DeferredValue; import com.hubspot.jinjava.interpret.DeferredValueException; import com.hubspot.jinjava.interpret.InterpretException; @@ -143,15 +142,10 @@ public String interpretUnchecked(TagNode tagNode, JinjavaInterpreter interpreter List loopVars = loopVarsAndExpression.getLeft(); String loopExpression = loopVarsAndExpression.getRight(); - Object collection; - try { - collection = - interpreter.resolveELExpression(loopExpression, tagNode.getLineNumber()); - } catch (DeferredParsingException e) { - throw new DeferredParsingException( - String.format("%s in %s", String.join(", ", loopVars), e.getDeferredEvalResult()) - ); - } + Object collection = interpreter.resolveELExpression( + loopExpression, + tagNode.getLineNumber() + ); return renderForCollection(tagNode, interpreter, loopVars, collection); } diff --git a/src/main/java/com/hubspot/jinjava/random/DeferredRandomNumberGenerator.java b/src/main/java/com/hubspot/jinjava/random/DeferredRandomNumberGenerator.java index d7db11119..e0ebedda7 100644 --- a/src/main/java/com/hubspot/jinjava/random/DeferredRandomNumberGenerator.java +++ b/src/main/java/com/hubspot/jinjava/random/DeferredRandomNumberGenerator.java @@ -1,6 +1,6 @@ package com.hubspot.jinjava.random; -import com.hubspot.jinjava.el.ext.DeferredParsingException; +import com.hubspot.jinjava.interpret.DeferredValueException; import java.util.Random; import java.util.stream.DoubleStream; import java.util.stream.IntStream; @@ -15,42 +15,42 @@ public class DeferredRandomNumberGenerator extends Random { @Override protected int next(int bits) { - throw new DeferredParsingException(EXCEPTION_MESSAGE); + throw new DeferredValueException(EXCEPTION_MESSAGE); } @Override public int nextInt() { - throw new DeferredParsingException(EXCEPTION_MESSAGE); + throw new DeferredValueException(EXCEPTION_MESSAGE); } @Override public int nextInt(int bound) { - throw new DeferredParsingException(EXCEPTION_MESSAGE); + throw new DeferredValueException(EXCEPTION_MESSAGE); } @Override public long nextLong() { - throw new DeferredParsingException(EXCEPTION_MESSAGE); + throw new DeferredValueException(EXCEPTION_MESSAGE); } @Override public boolean nextBoolean() { - throw new DeferredParsingException(EXCEPTION_MESSAGE); + throw new DeferredValueException(EXCEPTION_MESSAGE); } @Override public float nextFloat() { - throw new DeferredParsingException(EXCEPTION_MESSAGE); + throw new DeferredValueException(EXCEPTION_MESSAGE); } @Override public double nextDouble() { - throw new DeferredParsingException(EXCEPTION_MESSAGE); + throw new DeferredValueException(EXCEPTION_MESSAGE); } @Override public synchronized double nextGaussian() { - throw new DeferredParsingException(EXCEPTION_MESSAGE); + throw new DeferredValueException(EXCEPTION_MESSAGE); } @Override diff --git a/src/test/java/com/hubspot/jinjava/EagerTest.java b/src/test/java/com/hubspot/jinjava/EagerTest.java index 7947f8ed4..be129aca8 100644 --- a/src/test/java/com/hubspot/jinjava/EagerTest.java +++ b/src/test/java/com/hubspot/jinjava/EagerTest.java @@ -1669,4 +1669,11 @@ public void itHandlesDeferredContinueInForLoop() { public void itReconstructsFromedMacro() { expectedTemplateInterpreter.assertExpectedOutput("reconstructs-fromed-macro/test"); } + + @Test + public void itHandlesDeferredValueInRenderFilter() { + expectedTemplateInterpreter.assertExpectedOutput( + "handles-deferred-value-in-render-filter/test" + ); + } } diff --git a/src/test/resources/eager/handles-deferred-value-in-render-filter/test.expected.jinja b/src/test/resources/eager/handles-deferred-value-in-render-filter/test.expected.jinja new file mode 100644 index 000000000..21a51dcc1 --- /dev/null +++ b/src/test/resources/eager/handles-deferred-value-in-render-filter/test.expected.jinja @@ -0,0 +1,9 @@ +{% set __render_524436216_temp_variable__ %}\ +Hi {{ filter:escape.filter(deferred, ____int3rpr3t3r____) }}\ +{% endset %}\ +{{ filter:escape_jinjava.filter(__render_524436216_temp_variable__, ____int3rpr3t3r____) }} + +{% set __render_524436216_temp_variable__ %}\ +Hi {{ filter:escape.filter(deferred, ____int3rpr3t3r____) }}\ +{% endset %}\ +{{ __render_524436216_temp_variable__ }} \ No newline at end of file diff --git a/src/test/resources/eager/handles-deferred-value-in-render-filter/test.jinja b/src/test/resources/eager/handles-deferred-value-in-render-filter/test.jinja new file mode 100644 index 000000000..25c5adf9d --- /dev/null +++ b/src/test/resources/eager/handles-deferred-value-in-render-filter/test.jinja @@ -0,0 +1,4 @@ +{% set foo = "Hi {{ deferred|escape }}" %} +{{ foo|render|escape_jinjava }} + +{{ foo|render }} \ No newline at end of file