CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-freemarker--freemarker

Apache FreeMarker is a template engine: a Java library to generate text output based on templates and changing data.

Pending
Overview
Eval results
Files

template-models.mddocs/

Template Model System

The template model system provides interfaces for representing different data types in FreeMarker templates. These interfaces enable seamless integration between Java objects and template expressions.

Core Model Interfaces

Base Interface

interface TemplateModel {
  // Singleton constant representing null/empty values
  TemplateModel NOTHING = GeneralPurposeNothing.INSTANCE;
}

All template model interfaces extend this base interface. The NOTHING constant represents null or empty values in templates.

Scalar Models (Strings)

interface TemplateScalarModel extends TemplateModel {
  String getAsString() throws TemplateModelException;
}

// Simple implementation
class SimpleScalar implements TemplateScalarModel {
  SimpleScalar(String value);
  String getAsString() throws TemplateModelException;
}

Usage example:

TemplateModel stringValue = new SimpleScalar("Hello World");
// In template: ${stringValue} outputs "Hello World"

Number Models

interface TemplateNumberModel extends TemplateModel {
  Number getAsNumber() throws TemplateModelException;
}

// Simple implementation
class SimpleNumber implements TemplateNumberModel {
  SimpleNumber(Number value);
  Number getAsNumber() throws TemplateModelException;
}

Usage example:

TemplateModel numberValue = new SimpleNumber(42);
// In template: ${numberValue} outputs "42"
// In template: ${numberValue + 8} outputs "50"

Boolean Models

interface TemplateBooleanModel extends TemplateModel {
  boolean getAsBoolean() throws TemplateModelException;
  
  // Predefined constants
  TemplateBooleanModel TRUE = TrueBooleanModel.INSTANCE;
  TemplateBooleanModel FALSE = FalseBooleanModel.INSTANCE;
}

// True implementation
class TrueBooleanModel implements TemplateBooleanModel {
  static final TrueBooleanModel INSTANCE = new TrueBooleanModel();
  boolean getAsBoolean() throws TemplateModelException;
}

// False implementation  
class FalseBooleanModel implements TemplateBooleanModel {
  static final FalseBooleanModel INSTANCE = new FalseBooleanModel();
  boolean getAsBoolean() throws TemplateModelException;
}

Usage example:

TemplateModel isActive = TemplateBooleanModel.TRUE;
// In template: <#if isActive>Active</#if>

Date Models

interface TemplateDateModel extends TemplateModel {
  Date getAsDate() throws TemplateModelException;
  int getDateType();
  
  // Date type constants
  int DATE = 1;      // Date only (no time)
  int TIME = 2;      // Time only (no date)  
  int DATETIME = 3;  // Both date and time
  int UNKNOWN = 0;   // Unknown date type
}

// Simple implementation
class SimpleDate implements TemplateDateModel {
  SimpleDate(Date date, int type);
  Date getAsDate() throws TemplateModelException;
  int getDateType();
}

Usage example:

TemplateModel currentDate = new SimpleDate(new Date(), TemplateDateModel.DATETIME);
// In template: ${currentDate?string("yyyy-MM-dd HH:mm:ss")}

Collection Models

Sequence Models (Lists/Arrays)

interface TemplateSequenceModel extends TemplateModel {
  TemplateModel get(int index) throws TemplateModelException;
  int size() throws TemplateModelException;
}

// Simple implementation
class SimpleSequence extends WrappingTemplateModel implements TemplateSequenceModel {
  SimpleSequence();
  SimpleSequence(ObjectWrapper wrapper);
  SimpleSequence(Collection collection, ObjectWrapper wrapper);
  
  void add(Object obj);
  TemplateModel get(int index) throws TemplateModelException;
  int size() throws TemplateModelException;
  List toList() throws TemplateModelException;
}

Usage example:

SimpleSequence items = new SimpleSequence();
items.add("Apple");  
items.add("Banana");
items.add("Cherry");
// In template: <#list items as item>${item}</#list>

Hash Models (Maps/Objects)

interface TemplateHashModel extends TemplateModel {
  TemplateModel get(String key) throws TemplateModelException;
  boolean isEmpty() throws TemplateModelException;
}

// Extended hash model with iteration capabilities
interface TemplateHashModelEx extends TemplateHashModel {
  TemplateCollectionModel keys() throws TemplateModelException;
  TemplateCollectionModel values() throws TemplateModelException;
  int size() throws TemplateModelException;
}

// Enhanced hash model with key-value iteration
interface TemplateHashModelEx2 extends TemplateHashModelEx {
  KeyValuePairIterator keyValuePairIterator() throws TemplateModelException;
}

// Simple implementation
class SimpleHash extends WrappingTemplateModel implements TemplateHashModelEx2 {
  SimpleHash();
  SimpleHash(ObjectWrapper wrapper);
  SimpleHash(Map map, ObjectWrapper wrapper);
  
  void put(String key, Object value);
  void put(String key, boolean value);
  void put(String key, Number value);
  void remove(String key);
  void clear();
  
  TemplateModel get(String key) throws TemplateModelException;
  boolean isEmpty() throws TemplateModelException;
  int size() throws TemplateModelException;
  TemplateCollectionModel keys() throws TemplateModelException;
  TemplateCollectionModel values() throws TemplateModelException;
  KeyValuePairIterator keyValuePairIterator() throws TemplateModelException;
}

Usage example:

SimpleHash person = new SimpleHash();
person.put("name", "John Doe");
person.put("age", 30);
person.put("active", true);
// In template: ${person.name} is ${person.age} years old

Collection Models (Iteration)

interface TemplateCollectionModel extends TemplateModel {
  TemplateModelIterator iterator() throws TemplateModelException;
}

// Extended collection with size information
interface TemplateCollectionModelEx extends TemplateCollectionModel {
  int size() throws TemplateModelException;
}

// Simple implementation
class SimpleCollection extends WrappingTemplateModel implements TemplateCollectionModelEx {
  SimpleCollection(Collection collection);
  SimpleCollection(Collection collection, ObjectWrapper wrapper);
  SimpleCollection(Iterator iterator);
  SimpleCollection(Iterator iterator, ObjectWrapper wrapper);
  
  TemplateModelIterator iterator() throws TemplateModelException;
  int size() throws TemplateModelException;
}

Functional Models

Method Models

interface TemplateMethodModel extends TemplateModel {
  Object exec(List arguments) throws TemplateModelException;
}

// Enhanced method model with TemplateModel arguments
interface TemplateMethodModelEx extends TemplateMethodModel {
  Object exec(List arguments) throws TemplateModelException;
}

Usage example:

TemplateMethodModelEx upperCase = new TemplateMethodModelEx() {
    public Object exec(List arguments) throws TemplateModelException {
        if (arguments.size() != 1) {
            throw new TemplateModelException("Wrong number of arguments");
        }
        String s = ((TemplateScalarModel) arguments.get(0)).getAsString();
        return new SimpleScalar(s.toUpperCase());
    }
};
// In template: ${upperCase("hello")} outputs "HELLO"

Directive Models

interface TemplateDirectiveModel extends TemplateModel {
  void execute(Environment env, Map params, TemplateModel[] loopVars, 
               TemplateDirectiveBody body) throws TemplateException, IOException;
}

// Body interface for directive content
interface TemplateDirectiveBody {
  void render(Writer out) throws TemplateException, IOException;
}

Usage example:

TemplateDirectiveModel repeat = new TemplateDirectiveModel() {
    public void execute(Environment env, Map params, TemplateModel[] loopVars, 
                       TemplateDirectiveBody body) throws TemplateException, IOException {
        int count = ((TemplateNumberModel) params.get("count")).getAsNumber().intValue();
        for (int i = 0; i < count; i++) {
            loopVars[0] = new SimpleNumber(i);
            body.render(env.getOut());
        }
    }
};
// In template: <@repeat count=3 ; i>Item ${i}</@repeat>

Transform Models

interface TemplateTransformModel extends TemplateModel {
  Writer getWriter(Writer out, Map args) throws TemplateModelException, IOException;
}

Usage example:

TemplateTransformModel upperCaseTransform = new TemplateTransformModel() {
    public Writer getWriter(Writer out, Map args) throws TemplateModelException, IOException {
        return new FilterWriter(out) {
            public void write(String str) throws IOException {
                out.write(str.toUpperCase());
            }
        };
    }
};
// In template: <@upperCaseTransform>hello world</@upperCaseTransform>

Node Models (XML/Tree Structures)

interface TemplateNodeModel extends TemplateModel {
  TemplateModel get(String key) throws TemplateModelException;
  TemplateSequenceModel getChildNodes() throws TemplateModelException;
  String getNodeName() throws TemplateModelException;
  String getNodeType() throws TemplateModelException;
  TemplateNodeModel getParentNode() throws TemplateModelException;
}

// Extended node model with namespace support
interface TemplateNodeModelEx extends TemplateNodeModel {
  String getNodeNamespace() throws TemplateModelException;
  String getNamespaceURI(String prefix) throws TemplateModelException;
}

Iteration Support

interface TemplateModelIterator {
  TemplateModel next() throws TemplateModelException;
  boolean hasNext() throws TemplateModelException;
}

interface KeyValuePairIterator {
  KeyValuePair next() throws TemplateModelException;
  boolean hasNext() throws TemplateModelException;
}

interface KeyValuePair {
  TemplateModel getKey() throws TemplateModelException;
  TemplateModel getValue() throws TemplateModelException;
}

Adapter Classes

Collection Adapters

class DefaultListAdapter extends WrappingTemplateModel implements TemplateSequenceModel, AdapterTemplateModel {
  DefaultListAdapter(List list, ObjectWrapper wrapper);
  TemplateModel get(int index) throws TemplateModelException;
  int size() throws TemplateModelException;
  Object getAdaptedObject(Class hint);
}

class DefaultMapAdapter extends WrappingTemplateModel implements TemplateHashModelEx2, AdapterTemplateModel {
  DefaultMapAdapter(Map map, ObjectWrapper wrapper);
  TemplateModel get(String key) throws TemplateModelException;
  boolean isEmpty() throws TemplateModelException;
  int size() throws TemplateModelException;
  TemplateCollectionModel keys() throws TemplateModelException;
  TemplateCollectionModel values() throws TemplateModelException;
  Object getAdaptedObject(Class hint);
}

class DefaultArrayAdapter extends WrappingTemplateModel implements TemplateSequenceModel, AdapterTemplateModel {
  DefaultArrayAdapter(Object array, ObjectWrapper wrapper);
  TemplateModel get(int index) throws TemplateModelException;
  int size() throws TemplateModelException;
  Object getAdaptedObject(Class hint);
}

Iterator Adapters

class DefaultIteratorAdapter extends WrappingTemplateModel implements TemplateCollectionModel, AdapterTemplateModel {
  DefaultIteratorAdapter(Iterator iterator, ObjectWrapper wrapper);
  TemplateModelIterator iterator() throws TemplateModelException;
  Object getAdaptedObject(Class hint);
}

class DefaultEnumerationAdapter extends WrappingTemplateModel implements TemplateCollectionModel, AdapterTemplateModel {
  DefaultEnumerationAdapter(Enumeration enumeration, ObjectWrapper wrapper);
  TemplateModelIterator iterator() throws TemplateModelException;
  Object getAdaptedObject(Class hint);
}

Utility Classes

abstract class WrappingTemplateModel implements TemplateModel, AdapterTemplateModel {
  WrappingTemplateModel(ObjectWrapper objectWrapper);
  ObjectWrapper getObjectWrapper();
  TemplateModel wrap(Object obj) throws TemplateModelException;
}

// Represents null/nothing values
class GeneralPurposeNothing implements TemplateModel {
  static final GeneralPurposeNothing INSTANCE = new GeneralPurposeNothing();
}

// For wrapping objects that implement multiple model interfaces
interface AdapterTemplateModel extends TemplateModel {
  Object getAdaptedObject(Class hint);
}

Model Creation Best Practices

Using Simple Model Classes

For basic use cases, use the Simple* classes:

// Create simple models
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("title", "My Page");  // Auto-wrapped to SimpleScalar
dataModel.put("count", 42);         // Auto-wrapped to SimpleNumber  
dataModel.put("active", true);      // Auto-wrapped to TrueBooleanModel

// Or create explicitly
dataModel.put("message", new SimpleScalar("Hello"));
dataModel.put("items", new SimpleSequence(Arrays.asList("A", "B", "C")));

Custom Model Implementation

For complex scenarios, implement model interfaces directly:

public class ProductModel implements TemplateHashModel {
    private Product product;
    
    public ProductModel(Product product) {
        this.product = product;
    }
    
    public TemplateModel get(String key) throws TemplateModelException {
        if ("name".equals(key)) return new SimpleScalar(product.getName());
        if ("price".equals(key)) return new SimpleNumber(product.getPrice());
        if ("inStock".equals(key)) return product.isInStock() ? 
            TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
        return null;
    }
    
    public boolean isEmpty() {
        return false;
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-freemarker--freemarker

docs

caching-loading.md

core-processing.md

exception-handling.md

extensions.md

index.md

object-wrapping.md

output-formats.md

template-models.md

tile.json