Secure Mustache.java with SafeMustacheFactory
mainSafeMustacheFactory and whitelist all allowed templates and partials.repository·main·Indexed 23 days ago
https://github.com/spullara/mustache.javaA high-performance Java implementation of the Mustache templating system. It supports template inheritance, concurrent evaluation via Callables and ExecutorService, and data access through non-private fields, methods, or maps. The library includes SafeMustacheFactory for handling untrusted templates and ScalaObjectHandler for integration with Scala 2.10, 2.11, 2.12, and 2.13, providing specialized handling for Scala collections, Options, and truthiness logic.
SafeMustacheFactory and whitelist all allowed templates and partials.While Mustache.java is a derivative of mustache.js, it has several key differences:
Callable objects are used with an ExecutorService.Function (post-substitution). Use TemplateFunction if you want the library to reparse the results of your function (pre-substitution).{{<super}}{{$content}}...{{/content}}{{/super}}).By default, template evaluation is serial. If a data method contains blocking code, the system pauses. To enable concurrent/asynchronous evaluation, return a Callable from your data methods and provide an ExecutorService when creating your MustacheFactory.
// Instead of a blocking method:
String description() throws InterruptedException {
Thread.sleep(1000);
return description;
}
// Use a Callable for concurrent execution:
Callable<String> description() throws InterruptedException {
return new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return description;
}
};
}To use Mustache.java in your project, add the compiler module as a dependency in your pom.xml. Choose the version based on your Java runtime:
0.9.10.0.8.18.<!-- Java 8+ -->
<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.9.10</version>
</dependency>
<!-- Java 6/7 -->
<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.8.18</version>
</dependency>You can provide data to a template using Java objects. Mustache.java accesses data via non-private fields, methods, or maps. Any Iterable can be used for list-like behaviors.
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
public class Example {
List<Item> items() {
return Arrays.asList(
new Item("Item 1", "$19.99", Arrays.asList(new Feature("New!"), new Feature("Awesome!"))),
new Item("Item 2", "$29.99", Arrays.asList(new Feature("Old."), new Feature("Ugly.")))
);
}
static class Item {
Item(String name, String price, List<Feature> features) {
this.name = name;
this.price = price;
this.features = features;
}
String name, price;
List<Feature> features;
}
static class Feature {
Feature(String description) {
this.description = description;
}
String description;
}
public static void main(String[] args) throws IOException {
MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile("template.mustache");
mustache.execute(new PrintWriter(System.out), new Example()).flush();
}
}Alternatively, you can provide data using a Map<String, Object> instead of a dedicated context object.
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.Writer;
import java.util.HashMap;
public class MapExample {
public static void main(String[] args) throws IOException {
HashMap<String, Object> scopes = new HashMap<String, Object>();
scopes.put("name", "Mustache");
scopes.put("feature", new Feature("Perfect!"));
Writer writer = new OutputStreamWriter(System.out);
MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile(new StringReader("{{name}}, {{feature.description}}!"), "example");
mustache.execute(writer, scopes);
writer.flush();
}
static class Feature {
Feature(String description) { this.description = description; }
String description;
}
}The ScalaObjectHandler is a specialized implementation of ReflectionObjectHandler designed for Scala 2.12 environments. It bridges the gap between Scala's collection types and Mustache.java's expectations by providing custom coercion and iteration logic.
Key behaviors include:
Map types to Java Maps.Some(value) to the underlying value and converts None to null.0.BoxedUnit to null.Traversable collections.The ScalaObjectHandler is a specialized implementation of ReflectionObjectHandler designed for Scala 2.11 environments. It allows Mustache.java to correctly interpret Scala-specific types and collections when rendering templates.
Key behaviors include:
Map objects to Java Maps.Some(value) to the underlying value and treats None as null.Traversable collections are considered 'falsey' if they are empty.0 are treated as 'falsey'.BoxedUnit to null.To use this, you should provide an instance of ScalaObjectHandler to your Mustache compiler or engine configuration to ensure Scala data structures are correctly resolved during template execution.
The ScalaObjectHandler is a specialized implementation of ReflectionObjectHandler designed to bridge Scala 2.10 data structures with Mustache.java templates. It allows Mustache to natively understand Scala-specific types like Option, Some, None, and Scala collections.
Some(value) is automatically unwrapped to its underlying value, while None is treated as null.Map objects are converted to Java Maps. Scala Traversable collections are iterated over during template execution.{{#section}}...{{/section}} else block or skip the section).Number with a value of 0 is considered "falsey".BoxedUnit values are treated as null.The ScalaObjectHandler is a specialized ReflectionObjectHandler designed for use with Mustache.java in Scala 2.13 environments. It provides seamless integration between Scala types and Mustache templates by handling Scala-specific constructs that the standard Java reflection handler might not recognize.
Key behaviors include:
Map types to Java Maps using asJava so they can be accessed in templates.Some(value) to the underlying value and treats None as null.BoxedUnit to null.Iterable is treated as falsey.Number with a value of 0 is treated as falsey.checkMethod and checkField to allow access to any method or field without restriction.