thymeleaf/thymeleaf-spring

Trying to use fragment inside template but get TemplateInputException: Error resolving template

alan-czajkowski opened this issue · 3 comments

Building a back-end app using Spring Boot 3.1
Using dependency:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
      <version>3.1.9</version>
    </dependency>

which uses:

    <dependency>
      <groupId>org.thymeleaf</groupId>
      <artifactId>thymeleaf-spring6</artifactId>
      <version>3.1.2.RELEASE</version>
    </dependency>

Rendering templates on the fly using the Template engine:

    ...

    SpringResourceTemplateResolver templateResolver;

    // HTML template resolver
    templateResolver = new SpringResourceTemplateResolver();
    templateResolver.setPrefix("/WEB-INF/thymeleaf/templates");
    templateResolver.setTemplateMode(TemplateMode.HTML);
    templateResolver.setCharacterEncoding(UTF_8.name());
    templateResolver.setCacheable(false);
    templateResolver.setCheckExistence(true);
    templateResolver.setApplicationContext(this.applicationContext);
    templateEngine.addTemplateResolver(templateResolver);

    // TEXT template resolver
    templateResolver = new SpringResourceTemplateResolver();
    templateResolver.setPrefix("/WEB-INF/thymeleaf/templates");
    templateResolver.setTemplateMode(TemplateMode.TEXT);
    templateResolver.setCharacterEncoding(UTF_8.name());
    templateResolver.setCacheable(false);
    templateResolver.setCheckExistence(true);
    templateResolver.setApplicationContext(this.applicationContext);
    templateEngine.addTemplateResolver(templateResolver);

    ...

    renderedContent = templateEngine.process(templatePath, context);

    ...

template directory layout:
Screen Shot 2024-03-16 at 4 16 58 PM

welcome.html:

<!DOCTYPE html>
<html xml:lang="en" xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
  <title th:text="#{templates.email.html.welcome.title}">Subject: ${subject}</title>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body style="font-family: sans-serif">
<div th:replace="~{email/fragments/header.html :: header}">hi</div>
...
</body>
</html>

there is no problem rendering this template (without the fragment) using:

    renderedContent = templateEngine.process("/email/welcome.html", context);

as soon as you add the fragment:

<div th:replace="~{email/fragments/header.html :: header}">hi</div>

you get this error:

...
Caused by: org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "ServletContext resource [/WEB-INF/thymeleaf/templates/email/welcome.html]")
	at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:241)
	at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100)
	at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:666)
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1103)
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1064)
	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1053)
	at com.sihuve.dyskover.common.manager.template.TemplateManager.render(TemplateManager.java:227)
	... 181 more
Caused by: org.attoparser.ParseException: Error resolving template [email/fragments/header.html], template might not exist or might not be accessible by any of the configured Template Resolvers (template: "/email/welcome.html" - line 8, col 6)
	at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393)
	at org.attoparser.MarkupParser.parse(MarkupParser.java:257)
	at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230)
	... 187 more
Caused by: org.thymeleaf.exceptions.TemplateInputException: Error resolving template [email/fragments/header.html], template might not exist or might not be accessible by any of the configured Template Resolvers (template: "/email/welcome.html" - line 8, col 6)
	at org.thymeleaf.engine.TemplateManager.resolveTemplate(TemplateManager.java:869)
	at org.thymeleaf.engine.TemplateManager.parseStandalone(TemplateManager.java:250)
	at org.thymeleaf.standard.expression.FragmentExpression.resolveExecutedFragmentExpression(FragmentExpression.java:567)
	at org.thymeleaf.standard.processor.AbstractStandardFragmentInsertionTagProcessor.computeFragment(AbstractStandardFragmentInsertionTagProcessor.java:419)
	at org.thymeleaf.standard.processor.AbstractStandardFragmentInsertionTagProcessor.doProcess(AbstractStandardFragmentInsertionTagProcessor.java:115)
	at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74)
	at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95)
	at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633)
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314)
	at org.thymeleaf.engine.TemplateHandlerAdapterMarkupHandler.handleOpenElementEnd(TemplateHandlerAdapterMarkupHandler.java:304)
	at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler$InlineMarkupAdapterPreProcessorHandler.handleOpenElementEnd(InlinedOutputExpressionMarkupHandler.java:278)
	at org.thymeleaf.standard.inline.OutputExpressionInlinePreProcessorHandler.handleOpenElementEnd(OutputExpressionInlinePreProcessorHandler.java:186)
	at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler.handleOpenElementEnd(InlinedOutputExpressionMarkupHandler.java:124)
	at org.attoparser.HtmlElement.handleOpenElementEnd(HtmlElement.java:109)
	at org.attoparser.HtmlMarkupHandler.handleOpenElementEnd(HtmlMarkupHandler.java:297)
	at org.attoparser.MarkupEventProcessorHandler.handleOpenElementEnd(MarkupEventProcessorHandler.java:402)
	at org.attoparser.ParsingElementMarkupUtil.parseOpenElement(ParsingElementMarkupUtil.java:159)
	at org.attoparser.MarkupParser.parseBuffer(MarkupParser.java:710)
	at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:301)

doesn't matter which fragment path you use:

  • email/fragments/header.html
  • email/fragments/header
  • fragments/header.html
  • fragments/header