Template engines for Apache Groovy including SimpleTemplateEngine, StreamingTemplateEngine, XmlTemplateEngine, and MarkupTemplateEngine
—
The StreamingTemplateEngine provides closure-based template processing optimized for large templates (>64k characters). It offers equivalent functionality to SimpleTemplateEngine but with better scalability and enhanced error reporting.
Creates templates using closure-based approach with enhanced error handling and support for large templates.
/**
* Closure-based template engine optimized for large templates and scalable performance.
* Handles templates larger than 64k characters and provides enhanced error reporting.
*/
public class StreamingTemplateEngine extends TemplateEngine {
/**
* Creates a new StreamingTemplateEngine with default class loader
*/
public StreamingTemplateEngine();
/**
* Creates a new StreamingTemplateEngine with custom class loader
* @param parentLoader ClassLoader used when parsing template code
*/
public StreamingTemplateEngine(ClassLoader parentLoader);
}Usage Examples:
import groovy.text.StreamingTemplateEngine;
import groovy.text.Template;
import java.util.Map;
import java.util.HashMap;
// Create streaming template engine
StreamingTemplateEngine engine = new StreamingTemplateEngine();
// Template with mixed JSP and GString syntax (same as SimpleTemplateEngine)
String templateText = """
Dear <% out.print firstname %> ${lastname},
We <% if (accepted) out.print 'are pleased' else out.print 'regret' %>
to inform you that your paper entitled
'$title' was ${ accepted ? 'accepted' : 'rejected' }.
The conference committee.
""";
Template template = engine.createTemplate(templateText);
Map<String, Object> binding = new HashMap<>();
binding.put("firstname", "Grace");
binding.put("lastname", "Hopper");
binding.put("accepted", true);
binding.put("title", "Groovy for COBOL programmers");
String result = template.make(binding).toString();
// Works with large templates (>64k characters)
StringBuilder largeTemplate = new StringBuilder();
for (int i = 0; i < 10000; i++) {
largeTemplate.append("Line ${i}: Hello $name!\\n");
}
Template bigTemplate = engine.createTemplate(largeTemplate.toString());
Map<String, Object> bigBinding = new HashMap<>();
bigBinding.put("name", "World");
String bigResult = bigTemplate.make(bigBinding).toString();StreamingTemplateEngine supports the same syntax as SimpleTemplateEngine with some additional considerations:
Use <% %> blocks for executing Groovy code. Note that out.print is required for output in scriptlets:
String template = """
<%
def greeting = "Hello"
if (name) {
out.print greeting + " " + name
} else {
out.print greeting + " World"
}
%>
""";Use <%= %> blocks for outputting expression results:
String template = """
Current time: <%= new Date() %>
User count: <%= users.size() %>
""";Use ${expression} or $variable for variable substitution:
String template = """
Welcome ${user.name}!
Your balance is $balance.
""";Simple variable references without braces:
String template = """
Hello $name!
Today is $date
""";StreamingTemplateEngine is specifically designed to handle large templates that would cause issues with other engines:
// Example: Generate a large report template
StringBuilder reportTemplate = new StringBuilder();
reportTemplate.append("# Large Report\\n\\n");
// Add thousands of template sections
for (int section = 1; section <= 1000; section++) {
reportTemplate.append("## Section ").append(section).append("\\n");
reportTemplate.append("Content for section ${section}: $data_").append(section).append("\\n\\n");
}
StreamingTemplateEngine engine = new StreamingTemplateEngine();
Template template = engine.createTemplate(reportTemplate.toString());
// Bind data for all sections
Map<String, Object> binding = new HashMap<>();
for (int i = 1; i <= 1000; i++) {
binding.put("data_" + i, "Data for section " + i);
}
String report = template.make(binding).toString();StreamingTemplateEngine provides detailed error reporting with template source context:
// Template with intentional error
String templateWithError = """
<% def greeting = "Hello" %>
Welcome ${greeting}!
<% invalid_variable.someMethod() %> // This will cause an error
Goodbye!
""";
try {
StreamingTemplateEngine engine = new StreamingTemplateEngine();
Template template = engine.createTemplate(templateWithError);
String result = template.make(new HashMap()).toString();
} catch (Exception e) {
// StreamingTemplateEngine provides detailed error context:
// "Template execution error at line 3:
// 2: Welcome ${greeting}!
// --> 3: <% invalid_variable.someMethod() %>
// 4: Goodbye!
System.err.println(e.getMessage());
}StreamingTemplateEngine can be used with servlet containers:
<servlet>
<servlet-name>StreamingTemplate</servlet-name>
<servlet-class>groovy.servlet.TemplateServlet</servlet-class>
<init-param>
<param-name>template.engine</param-name>
<param-value>groovy.text.StreamingTemplateEngine</param-value>
</init-param>
</servlet>StreamingTemplateEngine allows access to the generated script source for debugging:
StreamingTemplateEngine engine = new StreamingTemplateEngine();
Template template = engine.createTemplate("Hello ${name}!");
// Access the generated script source (implementation detail)
// This can be useful for debugging complex template issues
// Note: This is accessed through internal StreamingTemplate propertiesStreamingTemplateEngine is optimized for:
StreamingTemplateEngine can throw several types of exceptions:
try {
Template template = engine.createTemplate(templateText);
String result = template.make(binding).toString();
} catch (CompilationFailedException e) {
// Template compilation failed
} catch (ClassNotFoundException e) {
// Missing class dependencies
} catch (IOException e) {
// I/O error reading template source
} catch (TemplateExecutionException e) {
// Runtime error during template execution
int errorLine = e.getLineNumber();
System.err.println("Error at line " + errorLine + ": " + e.getMessage());
}Install with Tessl CLI
npx tessl i tessl/maven-org-apache-groovy--groovy-templates