Skip to content

Instantly share code, notes, and snippets.

@juangamnik
Last active July 3, 2016 15:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juangamnik/74260c068e918935994c9720108b8897 to your computer and use it in GitHub Desktop.
Save juangamnik/74260c068e918935994c9720108b8897 to your computer and use it in GitHub Desktop.
Enhancing Mustache via an if-statement with EL
package info.mustacheexample;
import com.github.mustachejava.*;
import javax.el.*;
import java.beans.FeatureDescriptor;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Function;
public class MustacheExample {
public static void main(String[] args) {
// helper function for evaluating the end of the expression by counting
// opening and closing braces.
final Function<String, Integer> calcEndIndexOfExpression = s -> {
int i = 0;
int open = 0;
for(char c : s.toCharArray()) {
switch(c) {
case '(':
open++;
break;
case ')':
open--;
break;
}
if(open == 0) {
return i;
}
i++;
}
return -1;
};
// The template to evaluate
final String template =
"a is {{#if}}(a <= 3)not {{/if}}greater than three. " +
"b is {{#if}}(b <= (4 + 1))not {{/if}}greater than 5.";
StringWriter sw = new StringWriter();
// the context for the el expression.
final Map<String, Object> context = new HashMap<>();
context.put("a", 100);
context.put("b", 5);
final ExpressionFactory factory = ExpressionFactory.newInstance();
final ELContext elContext = new MustacheELContext(context);
final Map<String, TemplateFunction> functions = new HashMap<>();
// add a template function to mustache evaluating `{{#if}}` expressions.
functions.put("if", str -> {
// extract the expression.
final Integer endIndex = calcEndIndexOfExpression.apply(str);
if (endIndex <= 0) {
return str;
}
final String expression = str.substring(1, endIndex);
// evaluate the expression (only boolean expressions are allowed).
if((Boolean) factory.createValueExpression(elContext,
"${" + expression + "}", Boolean.class)
.getValue(elContext)) {
final String content = str.substring(endIndex + 1);
return content;
}
return "";
});
// Execute the complete example.
try {
final MustacheFactory mf = new DefaultMustacheFactory();
final Mustache mustache = mf.compile(new StringReader(template), null);
mustache.execute(sw, new Object[] {context, functions}).flush();
}
catch (NumberFormatException | IOException | MustacheException e) {
throw new IllegalArgumentException(e);
}
// prints: a is greater than three. b is not greater than 5.
System.out.println(sw.toString());
}
private static class MustacheELContext extends ELContext {
private MustacheELResolver resolver;
private MustacheELContext(Object o) {
this.resolver = new MustacheELResolver(o);
}
@Override
public VariableMapper getVariableMapper() {
return null;
}
@Override
public FunctionMapper getFunctionMapper() {
return null;
}
@Override
public ELResolver getELResolver() {
return resolver;
}
}
private static class MustacheELResolver extends ELResolver {
private CompositeELResolver delegate = new CompositeELResolver();
private Object o;
public MustacheELResolver(Object o) {
this.o = o;
delegate.add(new MapELResolver(true));
delegate.add(new BeanELResolver(true));
}
@Override
public Class<?> getCommonPropertyType(ELContext arg0, Object base) {
if (base == null) {
base = o;
}
return delegate.getCommonPropertyType(arg0, base);
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(
ELContext arg0, Object base) {
if (base == null)
base = o;
return delegate.getFeatureDescriptors(arg0, base);
}
@Override
public Class<?> getType(ELContext arg0, Object base, Object arg2) {
if (base == null)
base = o;
return delegate.getType(arg0, base, arg2);
}
@Override
public Object getValue(ELContext arg0, Object base, Object arg2) {
if (base == null)
base = o;
return delegate.getValue(arg0, base, arg2);
}
@Override
public boolean isReadOnly(ELContext arg0, Object base, Object arg2) {
if (base == null) {
base = o;
}
return delegate.isReadOnly(arg0, base, arg2);
}
@Override
public void setValue(ELContext arg0, Object base, Object arg2,
Object arg3) {
if (base == null)
base = o;
delegate.setValue(arg0, base, arg2, arg3);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>info.mustacheexample</groupId>
<artifactId>mustache-example</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.orbit</groupId>
<artifactId>com.sun.el</artifactId>
<version>2.2.0.v201303151357</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
<type>jar</type>
</dependency>
</dependencies>
</project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment