CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-codehaus-groovy--groovy-templates

Groovy templating engines providing JSP-style scripting, GString expressions, markup builders, and streaming template capabilities for generating dynamic content from templates with variable substitution and control flow

Pending
Overview
Eval results
Files

streaming-template-engine.mddocs/

Streaming Template Engine

The StreamingTemplateEngine provides the same functionality as SimpleTemplateEngine but is optimized for large templates (>64k characters) using a closure-based approach. It offers better memory efficiency, superior error reporting with line numbers and context, and handles very large templates that cause problems for other engines.

API

class StreamingTemplateEngine extends TemplateEngine {
    StreamingTemplateEngine();
    StreamingTemplateEngine(ClassLoader parentLoader);
    
    Template createTemplate(Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException;
}

Template Syntax

Same as SimpleTemplateEngine and GStringTemplateEngine:

  • Script blocks: <% ... %> - Execute Groovy code
  • Expression blocks: <%= ... %> - Output expression result
  • GString expressions: ${...} and $variable - Variable interpolation
  • Output variable: out - Writer bound to template output

Key Features

Large Template Support

The StreamingTemplateEngine can handle templates larger than 64k characters, while other Groovy template engines may fail with such large templates.

Enhanced Error Reporting

Provides descriptive exceptions with context lines showing exactly where errors occur:

groovy.text.TemplateExecutionException: Template execution error at line 4:
         3: We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
     --> 4: '$txitle' was ${ accepted ? 'accepted' : 'rejected' }.
         5:

Caused by: groovy.lang.MissingPropertyException: No such property: txitle for class: groovy.tmp.templates.StreamingTemplateScript1

Memory Efficiency

Uses a streaming closure-based approach that processes templates incrementally rather than building large strings in memory.

Usage Examples

Basic Usage

import groovy.text.StreamingTemplateEngine;
import groovy.text.Template;
import java.util.HashMap;
import java.util.Map;

StreamingTemplateEngine engine = new StreamingTemplateEngine();

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

Large Template Processing

// Process a very large template (>64k characters)
StreamingTemplateEngine engine = new StreamingTemplateEngine();

// Read large template from file
File largeTemplateFile = new File("large-report-template.gsp");
Template template = engine.createTemplate(largeTemplateFile);

// Process with data
Map<String, Object> binding = new HashMap<>();
binding.put("records", largeDataSet); // Large dataset
binding.put("reportDate", new Date());

// Stream directly to file to avoid memory issues
try (FileWriter writer = new FileWriter("output-report.html");
     BufferedWriter bufferedWriter = new BufferedWriter(writer)) {
    template.make(binding).writeTo(bufferedWriter);
}

Custom Class Loader

ClassLoader customLoader = MyClass.class.getClassLoader();
StreamingTemplateEngine engine = new StreamingTemplateEngine(customLoader);

Template template = engine.createTemplate(templateSource);

Debugging Templates

Access the generated script source for debugging:

StreamingTemplateEngine engine = new StreamingTemplateEngine();
Template template = engine.createTemplate(templateText);

// Access the generated script source (internal property)
// Note: This requires casting to internal implementation class
if (template instanceof groovy.text.StreamingTemplateEngine.StreamingTemplate) {
    String scriptSource = ((groovy.text.StreamingTemplateEngine.StreamingTemplate) template).scriptSource;
    System.out.println("Generated script:");
    System.out.println(scriptSource);
}

Streaming to Different Outputs

Template template = engine.createTemplate(templateText);
Writable writable = template.make(binding);

// Stream to string
String result = writable.toString();

// Stream to file
try (FileWriter fileWriter = new FileWriter("output.txt")) {
    writable.writeTo(fileWriter);
}

// Stream to HTTP response
// response.setContentType("text/html");
// writable.writeTo(response.getWriter());

// Stream to any Writer
StringWriter stringWriter = new StringWriter();
writable.writeTo(stringWriter);

Advanced Usage

Template with Complex Logic

String templateText = """
<html>
<head><title>$title</title></head>
<body>
  <h1>$title</h1>
  
  <% if (showSummary) { %>
  <div class="summary">
    <h2>Summary</h2>
    <p>Total items: ${items.size()}</p>
    <p>Total value: \\$${items.sum { it.price * it.quantity }}</p>
  </div>
  <% } %>
  
  <div class="items">
    <% items.eachWithIndex { item, index -> %>
    <div class="item ${index % 2 == 0 ? 'even' : 'odd'}">
      <h3>${item.name}</h3>
      <p>Price: \\$${item.price}</p>
      <p>Quantity: ${item.quantity}</p>
      <% if (item.description) { %>
      <p class="description">${item.description}</p>
      <% } %>
    </div>
    <% } %>
  </div>
  
  <footer>
    Generated on <%= new Date().format('yyyy-MM-dd HH:mm:ss') %>
  </footer>
</body>
</html>
""";

Error Handling with Context

import groovy.text.TemplateExecutionException;
import groovy.text.TemplateParseException;

try {
    StreamingTemplateEngine engine = new StreamingTemplateEngine();
    Template template = engine.createTemplate(templateSource);
    String result = template.make(binding).toString();
} catch (TemplateExecutionException e) {
    // Enhanced error reporting with line numbers and context
    System.err.println("Template execution failed:");
    System.err.println(e.getMessage()); // Includes context lines
    System.err.println("Error at line: " + e.getLineNumber());
} catch (TemplateParseException e) {
    // Parse-time errors with line and column information
    System.err.println("Template parse error at line " + e.getLineNumber() + 
                      ", column " + e.getColumn() + ": " + e.getMessage());
} catch (Exception e) {
    System.err.println("Other template error: " + e.getMessage());
}

Performance Characteristics

Memory Usage

  • Streaming output: Generates content incrementally
  • Closure-based: Avoids large string concatenations
  • Garbage collection friendly: Reduces intermediate object creation
  • Large template support: Handles templates >64k without issues

Processing Speed

  • Optimized compilation: Efficient template-to-closure conversion
  • Reduced overhead: Minimal string manipulation during execution
  • Scalable: Performance scales well with template size

Error Handling Performance

  • Line tracking: Maintains source position information without significant overhead
  • Context generation: Efficient error context extraction
  • Stack trace sanitization: Cleaner exception traces

Servlet Integration

<!-- web.xml -->
<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>

When to Use StreamingTemplateEngine

Choose StreamingTemplateEngine when:

  1. Working with large templates (>64k characters)
  2. Memory efficiency is critical
  3. Need detailed error reporting with line numbers and context
  4. Processing templates with large datasets
  5. Streaming output to files or network rather than building strings
  6. Performance and scalability are important

Comparison with Other Engines

FeatureSimpleTemplateEngineGStringTemplateEngineStreamingTemplateEngine
Template size limit~64k~64kUnlimited
Memory efficiencyLowMediumHigh
Error reportingBasicBasicDetailed with context
PerformanceGoodBetterBest for large templates
Debugging featuresVerbose modeNoneScript source access

Best Practices

  1. Use for large templates: Prefer StreamingTemplateEngine for templates over 10k characters
  2. Stream to output: Use writeTo(Writer) instead of toString() for large outputs
  3. Handle errors properly: Take advantage of enhanced error reporting
  4. Reuse engine instances: Create engine once and reuse for multiple templates
  5. Use appropriate binding types: Prefer collections and iterators over large arrays for memory efficiency

Install with Tessl CLI

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

docs

basic-template-engines.md

index.md

markup-template-engine.md

streaming-template-engine.md

xml-template-engine.md

tile.json