Architecture
1. Pipeline
A template string flows through four stages:
Template string -> Lexer -> Tokens -> Parser -> AST -> Executor -> Output
-
Lexer (
parse/Lexer.java) — scans the template into tokens, tracking action delimiters and trim markers. -
Parser (
parse/Parser.java) — builds an AST ofNodetypes (actions, pipelines,if/range/with, defined templates). -
Executor (
exec/Executor.java) — walks the AST against the data value, resolving fields, invoking functions, and writing output. A fresh executor is created perexecutecall, so a parsed template can be executed concurrently.
2. Modules and the function SPI
gotmpl4j-core knows only Go’s built-in functions (Functions.GO_BUILTINS). Everything else
is contributed by FunctionProvider implementations discovered through ServiceLoader:
| Provider | Priority | Source module |
|---|---|---|
Go built-ins |
— |
|
Sprig |
100 |
|
Helm |
200 |
(external — |
Higher priority wins on name collisions. To add your own functions, implement
FunctionProvider, register it in META-INF/services, and put it on the classpath — or pass
functions directly through GoTemplate.builder().withFunctions(…).
The core module must not depend on Sprig, Helm, or any host application; that boundary is what lets the engine be embedded standalone.
3. HTML auto-escaping
The html/ package is a port of Go’s html/template contextual escaper: a state machine
that tracks the HTML/attribute/URL/JS/CSS context at each interpolation point and inserts the
appropriate escaper. It is opt-in via GoTemplate.builder().htmlEscaping().
4. Caching
TemplateCache stores compiled ASTs so repeated renders of the same template skip the
lex/parse stages. The Spring starter wires it in by default; it uses double-checked locking
and is safe for concurrent use.
5. API stability
From 1.0, the supported public API — everything covered by semantic versioning — is driving
the engine through GoTemplate (parse / execute / render / compiled / builder),
the Function / FunctionProvider SPI, the MissingKeyMode option, and the
GoTemplateException hierarchy. The Spring Boot starter’s documented properties and beans are
covered too.
GoTemplate.getRootNodes() and getFunctions() — and the org.alexmond.gotmpl4j.parse.Node
types they expose — are an advanced integrator surface, not general application API. They
return the engine’s live, mutable internals so that engines built on top of gotmpl4j (such as
Helm’s tpl / include, implemented in jhelm) can share
named templates across instances. Because they leak internals, they are not covered by the
1.0 stability guarantee and may change in a minor release; a first-class replacement is tracked
in issue #48. Application code should not depend
on them.