SkillAgentSearch skills...

Jmustache

A Java implementation of the Mustache templating language.

Install / Use

/learn @samskivert/Jmustache
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

This is a Java implementation of the Mustache template language.

Build Status

Motivations

  • Zero dependencies. You can include this single tiny library in your project and start making use of templates.

  • Usability on a variety of target platforms. This implementation makes very limited demands on the JVM in which it runs and as a result is usable on Android, or on other limited JVMs. It is even possible to avoid the use of reflection and provide all of your data as a series of nested maps.

  • Proguard and JarJar friendly. Though the library will reflectively access your data (if you desire it), the library makes no other internal use of reflection or by name instantiation of classes. So you can embed it using Proguard or JarJar without any annoying surprises.

  • Minimal API footprint. There are really only two methods you need to know about: compile and execute. You can even chain them together in cases where performance is of no consequence.

Its existence justified by the above motivations, this implementation then strives to provide additional benefits:

  • It is available via Maven Central, see below for details.
  • It is reasonably performant. Templates are parsed separately from execution. A template will specialize its variables on (class of context, name) pairs so that if a variable is first resolved to be (for example) a field of the context object, that will be attempted directly on subsequent template invocations, and the slower full resolution will only be tried if accessing the variable as a field fails.

Get It

JMustache is available via Maven Central and can thus be easily added to your Maven, Ivy, etc. projects by adding a dependency on com.samskivert:jmustache:1.15. Or download the pre-built jar file.

Documentation

In addition to the usage section below, the following documentation may be useful:

Usage

Using JMustache is very simple. Supply your template as a String or a Reader and get back a Template that you can execute on any context:

String text = "One, two, {{three}}. Three sir!";
Template tmpl = Mustache.compiler().compile(text);
Map<String, String> data = new HashMap<String, String>();
data.put("three", "five");
System.out.println(tmpl.execute(data));
// result: "One, two, five. Three sir!"

Use Reader and Writer if you're doing something more serious:

void executeTemplate (Reader template, Writer out, Map<String, String> data) {
   Mustache.compiler().compile(template).execute(data, out);
}

The execution context can be any Java object. Variables will be resolved via the following mechanisms:

  • If the context is a MustacheCustomContext, MustacheCustomContext.get will be used.
  • If the context is a Map, Map.get will be used.
  • If a non-void method with the same name as the variable exists, it will be called.
  • If a non-void method named (for variable foo) getFoo exists, it will be called.
  • If a field with the same name as the variable exists, its contents will be used.

Example:

class Person {
    public final String name;
    public Person (String name, int age) {
        this.name = name;
        _age = age;
    }
    public int getAge () {
        return _age;
    }
    protected int _age;
}

String tmpl = "{{#persons}}{{name}}: {{age}}\n{{/persons}}";
Mustache.compiler().compile(tmpl).execute(new Object() {
    Object persons = Arrays.asList(new Person("Elvis", 75), new Person("Madonna", 52));
});

// result:
// Elvis: 75
// Madonna: 52

As you can see from the example, the fields (and methods) need not be public. The persons field in the anonymous class created to act as a context is accessible. Note that the use of non-public fields will not work in a sandboxed security environment.

Sections behave as you would expect:

  • Boolean values enable or disable the section.
  • Array, Iterator, or Iterable values repeatedly execute the section with each element used as the context for each iteration. Empty collections result in zero instances of the section being included in the template.
  • An unresolvable or null value is treated as false. This behavior can be changed by using strictSections(). See Default Values for more details.
  • Any other object results in a single execution of the section with that object as a context.

See the code in MustacheTest.java for concrete examples. See also the Mustache documentation for details on the template syntax.

Partials

If you wish to make use of partials (e.g. {{>subtmpl}}) you must provide a Mustache.TemplateLoader to the compiler when creating it. For example:

final File templateDir = ...;
Mustache.Compiler c = Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
    public Reader getTemplate (String name) {
        return new FileReader(new File(templateDir, name));
    }
});
String tmpl = "...{{>subtmpl}}...";
c.compile(tmpl).execute();

The above snippet will load new File(templateDir, "subtmpl") when compiling the template.

Lambdas

JMustache implements lambdas by passing you a Template.Fragment instance which you can use to execute the fragment of the template that was passed to the lambda. You can decorate the results of the fragment execution, as shown in the standard Mustache documentation on lambdas:

String tmpl = "{{#bold}}{{name}} is awesome.{{/bold}}";
Mustache.compiler().compile(tmpl).execute(new Object() {
   String name = "Willy";
   Mustache.Lambda bold = new Mustache.Lambda() {
        public void execute (Template.Fragment frag, Writer out) throws IOException {
            out.write("<b>");
            frag.execute(out);
            out.write("</b>");
        }
    };
});
// result:
<b>Willy is awesome.</b>

You can also obtain the results of the fragment execution to do things like internationalization or caching:

Object ctx = new Object() {
    Mustache.Lambda i18n = new Mustache.Lambda() {
         public void execute (Template.Fragment frag, Writer out) throws IOException {
             String key = frag.execute();
             String text = // look up key in i18n system
             out.write(text);
         }
    };
};
// template might look something like:
<h2>{{#i18n}}title{{/i18n}}</h2>
{{#i18n}}welcome_msg{{/i18n}}

There is also limited support for decompiling (unexecuting) the template and obtaining the original Mustache template text contained in the section. See the documentation for [Template.Fragment] for details on the limitations.

Default Values

By default, an exception will be thrown any time a variable cannot be resolved, or resolves to null (except for sections, see below). You can change this behavior in two ways. If you want to provide a value for use in all such circumstances, use defaultValue():

String tmpl = "{{exists}} {{nullValued}} {{doesNotExist}}?";
Mustache.compiler().defaultValue("what").compile(tmpl).execute(new Object() {
    String exists = "Say";
    String nullValued = null;
    // String doesNotExist
});
// result:
Say what what?

If you only wish to provide a default value for variables that resolve to null, and wish to preserve exceptions in cases where variables cannot be resolved, use nullValue():

String tmpl = "{{exists}} {{nullValued}} {{doesNotExist}}?";
Mustache.compiler().nullValue("what").compile(tmpl).execute(new Object() {
    String exists = "Say";
    String nullValued = null;
    // String doesNotExist
});
// throws MustacheException when executing the template because doesNotExist cannot be resolved

When using a Map as a context, nullValue() will only be used when the map contains a mapping to null. If the map lacks a mapping for a given variable, then it is considered unresolvable and throws an exception.

Map<String,String> map = new HashMap<String,String>();
map.put("exists", "Say");
map.put("nullValued", null);
// no mapping exists for "doesNotExist"
String tmpl = "{{exists}} {{nullValued}} {{doesNotExist}}?";
Mustache.compiler().nullValue("what").compile(tmpl).execute(map);
// throws MustacheException when executing the template because doesNotExist cannot be resolved

Do not use both defaultValue and nullValue in your compiler configuration. Each one overrides the other, so whichever one you call last is the behavior you will get. But even if you accidentally do the right thing, you have confusing code, so don't call both, use one or the other.

Sections

Sections are not affected by the nullValue() or defaultValue() settings. Their behavior is governed by a separate configuration: strictSections().

By default, a section that is not resolvable or which resolves to null will be omitted (and conversely, an inverse section that is not resolvable or resolves to null will be included). If you use strictSections(true), sections that refer to an unresolvable value will always throw an exception. Sections that refer to a resolvable but null value never throw an exception, regardless of the strictSections() setting.

Extensions

JMustache extends the basic Mustache template language with some additional functionality. These additional features are enumerated below:

Not escaping HTML by default

View on GitHub
GitHub Stars875
CategoryDevelopment
Updated13d ago
Forks132

Languages

Java

Security Score

80/100

Audited on Mar 10, 2026

No findings