Master Compile-Time Mustache Templates with JStachio in Spring Boot 3
This article introduces compile-time template concepts, explains the JStachio library and its extensive Mustache support, compares its performance, and provides step‑by‑step Maven and Spring Boot integration examples with full code snippets and result screenshots.
1. Introduction
Traditional template engines load and parse templates at runtime, which adds overhead and can hide format errors until execution. JStachio compiles Mustache templates into Java classes during the build, allowing the compiler to catch template mistakes early and eliminating runtime reflection, making it suitable for GraalVM native images.
2. Core Features of JStachio
Full support for Mustache v1.3.0 non‑optional requirements, including whitespace handling.
Optional inheritance and Lambda support (with static‑friendly differences).
Static value binding with compile‑time checks.
Ability to reference methods, fields, and getters inside templates.
Friendly error messages with context.
Zero configuration – works with standard javac and any IDE or build system.
Support for non‑HTML templates and customizable output types.
Mustache inheritance for layout composition.
ServiceLoader‑based fallback rendering (JMustache/mustache.java) for development.
Optional runtime rendering fallback for quick edits.
Customizable toString handling to avoid unsafe calls.
Extension points via @JStacheInterfaces.
Strong Lambda support, including Map<String, ?> and Optional<?>.
Compatibility with JMustache and Handlebars list extensions ( -first, -last, -index).
One of the fastest Java Mustache engines.
No external dependencies besides JStachio itself.
Zero‑runtime‑dependency option for minimal native image size.
First‑class Spring framework integration via a dedicated starter.
3. Performance Comparison
The following chart shows JStachio’s runtime speed compared with other Mustache implementations.
4. Practical Example
4.1 Quick Start
Add the JStachio dependency to your pom.xml:
<dependency>
<groupId>io.jstach</groupId>
<artifactId>jstachio</artifactId>
<version>1.3.7</version>
</dependency>Configure the Maven compiler plugin to use the annotation processor:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>21</source>
<target>21</target>
<annotationProcessorPaths>
<path>
<groupId>io.jstach</groupId>
<artifactId>jstachio-apt</artifactId>
<version>1.3.7</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>4.2 Full Example
A JUnit test demonstrating template rendering:
public class TemplateTest {
@JStache(template = """
{{#people}}
{{message}} {{name}}!你{{#ageInfo}}{{age}}{{/ageInfo}}岁了!
{{#-last}}
目前就这些啦!
{{/-last}}
{{/people}}
""")
public record HelloWorld(String message, List<Person> people) implements AgeLambdaSupport {}
public record Person(String name, LocalDate birthday) {}
public record AgeInfo(long age, String date) {}
public interface AgeLambdaSupport {
@JStacheLambda
default AgeInfo ageInfo(Person person) {
long age = ChronoUnit.YEARS.between(person.birthday(), LocalDate.now());
String date = person.birthday().format(DateTimeFormatter.ISO_DATE);
return new AgeInfo(age, date);
}
}
@Test
public void testPerson() throws Exception {
Person rick = new Person("张三", LocalDate.now().minusYears(70));
Person morty = new Person("李四", LocalDate.now().minusYears(14));
Person beth = new Person("王五", LocalDate.now().minusYears(35));
Person jerry = new Person("赵六", LocalDate.now().minusYears(35));
String actual = JStachio.render(new HelloWorld("你好,外星人", List.of(rick, morty, beth, jerry)));
System.err.println(actual);
}
}Result screenshot:
5. Integration with Spring Boot
5.1 Spring Boot Starter Dependency
<dependency>
<groupId>io.jstach</groupId>
<artifactId>jstachio-spring-boot-starter-webmvc</artifactId>
<version>1.3.7</version>
</dependency>5.2 Template File (templates/user.mustache)
<ul>
<li>姓名: {{name}}</li>
<li>年龄: {{age}}</li>
<li>邮箱: {{email}}</li>
</ul>5.3 Model Definition
@JStache(path = "templates/user.mustache")
public record UserModel(String name, Integer age, String email) {}5.4 Controller
@Controller
@RequestMapping("/jstach")
public class JstachController {
@GetMapping("/user")
public View user() {
return JStachioModelView.of(
new UserModel("Pack_xg", 33, "[email protected]"),
"text/html;charset=UTF-8");
}
}Rendered page screenshot:
6. Compile‑Time Error Detection
If a template reference is misspelled (e.g., {{list2}} instead of {{list}}), the build fails with a clear compilation error, preventing runtime failures.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
