CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-groovy--groovy-templates

Template engines for Apache Groovy including SimpleTemplateEngine, StreamingTemplateEngine, XmlTemplateEngine, and MarkupTemplateEngine

Pending
Overview
Eval results
Files

gstring-templates.mddocs/

GString Templates

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.

Capabilities

GString Template Engine Class

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();

Template Syntax Support

GStringTemplateEngine supports the same template syntax as SimpleTemplateEngine and StreamingTemplateEngine:

JSP-Style Scriptlets

Use <% %> blocks for executing Groovy code:

String template = """
<% 
def items = ['apple', 'banana', 'orange']
for (item in items) {
    print "- " + item + "\\n"
}
%>
""";

JSP-Style Expressions

Use <%= %> blocks for outputting expression results:

String template = """
Today is <%= new Date().format('yyyy-MM-dd') %>
Temperature: <%= temperature %>°C
""";

GString Expressions

Use ${expression} or $variable for variable substitution:

String template = """
Welcome ${user.name}!
You have ${messages.size()} new messages.
Your account balance is $balance.
""";

Closure-Based Architecture

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:

  • Efficient reuse: Templates are compiled once and can be applied multiple times
  • Memory efficiency: Closure-based storage reduces memory overhead
  • Thread safety: Each template execution gets its own closure instance

Streaming Support

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);
}

Template Reuse and Performance

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
}

Web Integration

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>

Binding Resolution Strategy

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
""";

Error Handling

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());
}

Best Practices

  1. Template Reuse: Compile templates once and reuse with different bindings
  2. Large Data: Use streaming with writeTo() for large outputs
  3. Variable Scope: Be aware that variables assigned in scriptlets go to the binding
  4. Thread Safety: Create separate template instances for concurrent use
  5. Memory Management: Let templates be garbage collected when no longer needed

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-groovy--groovy-templates

docs

gstring-templates.md

index.md

markup-templates.md

simple-templates.md

streaming-templates.md

xml-templates.md

tile.json