Skip to content

Commit 224e908

Browse files
committed
Make it so that you don't need to worry about pushing the interpreter if
using a JinjavaInterpreter directly
1 parent 098c895 commit 224e908

File tree

14 files changed

+288
-217
lines changed

14 files changed

+288
-217
lines changed

src/main/java/com/hubspot/jinjava/Jinjava.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import com.hubspot.jinjava.el.ExtendedSyntaxBuilder;
2121
import com.hubspot.jinjava.el.TruthyTypeConverter;
2222
import com.hubspot.jinjava.el.ext.eager.EagerExtendedSyntaxBuilder;
23-
import com.hubspot.jinjava.interpret.AutoCloseableSupplier.AutoCloseableImpl;
2423
import com.hubspot.jinjava.interpret.Context;
2524
import com.hubspot.jinjava.interpret.FatalTemplateErrorsException;
2625
import com.hubspot.jinjava.interpret.InterpretException;
@@ -246,14 +245,10 @@ public RenderResult renderForResult(
246245
context = new Context(copyGlobalContext(), bindings, renderConfig.getDisabled());
247246
}
248247

249-
try (
250-
AutoCloseableImpl<JinjavaInterpreter> interpreterAutoCloseable = JinjavaInterpreter
251-
.closeablePushCurrent(
252-
globalConfig.getInterpreterFactory().newInstance(this, context, renderConfig)
253-
)
254-
.get()
255-
) {
256-
JinjavaInterpreter interpreter = interpreterAutoCloseable.value();
248+
try {
249+
JinjavaInterpreter interpreter = globalConfig
250+
.getInterpreterFactory()
251+
.newInstance(this, context, renderConfig);
257252
try {
258253
String result = interpreter.render(template);
259254
return new RenderResult(

src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java

Lines changed: 160 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -355,170 +355,184 @@ public String render(Node root, boolean processExtendRoots) {
355355
* @return rendered result
356356
*/
357357
private String render(Node root, boolean processExtendRoots, long renderLimit) {
358-
OutputList output = new OutputList(
359-
RenderLimitUtils.clampProvidedRenderLimitToConfig(renderLimit, config)
360-
);
361-
for (Node node : root.getChildren()) {
362-
lineNumber = node.getLineNumber();
363-
position = node.getStartPosition();
364-
String renderStr = node.getMaster().getImage();
365-
try {
366-
if (node instanceof ExpressionNode && context.doesRenderStackContain(renderStr)) {
367-
// This is a circular rendering. Stop rendering it here.
368-
addError(
369-
new TemplateError(
370-
ErrorType.WARNING,
371-
ErrorReason.EXCEPTION,
372-
ErrorItem.TAG,
373-
"Rendering cycle detected: '" + renderStr + "'",
374-
null,
375-
getLineNumber(),
376-
node.getStartPosition(),
377-
null,
378-
BasicTemplateErrorCategory.IMPORT_CYCLE_DETECTED,
379-
ImmutableMap.of("string", renderStr)
380-
)
381-
);
382-
output.addNode(new RenderedOutputNode(renderStr));
383-
} else {
384-
OutputNode out;
385-
try (
386-
AutoCloseableImpl<String> closeable = context
387-
.closeablePushRenderStack(renderStr)
388-
.get()
358+
boolean pushed = false;
359+
//noinspection ErrorProne
360+
if (JinjavaInterpreter.getCurrent() != this) {
361+
JinjavaInterpreter.pushCurrent(this);
362+
pushed = true;
363+
}
364+
try {
365+
OutputList output = new OutputList(
366+
RenderLimitUtils.clampProvidedRenderLimitToConfig(renderLimit, config)
367+
);
368+
for (Node node : root.getChildren()) {
369+
lineNumber = node.getLineNumber();
370+
position = node.getStartPosition();
371+
String renderStr = node.getMaster().getImage();
372+
try {
373+
if (
374+
node instanceof ExpressionNode && context.doesRenderStackContain(renderStr)
389375
) {
390-
try {
391-
out = node.render(this);
392-
} catch (DeferredValueException e) {
393-
context.handleDeferredNode(node);
394-
out = new RenderedOutputNode(node.getMaster().getImage());
376+
// This is a circular rendering. Stop rendering it here.
377+
addError(
378+
new TemplateError(
379+
ErrorType.WARNING,
380+
ErrorReason.EXCEPTION,
381+
ErrorItem.TAG,
382+
"Rendering cycle detected: '" + renderStr + "'",
383+
null,
384+
getLineNumber(),
385+
node.getStartPosition(),
386+
null,
387+
BasicTemplateErrorCategory.IMPORT_CYCLE_DETECTED,
388+
ImmutableMap.of("string", renderStr)
389+
)
390+
);
391+
output.addNode(new RenderedOutputNode(renderStr));
392+
} else {
393+
OutputNode out;
394+
try (
395+
AutoCloseableImpl<String> closeable = context
396+
.closeablePushRenderStack(renderStr)
397+
.get()
398+
) {
399+
try {
400+
out = node.render(this);
401+
} catch (DeferredValueException e) {
402+
context.handleDeferredNode(node);
403+
out = new RenderedOutputNode(node.getMaster().getImage());
404+
}
395405
}
406+
output.addNode(out);
396407
}
397-
output.addNode(out);
398-
}
399-
} catch (OutputTooBigException e) {
400-
addError(TemplateError.fromOutputTooBigException(e));
401-
return output.getValue();
402-
} catch (CollectionTooBigException e) {
403-
addError(
404-
new TemplateError(
405-
ErrorType.FATAL,
406-
ErrorReason.COLLECTION_TOO_BIG,
407-
ErrorItem.OTHER,
408-
ExceptionUtils.getMessage(e),
409-
null,
410-
-1,
411-
-1,
412-
e,
413-
BasicTemplateErrorCategory.UNKNOWN,
414-
ImmutableMap.of()
415-
)
416-
);
417-
return output.getValue();
418-
}
419-
}
420-
DynamicRenderedOutputNode pathSetter = new DynamicRenderedOutputNode();
421-
output.addNode(pathSetter);
422-
Optional<String> basePath = context.getCurrentPathStack().peek();
423-
StringBuilder ignoredOutput = new StringBuilder();
424-
// render all extend parents, keeping the last as the root output
425-
if (processExtendRoots) {
426-
Set<String> extendPaths = new HashSet<>();
427-
Optional<String> extendPath = context.getExtendPathStack().peek();
428-
int numDeferredTokensBefore = 0;
429-
while (!extendParentRoots.isEmpty()) {
430-
if (extendPaths.contains(extendPath.orElse(""))) {
408+
} catch (OutputTooBigException e) {
409+
addError(TemplateError.fromOutputTooBigException(e));
410+
return output.getValue();
411+
} catch (CollectionTooBigException e) {
431412
addError(
432-
TemplateError.fromException(
433-
new ExtendsTagCycleException(
434-
extendPath.orElse(""),
435-
context.getExtendPathStack().getTopLineNumber(),
436-
context.getExtendPathStack().getTopStartPosition()
437-
)
413+
new TemplateError(
414+
ErrorType.FATAL,
415+
ErrorReason.COLLECTION_TOO_BIG,
416+
ErrorItem.OTHER,
417+
ExceptionUtils.getMessage(e),
418+
null,
419+
-1,
420+
-1,
421+
e,
422+
BasicTemplateErrorCategory.UNKNOWN,
423+
ImmutableMap.of()
438424
)
439425
);
440-
break;
426+
return output.getValue();
441427
}
442-
extendPaths.add(extendPath.orElse(""));
443-
try (
444-
AutoCloseableImpl<Result<String, TagCycleException>> closeableCurrentPath =
445-
context
446-
.getCurrentPathStack()
447-
.closeablePush(
448-
extendPath.orElse(""),
449-
context.getExtendPathStack().getTopLineNumber(),
450-
context.getExtendPathStack().getTopStartPosition()
428+
}
429+
DynamicRenderedOutputNode pathSetter = new DynamicRenderedOutputNode();
430+
output.addNode(pathSetter);
431+
Optional<String> basePath = context.getCurrentPathStack().peek();
432+
StringBuilder ignoredOutput = new StringBuilder();
433+
// render all extend parents, keeping the last as the root output
434+
if (processExtendRoots) {
435+
Set<String> extendPaths = new HashSet<>();
436+
Optional<String> extendPath = context.getExtendPathStack().peek();
437+
int numDeferredTokensBefore = 0;
438+
while (!extendParentRoots.isEmpty()) {
439+
if (extendPaths.contains(extendPath.orElse(""))) {
440+
addError(
441+
TemplateError.fromException(
442+
new ExtendsTagCycleException(
443+
extendPath.orElse(""),
444+
context.getExtendPathStack().getTopLineNumber(),
445+
context.getExtendPathStack().getTopStartPosition()
446+
)
451447
)
452-
.get()
453-
) {
454-
String currentPath = closeableCurrentPath
455-
.value()
456-
.unwrapOrElseThrow(Function.identity());
457-
Node parentRoot = extendParentRoots.removeFirst();
458-
if (context.getDeferredTokens().size() > numDeferredTokensBefore) {
459-
ignoredOutput.append(
460-
output
461-
.getNodes()
462-
.stream()
463-
.filter(node -> node instanceof RenderedOutputNode)
464-
.map(OutputNode::getValue)
465-
.collect(Collectors.joining())
466448
);
449+
break;
467450
}
468-
numDeferredTokensBefore = context.getDeferredTokens().size();
469-
output = new OutputList(config.getMaxOutputSize());
470-
output.addNode(pathSetter);
471-
boolean hasNestedExtends = false;
472-
for (Node node : parentRoot.getChildren()) {
473-
lineNumber = node.getLineNumber() - 1; // The line number is off by one when rendering the extend parent
474-
position = node.getStartPosition();
475-
try {
476-
OutputNode out = node.render(this);
477-
output.addNode(out);
478-
if (isExtendsTag(node)) {
479-
hasNestedExtends = true;
451+
extendPaths.add(extendPath.orElse(""));
452+
try (
453+
AutoCloseableImpl<Result<String, TagCycleException>> closeableCurrentPath =
454+
context
455+
.getCurrentPathStack()
456+
.closeablePush(
457+
extendPath.orElse(""),
458+
context.getExtendPathStack().getTopLineNumber(),
459+
context.getExtendPathStack().getTopStartPosition()
460+
)
461+
.get()
462+
) {
463+
String currentPath = closeableCurrentPath
464+
.value()
465+
.unwrapOrElseThrow(Function.identity());
466+
Node parentRoot = extendParentRoots.removeFirst();
467+
if (context.getDeferredTokens().size() > numDeferredTokensBefore) {
468+
ignoredOutput.append(
469+
output
470+
.getNodes()
471+
.stream()
472+
.filter(node -> node instanceof RenderedOutputNode)
473+
.map(OutputNode::getValue)
474+
.collect(Collectors.joining())
475+
);
476+
}
477+
numDeferredTokensBefore = context.getDeferredTokens().size();
478+
output = new OutputList(config.getMaxOutputSize());
479+
output.addNode(pathSetter);
480+
boolean hasNestedExtends = false;
481+
for (Node node : parentRoot.getChildren()) {
482+
lineNumber = node.getLineNumber() - 1; // The line number is off by one when rendering the extend parent
483+
position = node.getStartPosition();
484+
try {
485+
OutputNode out = node.render(this);
486+
output.addNode(out);
487+
if (isExtendsTag(node)) {
488+
hasNestedExtends = true;
489+
}
490+
} catch (OutputTooBigException e) {
491+
addError(TemplateError.fromOutputTooBigException(e));
492+
return output.getValue();
480493
}
481-
} catch (OutputTooBigException e) {
482-
addError(TemplateError.fromOutputTooBigException(e));
483-
return output.getValue();
484494
}
495+
Optional<String> currentExtendPath = context.getExtendPathStack().pop();
496+
extendPath =
497+
hasNestedExtends ? currentExtendPath : context.getExtendPathStack().peek();
498+
basePath = Optional.of(currentPath);
485499
}
486-
Optional<String> currentExtendPath = context.getExtendPathStack().pop();
487-
extendPath =
488-
hasNestedExtends ? currentExtendPath : context.getExtendPathStack().peek();
489-
basePath = Optional.of(currentPath);
490500
}
491501
}
492-
}
493502

494-
int numDeferredTokensBefore = context.getDeferredTokens().size();
495-
resolveBlockStubs(output);
496-
if (context.getDeferredTokens().size() > numDeferredTokensBefore) {
497-
pathSetter.setValue(
498-
EagerReconstructionUtils.buildBlockOrInlineSetTag(
499-
RelativePathResolver.CURRENT_PATH_CONTEXT_KEY,
500-
basePath,
501-
this
502-
)
503-
);
504-
}
503+
int numDeferredTokensBefore = context.getDeferredTokens().size();
504+
resolveBlockStubs(output);
505+
if (context.getDeferredTokens().size() > numDeferredTokensBefore) {
506+
pathSetter.setValue(
507+
EagerReconstructionUtils.buildBlockOrInlineSetTag(
508+
RelativePathResolver.CURRENT_PATH_CONTEXT_KEY,
509+
basePath,
510+
this
511+
)
512+
);
513+
}
505514

506-
if (ignoredOutput.length() > 0) {
507-
return (
508-
EagerReconstructionUtils.labelWithNotes(
509-
EagerReconstructionUtils.wrapInTag(
510-
ignoredOutput.toString(),
511-
DoTag.TAG_NAME,
512-
this,
513-
false
514-
),
515-
IGNORED_OUTPUT_FROM_EXTENDS_NOTE,
516-
this
517-
) +
518-
output.getValue()
519-
);
515+
if (ignoredOutput.length() > 0) {
516+
return (
517+
EagerReconstructionUtils.labelWithNotes(
518+
EagerReconstructionUtils.wrapInTag(
519+
ignoredOutput.toString(),
520+
DoTag.TAG_NAME,
521+
this,
522+
false
523+
),
524+
IGNORED_OUTPUT_FROM_EXTENDS_NOTE,
525+
this
526+
) +
527+
output.getValue()
528+
);
529+
}
530+
return output.getValue();
531+
} finally {
532+
if (pushed) {
533+
JinjavaInterpreter.popCurrent();
534+
}
520535
}
521-
return output.getValue();
522536
}
523537

524538
private void resolveBlockStubs(OutputList output) {

src/main/java/com/hubspot/jinjava/lib/tag/FromTag.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,7 @@ public String interpret(TagNode tagNode, JinjavaInterpreter interpreter) {
114114
.getInterpreterFactory()
115115
.newInstance(interpreter);
116116
child.getContext().put(Context.IMPORT_RESOURCE_PATH_KEY, templateFile);
117-
try (
118-
AutoCloseableImpl<JinjavaInterpreter> a = JinjavaInterpreter
119-
.closeablePushCurrent(child)
120-
.get()
121-
) {
122-
child.render(node);
123-
}
117+
child.render(node);
124118

125119
interpreter.addAllChildErrors(templateFile, child.getErrorsCopy());
126120

src/main/java/com/hubspot/jinjava/lib/tag/ImportTag.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,7 @@ public String interpret(TagNode tagNode, JinjavaInterpreter interpreter) {
123123
.getInterpreterFactory()
124124
.newInstance(interpreter);
125125
child.getContext().put(Context.IMPORT_RESOURCE_PATH_KEY, templateFile);
126-
127-
try (
128-
AutoCloseableImpl<JinjavaInterpreter> a = JinjavaInterpreter
129-
.closeablePushCurrent(child)
130-
.get()
131-
) {
132-
child.render(node.value());
133-
}
126+
child.render(node.value());
134127

135128
interpreter.addAllChildErrors(templateFile, child.getErrorsCopy());
136129

0 commit comments

Comments
 (0)