1. What is Trimou?

Trimou is yet another Mustache implementation written in Java. It’s goal is to provide a simple to use and easy to extend templating engine for any Java SE or Java EE application. So far there are four ready-to-use extensions which provide integration with CDI, Servlets, PrettyTime, HtmlCompressor and google-gson (see Extensions section for more info).

Trimou is available under the Apache License 2.0.

2. Features

The basic features of every Mustache implementation are defined in the Mustache spec. Trimou passes all the tests (version 1.1.2), except "Section - Alternate Delimiters" from lambdas optional module.

The most notable enhancements are:

  • Template caching

  • Extended processing of lambdas

  • Template inheritance

  • Very basic i18n support

  • Extension points (template locators, resolvers, text support, …)

2.1. Variables, interpolation tags

The interpolation tag’s content is called a key hereafter. The key consists of one or more dot-separated parts - a key part ("foo"["foo"], "foo.bar.name"["foo, "bar", "name"]). The current object the key part is resolved against is called a context object hereafter.

In general Trimou interpolation works very similar to the spec description - walk the context object stack from top to bottom, and resolve the value for the given part of the key (first part againts the context stack, other parts against the result from the former resolution).

However there are some differences:

  • it’s possible to use this keyword to reference the object atop the context object stack; the spec only allows .,

  • if the context object is an instance of a java.util.Map, value of the entry with the given key is resolved,

  • for any context object Trimou tries to:

    • find and invoke an accessible public method with no params, non-void return type and name keypart, getKeypart or isKeypart defined on the context object’s class and its superclasses (except for java.lang.Object),

    • find an accessible public field with name keypart and get its value,

  • java.util.List and array elements can be accessed via index (the key must be unsigned integer),

  • iterIndex, iterHasNext, iterIsFirst and iterIsLast keywords can be used inside an iteration block,

  • Trimou allows you to define a resolver that does not handle the context object stack at all (e.g. looks up a CDI bean).

{{foo}} <1>

{{foo.bar}} <2>

{{list.0}} <3>

{{array.5}} <4>

  {{iterIndex}} <5>
  {{#iterIsFirst}} The is the first one! {{/iterIsFirst}} <6>
  {{#iterIsLast}} This is the last one! {{/iterIsLast}} <7>
  {{name}} <8>
  {{#iterHasNext}}, {{/iterHasNext}} <9>

{{#quxEnumClass.values}} <10>
  1. Try to get a value of key "foo" from the context object stack, e.g. if the supplied data context object is an instance of Map get the value of key "foo"

  2. Try to get a value of key "bar" from the context object resolved in <1>, e.g. try to invoke bar(), getBar() or isBar() on the "foo" instance or get the value of the field with name "bar"

  3. Get the first element

  4. Get the sixth element

  5. The current index of the iteration block

  6. Render the text for the first iteration

  7. Render the text for the last iteration

  8. "name" is resolved against the context object stack (iteration element, supplied data map)

  9. Render a comma if the iteration has more elements (iterHasNext is true)

  10. It’s also possible to invoke static methods; quxEnumClass is an enum class here and we iterate over the array returned from static method values()

The set of resolvers may be extended - so in fact the above mentioned applies to the default set of resolvers only.

2.1.1. Escaping HTML

The interpolated value is escaped unless & is used. The spec only tests the basic escaping (&, ", <, >). Trimou also escapes all ISO-8859-1 characters by default.

{{foo}} <1>

{{& foo}} <2>

{{{foo}}} <3>
  1. Escape foo

  2. Do not escape foo

  3. Do not escape foo; works only for default delimiters!

You can implement your own escaping logic, e.g. to improve escaping performance - see Configure the engine and TextSupport sections.

2.2. Sections

The section content is rendered one or more times if there is an object found for the given key. If the found object is:

  • non-empty Iterable or array, the content is rendered for each element,

  • a Boolean of value true, the content is rendered once,

  • an instance of Lambda, the content is processed according to the lambda’s specification,

  • any other non-null object represents a nested context.

The section content is not rendered if there is no object found, or the found object is:

  • a Boolean of value false,

  • an Iterable with no elements,

  • an empty array.

   This line will be rendered only if "boolean" key resolves to java.lang.Boolean#TRUE, or true

  This line will be rendered for each element, and the element is pushed on the context object stack

2.3. Inverted sections

The content is rendered if there is no object found in the context, or is a Boolean of value false, or is an Iterable with no elements, or is an empty array.

  This line will be rendered if the resolved iterable has no elements

2.4. Partials

Partials only work if at least one template locator is in action. Otherwise the template cache is not used and there is no way to locate the required partial (template). See Configure the engine and Template locator sections for more info.

  {{>item_detail}} - process the template with name "item_detail" for each iteration element

2.5. Delimiters

{{=%% %%=}} - from now on use custom delimiters

%%foo.name%% - interpolate "foo.name"

%%={{ }}=%% - switch back to default values
It’s also possible to change the delimiters globally, see Configuration.

2.6. Lambdas

You can implement org.trimou.lambda.Lambda interface in order to define a lambda/callable object. Predefined abstract org.trimou.lambda.SpecCompliantLambda follows the behaviour defined by the spec:

Lambda makeMeBold = new SpecCompliantLambda() {
  public String invoke(String text) {
    return "<b>" + text + "</b>";

and template

  Any text...{{name}}

results in:

  <b>Any text...{{name}}</b>
-> the variable is not interpolated

However this might be a little bit more useful:

Lambda makeMeUppercase = new InputProcessingLambda() {
  public String invoke(String text) {
    return text.toUpperCase();
  public boolean isReturnValueInterpolated() {
    return false;

and template

  Any text...{{name}}

results in:

-> the variable is interpolated before the lambda invoke() method is invoked

See org.trimou.lambda.Lambda API javadoc for more info.

2.7. Extending templates

This feature is not supported in the spec. Trimou basically follows the way mustache.java implements the template inheritance. In the extended template, the sections to extend are defined - use $ to identify such sections. In extending templates, the extending sections are defined - again, use $ to identify such sections. Sections to extend may define the default content.

Following template with name "super":

This a template to extend
{{$header}} -> section to extend
  The default header
In between...
{{$content}} -> section to extend
  The default content
&copy; 2013

can be extended in this way:

Hello world!
  {{$header}} -> extending section
    My own header
  Only extending sections are considered...

and the result is:

Hello world!
This a template to extend <1>
    My own header <2>
In between...
  The default content <3>
&copy; 2013 <4>
  1. "super start

  2. section "header" is extended

  3. section "content" has the default content

  4. "super" end

2.8. Built-in helpers

Since version 1.5.0 handlebars-like helpers are supported. There are five helpers registered automatically: if, unless, each, with (see http://handlebarsjs.com for examples :-) and is (an inline version of if). Other helpers may be registered via MustacheEngineBuilder.registerHelper(String, Helper). See also Helper section.

Handlebars support is enabled by default. See HANDLEBARS_SUPPORT_ENABLED in Configuration properties.

3. How to use

3.1. Get started

First, get the trimou-core.jar and its dependencies (guava,slf4j-api and commons-lang3 at the moment).


And now for something completely different…

3.1.1. The simplest possible scenario

String data = "Hello world!";
String template = "{{this}}";
MustacheEngine engine = MustacheEngineBuilder.newBuilder().build(); <1>
Mustache mustache = engine.compileMustache("myTemplateName", template); <2>
String output = mustache.render(data); <3>

<1> <2> <3>
String output = MustacheEngineBuilder
                  .compileMustache("myTemplateName", template)

// Both snippets will render "Hello world!"
  1. Build the engine

  2. Compile the template

  3. Render the template

Instances of MustacheEngineBuilder are not reusable. The builder is considered immutable once the build() method is called - subsequent invocations of some MustacheEngineBuilder methods result in IllegalStateException.

3.1.2. Provide your own Appendable

MustacheEngine engine = MustacheEngineBuilder.newBuilder().build();
Mustache mustache = engine.compileMustache("fooTemplate", "{{foo}}");

// It's possible to pass a java.lang.Appendable impl, e.g. any java.io.Writer
StringWriter writer = new StringWriter();

mustache.render(writer, ImmutableMap.<String, Object> of("foo", "bar"));
// writer.toString() -> "bar"

3.1.3. Configure the engine

You may want to:

Simply use appropriate MustacheEngineBuilder methods, e.g.:

MustacheEngine engine = MustacheEngineBuilder
                            .addGlobalData("fooLambda", mySuperUsefulLambdaInstance)

3.2. Make use of template cache and template locators

Template locators automatically locate the template contents for the given template id (name, path, …). So that it’s not necessary to supply the template contents every time the template is compiled. Moreover if the template cache is enabled the compiled template is automatically put in the cache and no compilation happens the next time the template is requested.

Template locators are required for partials!
MustacheEngine engine = MustacheEngineBuilder
                           .addTemplateLocator(new FilesystemTemplateLocator(1, "/home/trimou/resources", "txt")) <1>
Mustache mustache = engine.getMustache("foo"); <2>
String output = mustache.render(null);
  1. Add a filesystem-based template locator with priority 1, root path "/home/trim/resources", template files have suffix "txt"

  2. Get the template with name "foo" from the template cache, compile it if not compiled before

There may be more than one template locators registered with the engine. Locators with higher priority are called first.

Use MustacheEngine#invalidateTemplateCache() to invalidate all template cache entries and force recompilation.

3.2.1. Note about file encoding

Trimou does not perform any file encoding detection and conversion. Instead any template locator must provide a java.io.Reader instance which is able to convert between Unicode and a other character encodings. Built-in locators don’t detect file encoding but use system file encoding by default. But it’s possible (and recommended) to define the default file encoding with configuration property EngineConfigurationKey.DEFAULT_FILE_ENCODING (see also configuration properties).

Applications are encouraged to always define a default file encoding per every MustacheEngine instance.

3.3. Configuration properties

Trimou engine properties can be configured through system properties, trimou.properties file or the property can be set manually with MustacheEngineBuilder.setProperty(String, Object) method. Manually set properties have higher priority than system properties which have higher priority than properties from trimou.properties file.

Trimou logs all configuration properties and values during engine initialization
Table 1. Engine configuration keys - see also org.trimou.engine.config.EngineConfigurationKey enum
Enum value / property key Default value Description




The default start delimiter.




The default end delimiter




If enabled, all available templates from all available template locators will be compiled during engine initialization.




Remove "standalone lines" from each template during compilation to fullfill the spec requirements (and get more readable output :-)




Remove unnecessary segments (e.g. comments and delimiters tags) from each template during compilation. Having this enabled results in spec not-compliant output, but may improve performance a little bit.




By default a variable miss returns an empty string. If set to true a org.trimou.exception.MustacheException with code org.trimou.exception.MustacheProblem.RENDER_NO_VALUE is thrown.




Debug mode disables the template cache and provides some more logging during template rendering.




The section-based literal blocks can be cached. This may be useful to optimize some lambdas processing scenarios, though it’s memory intensive.




The limit of recursive template invocation (partials, template inheritance); 0 - recursive invocation is forbidden.




If true interpolated values are never escaped, i.e. org.trimou.engine.text.TextSupport.escapeHtml() is never called.



System property "file.encoding"

The encoding every template locator should use if reading template from a file. System file encoding by default.




The template cache is enabled by default. If set to false every MustacheEngine.getMustache() invocation results in template lookup.

TEMPLATE_CACHE_EXPIRATION_TIMEOUT org.trimou.engine.config.templateCacheExpirationTimeout


The template cache expiration timeout in seconds. Zero and negative values mean no timeout. The template cachec never expires by default.

HANDLEBARS_SUPPORT_ENABLED org.trimou.engine.config.handlebarsSupportEnabled


Handlebars support is enabled by default. Right now only handlebars-like helpers are supported.

3.4. Basic i18n support

Trimou has a very basic i18n support. Basically it provides three optional resolvers: org.trimou.engine.resolver.i18n.NumberFormatResolver, org.trimou.engine.resolver.i18n.DateTimeFormatResolver, org.trimou.engine.resolver.i18n.ResourceBundleResolver and one optional lambda: org.trimou.lambda.i18n.ResourceBundleLambda. All these components rely on org.trimou.engine.locale.LocaleSupport implementation to get the current Locale. See javadoc for more info.

3.4.1. DateTimeFormatResolver example

MustacheEngine engine = MustacheEngineBuilder
                           .setProperty(DateTimeFormatResolver.CUSTOM_PATTERN_KEY, "DD-MM-YYYY HH:mm") <1>
                           .addResolver(new DateTimeFormatResolver()) <2>
Mustache mustache = engine.getMustache("foo");
String output = mustache.render(ImmutableMap.<String, Object> of("now", new Date()));
  1. DateTimeFormatResolver also supports custom formatting pattern

  2. Manually add resolver

Now: {{now.formatCustom}}

results in something similar:

Now: 03-05-2013 22:05

4. How to extend

Basically all the extension points are focused on MustacheEngine configuration. Some components may be automatically added using the org.trimou.engine.config.ConfigurationExtension and JDK service-provider loading facility. Others may be added manually via MustacheEngineBuilder methods. See existing extensions to get acquainted with the basic principles.

Automatic org.trimou.engine.config.ConfigurationExtension processing may be disabled per engine - see also MustacheEngineBuilder#omitServiceLoaderConfigurationExtensions().

4.1. Resolver

Resolvers define the set of resolvable objects for your templates. The built-in set of resolvers should satisfy most of the basic requirements.

4.1.1. Custom resolvers

Implementing/adding a custom resolver may have serious impact on the engine functionality and performance.

All resolvers have a priority and resolvers with higher priority are called first. Keep in mind that all resolvers must be thread-safe. There are two ways to extend the basic set of resolvers:

  • automatically via org.trimou.engine.config.ConfigurationExtension,

  • you can also use MustacheEngineBuilder.addResolver() method.

trimou-extension-cdi extension provides CDIBeanResolver to lookup normal-scoped CDI beans with name. trimou-extension-servlet extension provides HttpServletRequestResolver to get the current Servlet request wrapper.

4.2. TemplateLocator

Template locators automatically locate the template contents for the given template identifier. The form of the template identifier is not defined, however in most cases the id will represent a template name, e.g. foo and foo.html, or virtual path like order/orderDetail. The default virtual path separator is / and can be configured via org.trimou.engine.locator.PathTemplateLocator.VIRTUAL_PATH_SEPARATOR_KEY. Template locators may only be added with MustacheEngineBuilder.addTemplateLocator() method.

There are three basic built-in implementations. org.trimou.engine.locator.FilesystemTemplateLocator finds templates on the filesystem, within the given root directory (watch out, this wouldn’t be likely portable across various operating systems). org.trimou.engine.locator.ClassPathTemplateLocator makes use of ClassLoader, either thread context class loader (TCCL) or custom CL set via constructor. org.trimou.engine.locator.MapTemplateLocator is backed by a Map. See javadoc for more configuration info.

Locators with higher priority are called first.
trimou-extension-servlet extension provides org.trimou.servlet.locator.ServletContextTemplateLocator to be used in web apps deployed to a servlet container.

4.3. TextSupport

org.trimou.engine.text.TextSupport is used to escape variable text if necessary (see also Escaping HTML). You can set the custom instance with org.trimou.engine.MustacheEngineBuilder.setTextSupport() method. Implement your own logic to extend functionality or improve performance!

4.4. LocaleSupport

org.trimou.engine.locale.LocaleSupport allows the engine and its components (e.g. resolvers) to get the current locale via getCurrentLocale(). You can set the custom org.trimou.engine.locale.LocaleSupport instance with org.trimou.engine.MustacheEngineBuilder.setLocaleSupport() method.

4.5. MustacheListener

Any registered org.trimou.engine.listener.MustacheListener receives notifications about template processing. In particular compilationFinished() method is invoked when a template is compiled, renderingStarted() and renderingFinished() methods are invoked for each template rendering. parsingStarted() is invoked right before a template is processed by the parser. Listeners are invoked in the order of their registration, except for renderingFinished() method which is invoked in reverse order.

There are two ways to register a custom listener:

  • MustacheEngineBuilder.addMustacheListener() method,

  • automatically via org.trimou.engine.config.ConfigurationExtension (extension listeners are always registered after manually added listeners).

Code inside a listener may throw an unchecked exception - this aborts further processing of template and no more listeners are invoked afterwards.

4.6. Helper

org.trimou.handlebars.Helper API is inspired by Handlebars but it’s not 100% compatible. Mainly it does not define "inverse" section, so for example if helper doesn’t support else block. On the other hand any helper is able to validate the tag definition (see Helper.validate(HelperDefinition)) and fail fast if there’s invalid number of arguments etc.

A helper may be registered via MustacheEngineBuilder.registerHelper(String, Helper). Note that each helper must be registered with a unique name. If there are more helpers registered with the same name an IllegalArgumentException is thrown during engine build. There are some built-in helpers registered automatically.

The main advantage of helpers is the ability to consume multiple parameters and optional hash map. Suppose we have a resource bundle messages.properties with the following key/value pair: my.message.key=My name is %s! We can use a org.trimou.handlebars.i18n.ResourceBundleHelper to render the message:

{{msg "my.message.key" "Martin" baseName="messages" format="printf"}}
Expected output
My name is Martin!

Trimou provides other useful helpers which are not automatically registered: org.trimou.handlebars.NumberIsEvenHelper, org.trimou.handlebars.NumberIsOddHelper and org.trimou.handlebars.i18n.DateTimeFormatHelper. See also javadoc for more info.

The number of registered helpers should not affect the engine performance (unlike the number of registered resolvers).

4.7. MissingValueHandler

org.trimou.engine.interpolation.MissingValueHandler handles variable miss (no value found) during interpolation of a variable tag. By default org.trimou.engine.interpolation.NoOpMissingValueHandler is used so that a miss does not result in any special operation. However you can set your own handler through the MustacheEngineBuilder.setMissingValueHandler() method. There is also org.trimou.engine.interpolation.ThrowingExceptionMissingValueHandler which throws an exception in case of a miss (actually it replaces deprecated configuration property EngineConfigurationKey#NO_VALUE_INDICATES_PROBLEM).

4.8. KeySplitter

org.trimou.engine.interpolation.KeySplitter is responsible for splitting a variable key. org.trimou.engine.interpolation.DotKeySplitter which follows the dot notation is used by default. org.trimou.engine.interpolation.BracketDotKeySplitter enables to use bracket notation and literals in variable keys. E.g. {{messages["my.message.key"]}}. You can set your own splitter through the MustacheEngineBuilder.setKeySplitter() method.

5. Extensions

5.1. CDI

Maven dependency

5.1.1. CDIBeanResolver

Tries to resolve a CDI bean with the given name (i.e. annotated with @Named or with a @Named stereotype).

5.1.2. Rendering context

The rendering scope is active during each rendering of a template, i.e. during Mustache.render() invocation - there is exactly one bean instance per rendering which is destroyed after the rendering is finished. This could be useful in SE environments where usually only @ApplicationScoped and @Dependent built-in scopes are available. You can annotate your bean with org.trimou.cdi.context.RenderingScoped to declare the rendering scope.

5.2. Servlets

At the moment only Servlet 3.x API is supported.

Maven dependency

5.2.1. ServletContextTemplateLocator

Locates the template anywhere in the web app. The root path must begin with a / and is interpreted as relative to the current context root, or relative to the /META-INF/resources directory of a JAR file inside the web application’s /WEB-INF/lib directory.

  .addTemplateLocator(new ServletContextTemplateLocator(10, "/WEB-INF/templates"))

5.2.2. HttpServletRequestResolver

Resolves a key of value request to HttpServletRequestWrapper. Why the wrapper? Well, we just don’t think it’s the right thing to call the request object directly.

5.2.3. RequestLocaleSupport

Obtains the current locate from the current servlet request.

5.3. PrettyTime

Maven dependency

5.3.1. PrettyTimeResolver

This resolver allows you to use PrettyTime date-formatting in your templates.

The PrettyTimeResolver is automatically loaded if you place the extension jar on the classpath.
Simple example
MustacheEngine engine = MustacheEngineBuilder
Mustache mustache = engine.compileMustache("prettyTime","{{now.prettyTime}}");
String output = mustache.render(ImmutableMap.<String, Object> of("now", new Date()));
// Renders something similar:
// moments from now

5.4. Minify

Minify extension allows you to minify your HTML and XML templates (or any other type of content if you provide your own org.trimou.minify.Minifier implementation). Trimou integrates small and efficient HtmlCompressor library. There are two ways to minify the templates. It’s possible to register a special listener to minify templates before parsing/compilation or use a special lambda to minify some parts of the template contents.

org.trimou.minify.Minify helper methods are useful to create the default listeners and lambdas (i.e. if you don’t require some extra configuration).
From the performance point of view: both listener and lambda decrease the size of the rendered template. However listeners may also improve the rendering performance (template is minified only once - before the compilation). Whereas lambdas will likely make rendering performance worse (part of the template is minified every time the lambda is invoked).
Maven dependency

5.4.1. MinifyListener

Simple example
MustacheEngine engine = MustacheEngineBuilder
Mustache mustache = engine.compileMustache("minify_html","<html><body>     <!-- My comment -->{{foo}}  </body></html>");
String output = mustache.render(ImmutableMap.<String, Object> of("foo", "FOO"));
// Renders:
// <html><body> FOO </body></html>
It’s also possible to customize the underlying com.googlecode.htmlcompressor.compressor.HtmlCompressor instance - see also our MinifyListenerTest.

5.4.2. MinifyLambda

Simple example
MustacheEngine engine = MustacheEngineBuilder
Mustache mustache = engine.compileMustache("minify_html_lambda","<html><body><!-- Remains -->{{#mini}}<!-- Will be removed -->   FOO {{/mini}}</body></html>");
String output = mustache.render(ImmutableMap.<String, Object> of("mini", Minify.htmlLambda()));
// Renders:
// <html><body><!-- Remains --> FOO </body></html>

5.4.3. Minifier interface

You can also implement your own minifier and leverage existing infrastructure:

MustacheEngine engine = MustacheEngineBuilder
                             .addMustacheListener(Minify.customListener(new AbstractMinifier() {
                                public Reader minify(String mustacheName, Reader mustacheContents) {
                                    return mustacheName.endsWith("html") ? mySuperMinification(Reader mustacheContents) : mustacheContents;

5.5. Gson

Gson extension brings some basic support for JSON format by means of google-gson APIs.

Maven dependency

5.5.1. JsonElementResolver

org.trimou.gson.resolver.JsonElementResolver makes it easier to work with com.google.gson.JsonElement instances. It is automatically loaded if you place the extension jar on the classpath.

  • It allows you to access JsonObject properties via dot notation

    • e.g. if foo is an instance of JsonObject then foo.bar is translated to foo.get("bar")

  • JsonArray elements can be accessed via index

    • e.g. if foo is an instance of JsonArray then foo.1 is translated to foo.get(1)

JsonNull is resolved as a null and JsonPrimitive is automatically unwrapped. E.g. foo.bar in JsonObject example is translated to foo.get("bar").getAsNumber() if bar is an instance of a java.lang.Number. This can be disabled - see JsonElementResolver javadoc.

However unwrapping only works if JsonElementResolver is involved! So for example if you iterate over ["Jim", true, 5], a special keyword unwrapThis must be used so that the primitives are unwrapped:

Example code
Example data
    "firstName": "Jan",
    "lastName": "Novy",
    "age": 30,
    "address": {
        "street": "Nova",
        "city": "Prague",
        "state": "CZ",
        "postalCode": "11000"
    "phoneNumbers": [
            "type": "home",
            "number": "+42002012345"
            "type": "mobile",
            "number": "+420728000111"
Example template
Last name: {{lastName}}
Street: {{address.street}}
Phone numbers: {{#phoneNumbers}}{{number}}{{#iterHasNext}}, {{/iterHasNext}}{{/phoneNumbers}}
Type of the first phone number: {{phoneNumbers.0.type}}
Type of the second phone number: {{phoneNumbers.1.type}}
Java code
// Load the test data
JsonElement jsonElement = new JsonParser().parse(...);
// JsonElementResolver is loaded automatically
MustacheEngine engine = MustacheEngineBuilder
Mustache mustache = engine.getMustache("json_test.mustache");
String output = mustache.render(jsonElement);
Expected output
Last name: Novy
Street: Nova
Phone numbers: +42002012345, +420728000111
Type of the first phone number: home
Type of the second phone number: mobile