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

caching-loading.mddocs/

Template Caching and Loading

FreeMarker provides a flexible system for loading templates from various sources and caching them for optimal performance. The template loading and caching system consists of template loaders, cache storage, and lookup strategies.

Template Loader Interface

The core interface for loading template sources:

interface TemplateLoader {
  Object findTemplateSource(String name) throws IOException;
  long getLastModified(Object templateSource);
  Reader getReader(Object templateSource, String encoding) throws IOException;
  void closeTemplateSource(Object templateSource) throws IOException;
}

// Enhanced template loader with state information
interface StatefulTemplateLoader extends TemplateLoader {
  void resetState();
}

Built-in Template Loaders

File Template Loader

Loads templates from the file system:

class FileTemplateLoader implements TemplateLoader {
  // Constructors
  FileTemplateLoader(File baseDir) throws IOException;
  FileTemplateLoader(File baseDir, boolean disableCanonicalization) throws IOException;
  
  // TemplateLoader methods
  Object findTemplateSource(String name) throws IOException;
  long getLastModified(Object templateSource);
  Reader getReader(Object templateSource, String encoding) throws IOException;
  void closeTemplateSource(Object templateSource) throws IOException;
  
  // Configuration methods
  File getBaseDirectory();
  boolean getEagerCanonicalization();
}

Usage example:

// Load templates from /path/to/templates directory
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
cfg.setTemplateLoader(new FileTemplateLoader(new File("/path/to/templates")));

// Or use the convenience method
cfg.setDirectoryForTemplateLoading(new File("/path/to/templates"));

Class Template Loader

Loads templates from the classpath:

class ClassTemplateLoader extends URLTemplateLoader {
  // Constructors
  ClassTemplateLoader(Class resourceLoaderClass, String basePackagePath);
  
  // URLTemplateLoader methods
  URL getURL(String name);
}

Usage example:

// Load templates from classpath under /templates package
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
cfg.setTemplateLoader(new ClassTemplateLoader(MyClass.class, "/templates"));

// Or use the convenience method
cfg.setClassForTemplateLoading(MyClass.class, "/templates");

String Template Loader

Loads templates from strings stored in memory:

class StringTemplateLoader implements TemplateLoader {
  // Constructor
  StringTemplateLoader();
  
  // Template management
  void putTemplate(String name, String templateSource);
  void putTemplate(String name, String templateSource, long lastModified);
  void removeTemplate(String name);
  void closeTemplateSource(Object templateSource) throws IOException;
  
  // TemplateLoader methods
  Object findTemplateSource(String name) throws IOException;
  long getLastModified(Object templateSource);
  Reader getReader(Object templateSource, String encoding) throws IOException;
}

Usage example:

StringTemplateLoader loader = new StringTemplateLoader();
loader.putTemplate("hello.ftl", "<html><body>Hello ${name}!</body></html>");
loader.putTemplate("email.ftl", "Dear ${recipient}, Your order #${orderNumber} is ready.");

Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
cfg.setTemplateLoader(loader);

Multi Template Loader

Combines multiple template loaders:

class MultiTemplateLoader implements StatefulTemplateLoader {
  // Constructor
  MultiTemplateLoader(TemplateLoader[] loaders);
  
  // StatefulTemplateLoader methods
  Object findTemplateSource(String name) throws IOException;
  long getLastModified(Object templateSource);
  Reader getReader(Object templateSource, String encoding) throws IOException;
  void closeTemplateSource(Object templateSource) throws IOException;
  void resetState();
  
  // Configuration methods
  TemplateLoader[] getTemplateLoaders();
}

Usage example:

// Combine file system and classpath loading
TemplateLoader[] loaders = {
    new FileTemplateLoader(new File("/custom/templates")),
    new ClassTemplateLoader(MyClass.class, "/default/templates")
};

Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
cfg.setTemplateLoader(new MultiTemplateLoader(loaders));

URL Template Loader

Abstract base class for URL-based template loading:

abstract class URLTemplateLoader implements TemplateLoader {
  // Abstract method to be implemented by subclasses
  protected abstract URL getURL(String name);
  
  // TemplateLoader implementation
  Object findTemplateSource(String name) throws IOException;
  long getLastModified(Object templateSource);
  Reader getReader(Object templateSource, String encoding) throws IOException;
  void closeTemplateSource(Object templateSource) throws IOException;
  
  // Configuration methods
  void setURLConnectionUsesCaches(Boolean urlConnectionUsesCaches);
  Boolean getURLConnectionUsesCaches();
}

Webapp Template Loader

Loads templates from servlet context:

class WebappTemplateLoader implements TemplateLoader {
  // Constructors
  WebappTemplateLoader(ServletContext servletContext);
  WebappTemplateLoader(ServletContext servletContext, String subdirPath);
  
  // TemplateLoader methods
  Object findTemplateSource(String name) throws IOException;
  long getLastModified(Object templateSource);
  Reader getReader(Object templateSource, String encoding) throws IOException;
  void closeTemplateSource(Object templateSource) throws IOException;
}

Usage example:

// In a servlet context
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
cfg.setTemplateLoader(new WebappTemplateLoader(servletContext, "/WEB-INF/templates"));

Cache Storage

Cache Storage Interface

interface CacheStorage {
  Object get(Object key);
  void put(Object key, Object value);
  void remove(Object key);
  void clear();
}

// Enhanced cache storage with size information
interface CacheStorageWithGetSize extends CacheStorage {
  int getSize();
}

// Thread-safe cache storage
interface ConcurrentCacheStorage extends CacheStorage {
  // Marker interface for thread-safe implementations
}

Built-in Cache Storage Implementations

MRU Cache Storage

Most Recently Used cache with configurable size limits:

class MruCacheStorage implements CacheStorageWithGetSize {
  // Constructors
  MruCacheStorage(int maxStrongSize);
  MruCacheStorage(int maxStrongSize, int maxSoftSize);
  
  // CacheStorage methods
  Object get(Object key);
  void put(Object key, Object value);
  void remove(Object key);
  void clear();
  int getSize();
  
  // Configuration methods
  int getMaxStrongSize();
  int getMaxSoftSize();
}

Usage example:

// Cache up to 100 templates with strong references, 1000 with soft references
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
cfg.setCacheStorage(new MruCacheStorage(100, 1000));

Soft Cache Storage

Uses soft references for automatic memory management:

class SoftCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize {
  // Constructor
  SoftCacheStorage();
  
  // CacheStorage methods
  Object get(Object key);
  void put(Object key, Object value);
  void remove(Object key);
  void clear();
  int getSize();
}

Strong Cache Storage

No automatic eviction - cached items remain until explicitly removed:

class StrongCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize {
  // Constructor
  StrongCacheStorage();
  
  // CacheStorage methods
  Object get(Object key);
  void put(Object key, Object value);
  void remove(Object key);
  void clear();
  int getSize();
}

Null Cache Storage

Disables caching completely:

class NullCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize {
  // Singleton instance
  static final NullCacheStorage INSTANCE = new NullCacheStorage();
  
  // Constructor
  NullCacheStorage();
  
  // CacheStorage methods (all no-ops)
  Object get(Object key);
  void put(Object key, Object value);
  void remove(Object key);
  void clear();
  int getSize();
}

Cache Configuration Examples

// Default cache (MRU with reasonable limits)
Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
// Uses default MruCacheStorage

// Custom MRU cache
cfg.setCacheStorage(new MruCacheStorage(50, 200));

// Soft references cache (good for memory-constrained environments)
cfg.setCacheStorage(new SoftCacheStorage());

// Strong cache (never evicts, good for small template sets)
cfg.setCacheStorage(new StrongCacheStorage());

// Disable caching (useful for development)
cfg.setCacheStorage(NullCacheStorage.INSTANCE);

Template Lookup Strategy

Controls how templates are resolved and loaded:

abstract class TemplateLookupStrategy {
  // Main lookup method
  abstract TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException;
  
  // Default strategy constants
  static final TemplateLookupStrategy DEFAULT_2_3_0 = DefaultTemplateLookupStrategy.INSTANCE;
}

// Lookup context
class TemplateLookupContext {
  String getTemplateName();
  Locale getTemplateLocale();
  String getCustomLookupCondition();
  TemplateLoader getTemplateLoader();
}

// Lookup result
abstract class TemplateLookupResult {
  abstract boolean isPositive();
}

Template Name Format

Controls template name formatting and normalization:

abstract class TemplateNameFormat {
  // Name formatting methods
  abstract String normalizeAbsoluteName(String name) throws MalformedTemplateNameException;
  abstract String normalizeName(String name) throws MalformedTemplateNameException;
  abstract String toAbsoluteName(String baseName, String targetName) throws MalformedTemplateNameException;
  abstract String toRootBasedName(String baseName, String targetName) throws MalformedTemplateNameException;
  
  // Default format constants
  static final TemplateNameFormat DEFAULT_2_3_0 = DefaultTemplateNameFormat.INSTANCE_2_3_0;
  static final TemplateNameFormat DEFAULT_2_4_0 = DefaultTemplateNameFormat.INSTANCE_2_4_0;
}

Template Configuration

Per-template configuration using matchers:

abstract class TemplateConfigurationFactory {
  abstract TemplateConfiguration get(String sourceName, Object templateSource) throws IOException, TemplateConfigurationFactory.TemplateConfigurationFactoryException;
}

class ConditionalTemplateConfigurationFactory extends TemplateConfigurationFactory {
  // Constructor
  ConditionalTemplateConfigurationFactory(TemplateSourceMatcher matcher, TemplateConfigurationFactory factory);
  
  TemplateConfiguration get(String sourceName, Object templateSource) throws IOException, TemplateConfigurationFactoryException;
}

// Template-specific configuration
class TemplateConfiguration extends Configurable implements ParserConfiguration {
  TemplateConfiguration();
  
  // Apply configuration to parent configurable
  void apply(Configurable configurable);
}

Template Source Matchers

Match templates based on various criteria:

abstract class TemplateSourceMatcher {
  abstract boolean matches(String sourceName, Object templateSource) throws IOException;
}

// Path glob matching
class PathGlobMatcher extends TemplateSourceMatcher {
  PathGlobMatcher(String glob);
  PathGlobMatcher(String glob, boolean caseSensitive);
  boolean matches(String sourceName, Object templateSource) throws IOException;
}

// File extension matching
class FileExtensionMatcher extends TemplateSourceMatcher {
  FileExtensionMatcher(String extension);
  FileExtensionMatcher(String extension, boolean caseSensitive);
  boolean matches(String sourceName, Object templateSource) throws IOException;
}

// OR matcher - matches if any submatcher matches
class OrMatcher extends TemplateSourceMatcher {
  OrMatcher(TemplateSourceMatcher... matchers);
  boolean matches(String sourceName, Object templateSource) throws IOException;
}

Template Configuration Examples

Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);

// Configure specific output format for HTML templates
TemplateConfiguration htmlConfig = new TemplateConfiguration();
htmlConfig.setOutputFormat(HTMLOutputFormat.INSTANCE);
htmlConfig.setAutoEscapingPolicy(Configuration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY);

cfg.setTemplateConfigurations(
    new ConditionalTemplateConfigurationFactory(
        new FileExtensionMatcher("html"), 
        new FirstMatchTemplateConfigurationFactory(htmlConfig)
    )
);

// Configure different settings for email templates
TemplateConfiguration emailConfig = new TemplateConfiguration();
emailConfig.setOutputFormat(PlainTextOutputFormat.INSTANCE);
emailConfig.setWhitespaceStripping(true);

cfg.setTemplateConfigurations(
    new ConditionalTemplateConfigurationFactory(
        new PathGlobMatcher("email/**"),
        new FirstMatchTemplateConfigurationFactory(emailConfig)
    )
);

Cache Management

Cache Control Methods

// In Configuration class
void clearTemplateCache();
void removeTemplateFromCache(String name);
void removeTemplateFromCache(String name, Locale locale);
void removeTemplateFromCache(String name, Locale locale, String encoding);
void removeTemplateFromCache(String name, Locale locale, String encoding, boolean parseAsFTL);

// Cache statistics (if supported by cache storage)
CacheStorage getCacheStorage();

Cache Monitoring Example

Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);
MruCacheStorage cache = new MruCacheStorage(100, 500);
cfg.setCacheStorage(cache);

// Monitor cache size
System.out.println("Cache size: " + cache.getSize());
System.out.println("Max strong size: " + cache.getMaxStrongSize());

// Clear specific templates from cache
cfg.removeTemplateFromCache("outdated-template.ftl");

// Clear entire cache
cfg.clearTemplateCache();

Performance Optimization

Template Loading Best Practices

  1. Use appropriate cache storage: Choose based on memory constraints and template count
  2. Configure cache size limits: Set limits based on your application's template usage patterns
  3. Use template pre-loading: Load frequently used templates at startup
  4. Monitor cache hit rates: Adjust cache size based on actual usage patterns

Example: High-Performance Configuration

Configuration cfg = new Configuration(Configuration.VERSION_2_3_34);

// Optimized for high-throughput applications
cfg.setTemplateLoader(new FileTemplateLoader(new File("templates")));
cfg.setCacheStorage(new MruCacheStorage(500, 2000)); // Large cache
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false); // Reduce logging overhead
cfg.setWrapUncheckedExceptions(true);

// Pre-load critical templates
cfg.getTemplate("header.ftl");
cfg.getTemplate("footer.ftl");
cfg.getTemplate("main-layout.ftl");

Custom Template Loader Example

public class DatabaseTemplateLoader implements TemplateLoader {
    private final DataSource dataSource;
    
    public DatabaseTemplateLoader(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    @Override
    public Object findTemplateSource(String name) throws IOException {
        try (Connection conn = dataSource.getConnection();
             PreparedStatement stmt = conn.prepareStatement(
                 "SELECT content, last_modified FROM templates WHERE name = ?")) {
            
            stmt.setString(1, name);
            ResultSet rs = stmt.executeQuery();
            
            if (rs.next()) {
                return new DatabaseTemplateSource(
                    name, 
                    rs.getString("content"), 
                    rs.getTimestamp("last_modified").getTime()
                );
            }
            return null;
        } catch (SQLException e) {
            throw new IOException("Failed to load template: " + name, e);
        }
    }
    
    @Override
    public long getLastModified(Object templateSource) {
        return ((DatabaseTemplateSource) templateSource).getLastModified();
    }
    
    @Override
    public Reader getReader(Object templateSource, String encoding) throws IOException {
        String content = ((DatabaseTemplateSource) templateSource).getContent();
        return new StringReader(content);
    }
    
    @Override
    public void closeTemplateSource(Object templateSource) throws IOException {
        // Nothing to close for database templates
    }
    
    private static class DatabaseTemplateSource {
        private final String name;
        private final String content;
        private final long lastModified;
        
        DatabaseTemplateSource(String name, String content, long lastModified) {
            this.name = name;
            this.content = content;
            this.lastModified = lastModified;
        }
        
        String getContent() { return content; }
        long getLastModified() { return lastModified; }
    }
}

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