public RenderResult withOutput(String newOutput) { return new RenderResult(newOutput, getContext(), getErrors()); }
/** * Render the given template using the given context bindings. * * @param template * jinja source template * @param bindings * map of objects to put into scope for this rendering action * @return the rendered template * @throws InterpretException * if any syntax errors were encountered during rendering */ public String render(String template, Map<String, ?> bindings) { RenderResult result = renderForResult(template, bindings); List<TemplateError> fatalErrors = result.getErrors().stream() .filter(error -> error.getSeverity() == ErrorType.FATAL) .collect(Collectors.toList()); if (!fatalErrors.isEmpty()) { throw new FatalTemplateErrorsException(template, fatalErrors); } return result.getOutput(); }
@Override public Collection<InfoPanelItem> getContributions(final GraphContainer container) { try (final DirectoryStream<Path> stream = Files.newDirectoryStream(DIR, "*.html")) { final Set<InfoPanelItem> items = Sets.newHashSet(); for (final Path path : stream) { try { final RenderResult result = this.render(path, container); if (Iterables.any(result.getErrors(), e -> e.getSeverity() == TemplateError.ErrorType.FATAL)) { // Only show the errors to the user if there are real errors, ignoring warnings items.add(new ErrorItem(path, result.getErrors())); } else if ((Boolean) result.getContext().getOrDefault("visible", false)) { items.add(new TemplateItem(result)); } } catch (final IOException e) { LOG.error("Failed to load template: {}: {}", path, e); return Collections.emptySet(); } } return items; } catch (final IOException e) { LOG.error("Failed to walk template directory: {}", DIR); return Collections.emptySet(); } }
@Test public void itLimitsOutputSizeWhenSumOfNodeSizesExceedsMax() { JinjavaConfig outputSizeLimitedConfig = JinjavaConfig.newBuilder().withMaxOutputSize(19).build(); String input = "1234567890{% block testchild %}1234567890{% endblock %}"; String output = "12345678901234567890"; // Note that this exceeds the max size RenderResult renderResult = new Jinjava().renderForResult(input, new HashMap<>()); assertThat(renderResult.getOutput()).isEqualTo(output); assertThat(renderResult.hasErrors()).isFalse(); renderResult = new Jinjava(outputSizeLimitedConfig).renderForResult(input, new HashMap<>()); assertThat(renderResult.hasErrors()).isTrue(); assertThat(renderResult.getErrors().get(0).getMessage()).contains("OutputTooBigException"); } }
@Test public void itStoresResolvedFunctions() { context.put("datetime", 12345); final JinjavaConfig config = JinjavaConfig.newBuilder().build(); String template = "{% for i in range(1, 5) %}{{i}} {% endfor %}\n{{ unixtimestamp(datetime) }}"; final RenderResult renderResult = jinjava.renderForResult(template, context, config); assertThat(renderResult.getOutput()).isEqualTo("1 2 3 4 \n12000"); assertThat(renderResult.getContext().getResolvedFunctions()).hasSameElementsAs(ImmutableSet.of(":range", ":unixtimestamp")); }
@Override public int getOrder() { return (int) (long) this.renderResult.getContext().get("order", 0L); } }
@Override public Component getComponent() { return new Label(this.renderResult.getOutput(), ContentMode.HTML); }
return new RenderResult(result, interpreter.getContext(), interpreter.getErrorsCopy()); } catch (InterpretException e) { if (e instanceof TemplateSyntaxException) { return new RenderResult(TemplateError.fromException((TemplateSyntaxException) e), interpreter.getContext(), interpreter.getErrorsCopy()); return new RenderResult(TemplateError.fromSyntaxError(e), interpreter.getContext(), interpreter.getErrorsCopy()); } catch (Exception e) { return new RenderResult(TemplateError.fromException(e), interpreter.getContext(), interpreter.getErrorsCopy()); } finally { globalContext.reset();
@Test public void itLimitsOutputSize() { JinjavaConfig outputSizeLimitedConfig = JinjavaConfig.newBuilder().withMaxOutputSize(20).build(); String output = "123456789012345678901234567890"; RenderResult renderResult = new Jinjava().renderForResult(output, new HashMap<>()); assertThat(renderResult.getOutput()).isEqualTo(output); assertThat(renderResult.hasErrors()).isFalse(); renderResult = new Jinjava(outputSizeLimitedConfig).renderForResult(output, new HashMap<>()); assertThat(renderResult.getErrors().get(0).getMessage()).contains("OutputTooBigException"); }
@Test public void itResetsGlobalContextAfterRender() { Jinjava jinjava = new Jinjava(); Context globalContext = jinjava.getGlobalContext(); RenderResult result = jinjava.renderForResult("{{ foo + 1 }}", ImmutableMap.of("foo", 1)); assertThat(result.getOutput()).isEqualTo("2"); assertThat(result.getContext().getResolvedExpressions()).containsOnly("foo + 1"); assertThat(result.getContext().getResolvedValues()).containsOnly("foo"); assertThat(globalContext.getResolvedExpressions()).isEmpty(); assertThat(globalContext.getResolvedValues()).isEmpty(); } }
@Override public String getTitle() { return (String) this.renderResult.getContext().get("title", "No Title defined"); }
@Override public Collection<InfoPanelItem> getContributions(final GraphContainer container) { try (final DirectoryStream<Path> stream = Files.newDirectoryStream(DIR, "*.html")) { final Set<InfoPanelItem> items = Sets.newHashSet(); for (final Path path : stream) { try { final RenderResult result = this.render(path, container); if (Iterables.any(result.getErrors(), e -> e.getSeverity() == TemplateError.ErrorType.FATAL)) { // Only show the errors to the user if there are real errors, ignoring warnings items.add(new ErrorItem(path, result.getErrors())); } else if ((Boolean) result.getContext().getOrDefault("visible", false)) { items.add(new TemplateItem(result)); } } catch (final IOException e) { LOG.error("Failed to load template: {}: {}", path, e); return Collections.emptySet(); } } return items; } catch (final IOException e) { LOG.error("Failed to walk template directory: {}", DIR); return Collections.emptySet(); } }
@Override public Component getComponent() { return new Label(this.renderResult.getOutput(), ContentMode.HTML); }
@Test public void testAttrNotFound() { Map<String, Object> context = new HashMap<>(); context.put("foo", new MyFoo()); RenderResult renderResult = jinjava.renderForResult("{{ foo|attr(\"barf\") }}", context); assertThat(renderResult.getOutput()).isEmpty(); assertThat(renderResult.getErrors()).hasSize(1); assertThat(renderResult.getErrors().get(0).getReason()).isEqualTo(ErrorReason.UNKNOWN); assertThat(renderResult.getErrors().get(0).getFieldName()).isEqualTo("barf"); }
@Test public void itLimitsOutputSizeWhenSumOfNodeSizesExceedsMax() { JinjavaConfig outputSizeLimitedConfig = JinjavaConfig.newBuilder().withMaxOutputSize(19).build(); String input = "1234567890{% block testchild %}1234567890{% endblock %}"; String output = "12345678901234567890"; // Note that this exceeds the max size RenderResult renderResult = new Jinjava().renderForResult(input, new HashMap<>()); assertThat(renderResult.getOutput()).isEqualTo(output); assertThat(renderResult.hasErrors()).isFalse(); renderResult = new Jinjava(outputSizeLimitedConfig).renderForResult(input, new HashMap<>()); assertThat(renderResult.hasErrors()).isTrue(); assertThat(renderResult.getErrors().get(0).getMessage()).contains("OutputTooBigException"); } }
@Test public void itResetsGlobalContextAfterRender() { Jinjava jinjava = new Jinjava(); Context globalContext = jinjava.getGlobalContext(); RenderResult result = jinjava.renderForResult("{{ foo + 1 }}", ImmutableMap.of("foo", 1)); assertThat(result.getOutput()).isEqualTo("2"); assertThat(result.getContext().getResolvedExpressions()).containsOnly("foo + 1"); assertThat(result.getContext().getResolvedValues()).containsOnly("foo"); assertThat(globalContext.getResolvedExpressions()).isEmpty(); assertThat(globalContext.getResolvedValues()).isEmpty(); } }
@Override public String getTitle() { return (String) this.renderResult.getContext().get("title", "No Title defined"); }