Template engines for Apache Groovy including SimpleTemplateEngine, StreamingTemplateEngine, XmlTemplateEngine, and MarkupTemplateEngine
—
The GStringTemplateEngine provides template processing using GString closures stored as writable templates. It's designed for streaming scenarios and offers efficient template storage and execution through closure-based architecture.
Creates templates using GString closures with efficient storage and streaming support.
/**
* Template engine using GString and JSP-style syntax, storing templates as writable closures.
* Optimized for streaming scenarios and efficient template reuse.
*/
public class GStringTemplateEngine extends TemplateEngine {
/**
* Creates a new GStringTemplateEngine with default class loader
*/
public GStringTemplateEngine();
/**
* Creates a new GStringTemplateEngine with custom class loader
* @param parentLoader ClassLoader used for template compilation
*/
public GStringTemplateEngine(ClassLoader parentLoader);
}Usage Examples:
import groovy.text.GStringTemplateEngine;
import groovy.text.Template;
import java.util.Map;
import java.util.HashMap;
// Create GString template engine
GStringTemplateEngine engine = new GStringTemplateEngine();
// Template with mixed JSP and GString syntax
String templateText = """
Dear <%= firstname %> $lastname,
We <% if (accepted) print 'are pleased' else 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();GStringTemplateEngine supports the same template syntax as SimpleTemplateEngine and StreamingTemplateEngine:
Use <% %> blocks for executing Groovy code:
String template = """
<%
def items = ['apple', 'banana', 'orange']
for (item in items) {
print "- " + item + "\\n"
}
%>
""";Use <%= %> blocks for outputting expression results:
String template = """
Today is <%= new Date().format('yyyy-MM-dd') %>
Temperature: <%= temperature %>°C
""";Use ${expression} or $variable for variable substitution:
String template = """
Welcome ${user.name}!
You have ${messages.size()} new messages.
Your account balance is $balance.
""";GStringTemplateEngine internally converts templates to closure-based representations:
// The engine converts template text like this:
String template = "Hello ${name}! Today is <%= new Date() %>";
// Into closure-based code similar to:
// { out -> out << "Hello ${name}! Today is "; out << new Date(); }This architecture provides several benefits:
GStringTemplateEngine is particularly well-suited for streaming scenarios:
import groovy.text.GStringTemplateEngine;
import groovy.text.Template;
import groovy.lang.Writable;
import java.io.FileWriter;
import java.io.Writer;
GStringTemplateEngine engine = new GStringTemplateEngine();
String reportTemplate = """
# User Report
<% users.each { user -> %>
## User: ${user.name}
- Email: ${user.email}
- Status: ${user.active ? 'Active' : 'Inactive'}
- Last Login: <%= user.lastLogin?.format('yyyy-MM-dd') ?: 'Never' %>
<% } %>
Total users: ${users.size()}
""";
Template template = engine.createTemplate(reportTemplate);
// Create large dataset
List<Map<String, Object>> users = new ArrayList<>();
for (int i = 1; i <= 10000; i++) {
Map<String, Object> user = new HashMap<>();
user.put("name", "User " + i);
user.put("email", "user" + i + "@example.com");
user.put("active", i % 3 == 0);
users.add(user);
}
Map<String, Object> binding = new HashMap<>();
binding.put("users", users);
// Stream directly to file
Writable result = template.make(binding);
try (Writer writer = new FileWriter("report.txt")) {
result.writeTo(writer);
}GStringTemplateEngine excels at template reuse scenarios:
GStringTemplateEngine engine = new GStringTemplateEngine();
// Compile template once
String emailTemplate = """
Subject: Welcome ${name}!
Dear ${name},
Thank you for joining ${company}. Your account has been created with username: ${username}
<% if (isPremium) { %>
As a premium member, you have access to:
- Priority support
- Advanced features
- Extended storage
<% } %>
Welcome aboard!
The ${company} Team
""";
Template template = engine.createTemplate(emailTemplate);
// Reuse template for multiple users
List<Map<String, Object>> newUsers = getNewUsers(); // Assume this method exists
for (Map<String, Object> user : newUsers) {
Map<String, Object> binding = new HashMap<>();
binding.put("name", user.get("name"));
binding.put("username", user.get("username"));
binding.put("company", "Acme Corp");
binding.put("isPremium", user.get("accountType").equals("premium"));
String email = template.make(binding).toString();
sendEmail(user.get("email"), email); // Assume this method exists
}GStringTemplateEngine can be used with servlet containers:
<servlet>
<servlet-name>GStringTemplate</servlet-name>
<servlet-class>groovy.servlet.TemplateServlet</servlet-class>
<init-param>
<param-name>template.engine</param-name>
<param-value>groovy.text.GStringTemplateEngine</param-value>
</init-param>
</servlet>GStringTemplateEngine uses DELEGATE_FIRST resolution strategy to ensure proper variable binding:
// Template variables are resolved in this order:
// 1. Template binding (Map passed to make())
// 2. Template closure delegate
// 3. Template closure owner
String template = """
Value from binding: $bindingVar
<%
// This variable will be stored in the binding, not the script
localVar = "This goes to binding"
%>
Local variable: $localVar
""";GStringTemplateEngine provides standard Groovy error handling:
try {
GStringTemplateEngine engine = new GStringTemplateEngine();
Template template = engine.createTemplate(templateText);
String result = template.make(binding).toString();
} catch (CompilationFailedException e) {
// Template compilation failed - syntax error in template
System.err.println("Compilation error: " + e.getMessage());
} catch (IOException e) {
// I/O error when reading template source
System.err.println("I/O error: " + e.getMessage());
} catch (ClassNotFoundException e) {
// Missing class dependencies
System.err.println("Class not found: " + e.getMessage());
} catch (Exception e) {
// Runtime errors during template execution
System.err.println("Runtime error: " + e.getMessage());
}writeTo() for large outputsInstall with Tessl CLI
npx tessl i tessl/maven-org-apache-groovy--groovy-templates