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

markup-templates.mddocs/

Markup Templates

The MarkupTemplateEngine provides the most advanced template processing capabilities, leveraging StreamingMarkupBuilder for highly optimized XML/XHTML generation. It includes compile-time type checking, extensive configuration options, template caching, and a rich base template class for markup generation.

Capabilities

Markup Template Engine Class

Advanced template engine with type checking, configuration, and optimization features.

/**
 * Advanced template engine leveraging StreamingMarkupBuilder for optimized XML/XHTML generation.
 * Includes compile-time type checking, template caching, and extensive configuration options.
 */
public class MarkupTemplateEngine extends TemplateEngine {
    /**
     * Creates a new MarkupTemplateEngine with default configuration
     */
    public MarkupTemplateEngine();
    
    /**
     * Creates a new MarkupTemplateEngine with custom configuration
     * @param config TemplateConfiguration for engine settings
     */
    public MarkupTemplateEngine(TemplateConfiguration config);
    
    /**
     * Creates a new MarkupTemplateEngine with custom class loader and configuration
     * @param parentLoader ClassLoader for template compilation
     * @param config TemplateConfiguration for engine settings
     */
    public MarkupTemplateEngine(ClassLoader parentLoader, TemplateConfiguration config);
    
    /**
     * Creates a new MarkupTemplateEngine with full customization
     * @param parentLoader ClassLoader for template compilation
     * @param config TemplateConfiguration for engine settings
     * @param resolver TemplateResolver for resolving template resources
     */
    public MarkupTemplateEngine(ClassLoader parentLoader, TemplateConfiguration config, TemplateResolver resolver);
}

Template Configuration Class

Comprehensive configuration options for markup template generation.

/**
 * Configuration options for MarkupTemplateEngine
 */
public class TemplateConfiguration {
    /**
     * Creates a new TemplateConfiguration with default settings
     */
    public TemplateConfiguration();
    
    /**
     * Creates a copy of an existing TemplateConfiguration
     * @param that configuration to copy
     */
    public TemplateConfiguration(TemplateConfiguration that);
    
    // XML Declaration Configuration
    public String getDeclarationEncoding();
    public void setDeclarationEncoding(String declarationEncoding);
    
    // Element Formatting
    public boolean isExpandEmptyElements();
    public void setExpandEmptyElements(boolean expandEmptyElements);
    
    // Attribute Quoting
    public boolean isUseDoubleQuotes();
    public void setUseDoubleQuotes(boolean useDoubleQuotes);
    
    // Line Handling
    public String getNewLineString();
    public void setNewLineString(String newLineString);
    
    // Content Processing
    public boolean isAutoEscape();
    public void setAutoEscape(boolean autoEscape);
    
    // Indentation Control
    public boolean isAutoIndent();
    public void setAutoIndent(boolean autoIndent);
    public String getAutoIndentString();
    public void setAutoIndentString(String autoIndentString);
    
    // Newline Management
    public boolean isAutoNewLine();
    public void setAutoNewLine(boolean autoNewLine);
    
    // Template Base Class
    public Class<? extends BaseTemplate> getBaseTemplateClass();
    public void setBaseTemplateClass(Class<? extends BaseTemplate> baseTemplateClass);
    
    // Internationalization
    public Locale getLocale();
    public void setLocale(Locale locale);
    
    // Performance
    public boolean isCacheTemplates();
    public void setCacheTemplates(boolean cacheTemplates);
}

Base Template Class

Abstract base class providing utility methods for markup generation.

/**
 * Base class for all markup templates providing utility methods for markup generation.
 * Thread-safe when using distinct instances per thread/document.
 */
public abstract class BaseTemplate implements Writable {
    /**
     * Constructor for base template
     * @param templateEngine the markup template engine
     * @param model data model for template
     * @param modelTypes type information for model properties
     * @param configuration template configuration
     */
    public BaseTemplate(MarkupTemplateEngine templateEngine, Map model, Map<String,String> modelTypes, TemplateConfiguration configuration);
    
    /**
     * Get the template data model
     * @return Map containing template data
     */
    public Map getModel();
    
    /**
     * Execute the template logic
     * @return result of template execution
     */
    public abstract Object run();
    
    /**
     * Render object with XML escaping for safe output
     * @param obj object to render
     * @return this template instance for chaining
     * @throws IOException if output fails
     */
    public BaseTemplate yield(Object obj) throws IOException;
    
    /**
     * Render object without escaping (raw output)
     * @param obj object to render unescaped
     * @return this template instance for chaining
     * @throws IOException if output fails
     */
    public BaseTemplate yieldUnescaped(Object obj) throws IOException;
    
    /**
     * Create string representation of closure output
     * @param cl closure to execute and capture output
     * @return string representation of closure output
     * @throws IOException if output fails
     */
    public String stringOf(Closure cl) throws IOException;
    
    /**
     * Render XML comment
     * @param cs comment content
     * @return this template instance for chaining
     * @throws IOException if output fails
     */
    public BaseTemplate comment(Object cs) throws IOException;
    
    /**
     * Render XML declaration
     * @return this template instance for chaining
     * @throws IOException if output fails
     */
    public BaseTemplate xmlDeclaration() throws IOException;
    
    /**
     * Render processing instruction
     * @param attrs attributes for processing instruction
     * @return this template instance for chaining
     * @throws IOException if output fails
     */
    public BaseTemplate pi(Map<?, ?> attrs) throws IOException;
    
    /**
     * Handle dynamic method calls for tag generation
     * @param tagName name of the tag
     * @param args tag arguments
     * @return tag output
     * @throws IOException if output fails
     */
    public Object methodMissing(String tagName, Object args) throws IOException;
    
    /**
     * Include another Groovy template
     * @param templatePath path to template to include
     * @throws IOException if template loading or rendering fails
     * @throws ClassNotFoundException if template class cannot be found
     */
    public void includeGroovy(String templatePath) throws IOException, ClassNotFoundException;
    
    /**
     * Include template with escaped output
     * @param templatePath path to template to include
     * @throws IOException if template loading or rendering fails
     */
    public void includeEscaped(String templatePath) throws IOException;
    
    /**
     * Include template with unescaped output
     * @param templatePath path to template to include
     * @throws IOException if template loading or rendering fails
     */
    public void includeUnescaped(String templatePath) throws IOException;
    
    /**
     * Try to escape content if auto-escape is enabled
     * @param contents content to potentially escape
     * @return escaped or original content
     */
    public Object tryEscape(Object contents);
    
    /**
     * Get the output writer
     * @return the writer for template output
     */
    public Writer getOut();
    
    /**
     * Write a newline to output
     * @throws IOException if write fails
     */
    public void newLine() throws IOException;
    
    /**
     * Create template fragment from inline template text
     * @param model data model for fragment
     * @param templateText template source text
     * @return fragment output
     * @throws IOException if rendering fails
     * @throws ClassNotFoundException if template class cannot be found
     */
    public Object fragment(Map model, String templateText) throws IOException, ClassNotFoundException;
    
    /**
     * Apply layout template
     * @param model data model for layout
     * @param templateName name of layout template
     * @return layout output
     * @throws IOException if rendering fails
     * @throws ClassNotFoundException if template class cannot be found
     */
    public Object layout(Map model, String templateName) throws IOException, ClassNotFoundException;
    
    /**
     * Apply layout template with optional model inheritance
     * @param model data model for layout
     * @param templateName name of layout template
     * @param inheritModel whether to inherit current model
     * @return layout output
     * @throws IOException if rendering fails
     * @throws ClassNotFoundException if template class cannot be found
     */
    public Object layout(Map model, String templateName, boolean inheritModel) throws IOException, ClassNotFoundException;
    
    /**
     * Define content section for layout
     * @param cl closure defining content
     * @return content closure
     */
    public Closure contents(Closure cl);
}

Usage Examples:

import groovy.text.markup.MarkupTemplateEngine;
import groovy.text.markup.TemplateConfiguration;
import groovy.text.Template;
import java.util.Map;
import java.util.HashMap;
import java.util.Locale;

// Basic usage with default configuration
MarkupTemplateEngine engine = new MarkupTemplateEngine();

// Advanced configuration
TemplateConfiguration config = new TemplateConfiguration();
config.setAutoIndent(true);
config.setAutoIndentString("    "); // 4 spaces
config.setAutoNewLine(true);
config.setAutoEscape(true);
config.setUseDoubleQuotes(true);
config.setExpandEmptyElements(false);
config.setDeclarationEncoding("UTF-8");
config.setLocale(Locale.ENGLISH);

MarkupTemplateEngine configuredEngine = new MarkupTemplateEngine(config);

// Markup template using Groovy markup DSL
String template = """
html {
    head {
        title(pageTitle)
        meta(charset: 'UTF-8')
    }
    body {
        h1(pageTitle)
        div(class: 'content') {
            p("Welcome, \${user.name}!")
            ul {
                items.each { item ->
                    li(item.name)
                }
            }
        }
    }
}
""";

Template compiledTemplate = engine.createTemplate(template);

Map<String, Object> model = new HashMap<>();
model.put("pageTitle", "My Page");

Map<String, String> user = new HashMap<>();
user.put("name", "John Doe");
model.put("user", user);

List<Map<String, String>> items = Arrays.asList(
    Collections.singletonMap("name", "Item 1"),
    Collections.singletonMap("name", "Item 2"),
    Collections.singletonMap("name", "Item 3")
);
model.put("items", items);

String result = compiledTemplate.make(model).toString();

Markup DSL Syntax

MarkupTemplateEngine uses a Groovy-based DSL for generating markup:

Basic Element Creation

// Template syntax
html {
    head {
        title('My Page')
    }
    body {
        h1('Welcome')
        p('This is a paragraph')
    }
}

Elements with Attributes

// Elements with attributes
div(class: 'container', id: 'main') {
    img(src: '/images/logo.png', alt: 'Logo')
    a(href: 'https://example.com', target: '_blank', 'Click here')
}

// Empty elements
input(type: 'text', name: 'username', placeholder: 'Enter username')
br()
hr()

Variable Substitution

// Using variables from model
h1(pageTitle)
p("Welcome, ${user.name}!")

// Conditional content
if (user.isAdmin) {
    div(class: 'admin-panel') {
        p('Admin controls')
    }
}

Loops and Iteration

// Iterating over collections
ul {
    items.each { item ->
        li {
            a(href: item.url, item.title)
        }
    }
}

// With index
ol {
    products.eachWithIndex { product, index ->
        li("${index + 1}. ${product.name} - \$${product.price}")
    }
}

Configuration Options

Auto-Indentation

TemplateConfiguration config = new TemplateConfiguration();
config.setAutoIndent(true);
config.setAutoIndentString("  "); // 2 spaces (default)
// config.setAutoIndentString("\t"); // Use tabs
// config.setAutoIndentString("    "); // 4 spaces

Auto-Escaping

config.setAutoEscape(true); // Automatically escape content for XML safety

Element Formatting

// Control empty element format
config.setExpandEmptyElements(false); // <br/> (default)
config.setExpandEmptyElements(true);  // <br></br>

// Control attribute quotes
config.setUseDoubleQuotes(false); // class='container' (default)
config.setUseDoubleQuotes(true);  // class="container"

Line Handling

config.setAutoNewLine(true); // Automatically add newlines
config.setNewLineString("\n"); // Unix line endings (default)
config.setNewLineString("\r\n"); // Windows line endings

XML Declaration

config.setDeclarationEncoding("UTF-8"); // Adds <?xml version="1.0" encoding="UTF-8"?>

Template Caching

MarkupTemplateEngine supports template caching for improved performance:

TemplateConfiguration config = new TemplateConfiguration();
config.setCacheTemplates(true); // Enable caching (default)

MarkupTemplateEngine engine = new MarkupTemplateEngine(config);

// Templates are automatically cached and reused
Template template1 = engine.createTemplate(templateSource);
Template template2 = engine.createTemplate(templateSource); // Returns cached version

Custom Base Template

Extend BaseTemplate to add custom utility methods:

public class MyCustomTemplate extends BaseTemplate {
    public MyCustomTemplate(MarkupTemplateEngine engine, Map model, 
                           Map<String,String> modelTypes, TemplateConfiguration config) {
        super(engine, model, modelTypes, config);
    }
    
    // Custom helper method
    public MyCustomTemplate formatCurrency(double amount) throws IOException {
        yield(String.format("$%.2f", amount));
        return this;
    }
    
    // Custom helper for dates
    public MyCustomTemplate formatDate(Date date) throws IOException {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        yield(formatter.format(date));
        return this;
    }
}

// Configure engine to use custom base template
TemplateConfiguration config = new TemplateConfiguration();
config.setBaseTemplateClass(MyCustomTemplate.class);
MarkupTemplateEngine engine = new MarkupTemplateEngine(config);

Template Resolver

Interface for custom template path resolution.

/**
 * Interface for resolving template paths to URLs
 */
public interface TemplateResolver {
    /**
     * Configure the resolver with class loader and template configuration
     * @param templateClassLoader class loader for template compilation
     * @param configuration template configuration settings
     */
    void configure(ClassLoader templateClassLoader, TemplateConfiguration configuration);
    
    /**
     * Resolve template path to URL
     * @param templatePath path to resolve
     * @return URL for the template resource
     * @throws IOException if template cannot be found or accessed
     */
    URL resolveTemplate(String templatePath) throws IOException;
}

Built-in Resolvers:

/**
 * Default template resolver that searches classpath
 */
public static class DefaultTemplateResolver implements TemplateResolver {
    public DefaultTemplateResolver();
    public void configure(ClassLoader templateClassLoader, TemplateConfiguration configuration);
    public URL resolveTemplate(String templatePath) throws IOException;
}

/**
 * Caching template resolver for improved performance
 */
public static class CachingTemplateResolver extends DefaultTemplateResolver {
    public CachingTemplateResolver(Map<String, URL> cache);
    public CachingTemplateResolver();
    public void configure(ClassLoader templateClassLoader, TemplateConfiguration configuration);
    public URL resolveTemplate(String templatePath) throws IOException;
}

Usage Example:

public class MyTemplateResolver implements TemplateResolver {
    @Override
    public void configure(ClassLoader templateClassLoader, TemplateConfiguration configuration) {
        // Initialize resolver with classloader and configuration
    }
    
    @Override
    public URL resolveTemplate(String templatePath) throws IOException {
        // Custom logic for resolving template paths
        return getClass().getResource("/templates/" + templatePath);
    }
}

MyTemplateResolver resolver = new MyTemplateResolver();
MarkupTemplateEngine engine = new MarkupTemplateEngine(
    getClass().getClassLoader(), 
    new TemplateConfiguration(), 
    resolver
);

Type Checking

MarkupTemplateEngine includes compile-time type checking:

// Templates are type-checked at compile time
String template = """
html {
    body {
        // This would cause a compile-time error if 'user' is not defined in model
        p("Hello \${user.name}")
    }
}
""";

// Type information can be provided for better checking
Map<String, String> modelTypes = new HashMap<>();
modelTypes.put("user", "User"); // Specify that 'user' is of type 'User'

Advanced Features

Template Resource

Utility class for template path resolution with locale support.

/**
 * Represents a template resource with optional locale support
 */
public static class TemplateResource {
    /**
     * Parse a template path into a TemplateResource
     * @param fullPath the full template path
     * @return parsed TemplateResource
     */
    public static TemplateResource parse(String fullPath);
    
    /**
     * Create variant with specific locale
     * @param locale locale to use
     * @return TemplateResource with locale
     */
    public TemplateResource withLocale(String locale);
    
    /**
     * Check if this resource has a locale
     * @return true if locale is specified
     */
    public boolean hasLocale();
    
    /**
     * String representation of the resource path
     * @return string representation
     */
    public String toString();
}

Include Type Support

/**
 * Enumeration for different template inclusion types
 */
public enum IncludeType {
    template("includeGroovy"),
    escaped("includeEscaped"),
    unescaped("includeUnescaped");
    
    /**
     * Get the method name for this include type
     * @return method name
     */
    public String getMethodName();
}

Delegating Indent Writer

Writer that provides automatic indentation support for template output.

/**
 * Writer that delegates to another writer and provides indentation support
 */
public class DelegatingIndentWriter extends Writer {
    public static final String SPACES = "    ";
    public static final String TAB = "\t";
    
    /**
     * Create indent writer with default spaces indentation
     * @param delegate writer to delegate to
     */
    public DelegatingIndentWriter(Writer delegate);
    
    /**
     * Create indent writer with custom indentation
     * @param delegate writer to delegate to
     * @param indentString string to use for indentation
     */
    public DelegatingIndentWriter(Writer delegate, String indentString);
    
    /**
     * Increase indentation level
     * @return new indentation level
     */
    public int next();
    
    /**
     * Decrease indentation level
     * @return new indentation level
     */
    public int previous();
    
    /**
     * Write current indentation to output
     * @throws IOException if write fails
     */
    public void writeIndent() throws IOException;
    
    // Writer methods (inherited)
    public void write(int c) throws IOException;
    public void write(char[] cbuf) throws IOException;
    public void write(char[] cbuf, int off, int len) throws IOException;
    public void write(String str) throws IOException;
    public void write(String str, int off, int len) throws IOException;
    public Writer append(CharSequence csq) throws IOException;
    public Writer append(CharSequence csq, int start, int end) throws IOException;
    public Writer append(char c) throws IOException;
    public void flush() throws IOException;
    public void close() throws IOException;
}

Error Handling

MarkupTemplateEngine provides comprehensive error handling:

try {
    MarkupTemplateEngine engine = new MarkupTemplateEngine();
    Template template = engine.createTemplate(templateSource);
    String result = template.make(model).toString();
} catch (CompilationFailedException e) {
    // Template compilation failed due to syntax errors
    System.err.println("Compilation error: " + e.getMessage());
} catch (ClassNotFoundException e) {
    // Missing dependencies or custom base template class
    System.err.println("Class not found: " + e.getMessage());
} catch (IOException e) {
    // I/O error reading template source
    System.err.println("I/O error: " + e.getMessage());
} catch (Exception e) {
    // Runtime errors during template execution
    System.err.println("Runtime error: " + e.getMessage());
}

Best Practices

  1. Configuration Reuse: Create TemplateConfiguration once and reuse across engine instances
  2. Template Caching: Enable caching for frequently used templates
  3. Thread Safety: Use separate template instances per thread
  4. Custom Base Templates: Extend BaseTemplate for application-specific helpers
  5. Type Safety: Leverage compile-time type checking for robust templates
  6. Performance: Use MarkupTemplateEngine for high-performance markup generation
  7. Memory Management: Let unused templates be garbage collected

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