spring-bootmustache

How to load a Mustache Template in Spring Boot with includes


I have a simple test template TestMail.mustache:

<html lang="de">
{{>header}}
<body>
<p>bla bla bla bla</p>
<p>more bla bla.</p>
</body>
</html>

This template will be used for mailing. We plan a lot of mails with the same layout. Thus we wont to use some includes.

<head>
  <style>
    body {
      font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans",
      Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
      font-size: 16px;
      line-height: 24px;
    }
  </style>
</head>

When I use this template as a view template from an @Controller it is loaded completely including the header.mustache include.

But remember I want to use this template for a mail.
This is a part of the MailService

import org.springframework.boot.autoconfigure.mustache.MustacheResourceTemplateLoader

private val log = KotlinLogging.logger {}

@Service
class MailService(
  private val templateLoader: MustacheResourceTemplateLoader,
) {

fun testMail() {
    try {
      val reader = templateLoader.getTemplate("TestMail")

      val template = Mustache.compiler().compile(reader)

      val result = template.execute(null)

      log.info { "Test Mail Template:\n${result}" }
    } catch (th: Throwable) {
      log.error(th) { "error in method test mail" }
    }
  }

}

When I try to load the template with Spring Boots autowired MustacheResourceTemplateLoader I get the following stack trace:

java.lang.UnsupportedOperationException: Template loading not configured
    at com.samskivert.mustache.Mustache$1.getTemplate(Mustache.java:1034) ~[jmustache-1.15.jar:na]
    at com.samskivert.mustache.Mustache$Compiler.loadTemplate(Mustache.java:220) ~[jmustache-1.15.jar:na]
    at com.samskivert.mustache.Mustache$IncludedTemplateSegment.getTemplate(Mustache.java:845) ~[jmustache-1.15.jar:na]
    at com.samskivert.mustache.Mustache$IncludedTemplateSegment.execute(Mustache.java:831) ~[jmustache-1.15.jar:na]
    at com.samskivert.mustache.Template.executeSegs(Template.java:170) ~[jmustache-1.15.jar:na]
    at com.samskivert.mustache.Template.execute(Template.java:137) ~[jmustache-1.15.jar:na]
    at com.samskivert.mustache.Template.execute(Template.java:128) ~[jmustache-1.15.jar:na]
    at de.vrk.mail.MailService.testMail(MailService.kt:137) ~[main/:na]

If I don't use includes the template is loaded fine via the MustacheResourceTemplateLoader but as soon I use an include, it does not work.

Why can Spring Boot as a view completely resolve the two templates, but when I use the MustacheResourceTemplateLoader it does not work?


Solution

  • Inject the MustacheCompiler as well, as that compiler comes pre-configured with the loader.

    @Service
    class MailService(
      private val templateLoader: MustacheResourceTemplateLoader,
      private val compiler: Mustache.Compiler,
    ) {
    
    fun testMail() {
        try {
          val reader = templateLoader.getTemplate("TestMail")
    
          val template = compiler.compile(reader)
    
          val result = template.execute(null)
    
          log.info { "Test Mail Template:\n${result}" }
        } catch (th: Throwable) {
          log.error(th) { "error in method test mail" }
        }
      }
    
    }
    

    or if you don't want that configure the compiler to use the loader.

    val template = Mustache.compiler().withLoader(resourceLoader).compile(reader)
    

    Either way will use the compiler with a loader configured.