Handlebars.java is a Java port of handlebars.
Handlebars provides the power necessary to let you build semantic templates effectively with no frustration.
Mustache templates are compatible with Handlebars, so you can take a Mustache template, import it into Handlebars, and start taking advantage of the extra Handlebars features.
<dependency>
<groupId>com.github.edgarespina</groupId>
<artifactId>handlebars</artifactId>
<version>0.1.0</version>
</dependency>
Handlebars handlebars = new Handlebars();
Template template = handlebars.compile("Hello {{.}}!");
System.out.println(template.apply("Handlebars.java"));
Output:
Hello Handlebars.java!
- 'with'
- 'each'
- 'if'
- 'unless'
- 'log'
- 'dateFormat'
- 'block'
- 'partial'
- 'embedded'
See the built-in helper documentation.
Usage:
{{dateFormat date ["format"] ["locale"]}}
context: a java.util.Date object. Required. param(0): one of "full", "long", "medium", "sort" or a date pattern like ("MM/dd/yyyy", etc.). Default is "medium". param(1): a locale representation ("es_AR", "en", "es", etc). Default is platform specific.
Block and partial helpers work together to provide you Template Inheritance.
Usage:
{{#block "title"}}
...
{{/block}}
context: A string literal which define the region's name.
Usage:
{{#partial "title"}}
...
{{/partial}}
context: A string literal which define the region's name.
The embedded helper allow you to "embedded" a handlebars template inside a <script>
HTML tag. See it in action:
user.hbs
<tr>
<td>{{firstName}}</td>
<td>{{lastName}}</td>
</tr>
home.hbs
<html>
...
{{embedded "user"}}
...
</html>
Output:
<html>
...
<script id="user-hbs" type="text/x-handlebars">
<tr>
<td>{{firstName}}</td>
<td>{{lastName}}</td>
</tr>
</script>
...
</html>
Usage:
{{embedded "template"}}
context: A template name. Required.
handlebars.registerHelper("blog", new Helper<Blog>() {
public CharSequence apply(Blog blog, Options options) {
return options.fn(blog);
}
});
handlebars.registerHelper("blog-list", new Helper<List<Blog>>() {
public CharSequence apply(List<Blog> list, Options options) {
String ret = "<ul>";
for (Blog blog: list) {
ret += "<li>" + options.fn(blog) + "</li>";
}
return new Handlebars.SafeString(ret + "</ul>");
}
});
handlebars.registerHelper("blog-list", new Helper<Blog>() {
public CharSequence apply(List<Blog> list, Options options) {
String p0 = options.param(0);
assertEquals("param0", p0);
Integer p1 = options.param(1);
assertEquals(123, p1);
...
}
});
Bean bean = new Bean();
bean.setParam1(123);
Template template = handlebars.compile("{{#blog-list blogs \"param0\" param1}}{{/blog-list}}");
template.apply(bean);
handlebars.registerHelper("blog-list", new Helper<Blog>() {
public CharSequence apply(List<Blog> list, Options options) {
String p0 = options.param(0, "param0");
assertEquals("param0", p0);
Integer p1 = options.param(1, 123);
assertEquals(123, p1);
...
}
});
Template template = handlebars.compile("{{#blog-list blogs}}{{/blog-list}}");
handlebars.registerHelper("blog-list", new Helper<Blog>() {
public CharSequence apply(List<Blog> list, Options options) {
String class = options.hash("class");
assertEquals("blog-css", class);
...
}
});
handlebars.compile("{{#blog-list blogs class=\"blog-css\"}}{{/blog-list}}");
handlebars.registerHelper("blog-list", new Helper<Blog>() {
public CharSequence apply(List<Blog> list, Options options) {
String class = options.hash("class", "blog-css");
assertEquals("blog-css", class);
...
}
});
handlebars.compile("{{#blog-list blogs}}{{/blog-list}}");
Let's say you need to access to the current logged-in user in every single view/page. You can publishing the current logged in user by hooking the context-stack. See it in action:
hookContextStack(Object model, Template template) {
User user = ....;// Get the logged-in user from somewhere
Context parent = ContextFactory.wrap(model);
template.apply(ContextFactory.wrap(parent, user));
}
Where is the hookContextStack
method? Well, that will depends on our current application architecture.
Maven:
<dependency>
<groupId>com.github.edgarespina</groupId>
<artifactId>handlebars-json</artifactId>
<version>0.1.0</version>
</dependency>
Usage:
handlebars.registerHelper("json", new JSONHelper());
{{json context}}
context: An object or null. Required.
Maven:
<dependency>
<groupId>com.github.edgarespina</groupId>
<artifactId>handlebars-markdown</artifactId>
<version>0.1.0</version>
</dependency>
Usage:
handlebars.registerHelper("md", new MarkdownHelper());
{{md context}}
context: An object or null. Required.
Maven:
<dependency>
<groupId>com.github.edgarespina</groupId>
<artifactId>handlebars-springmvc</artifactId>
<version>0.1.0</version>
</dependency>
Checkout the HandlebarsViewResolver.
- Handlebars.java follows the JavaScript API with some minors exceptions due to the nature of the Java language.
- The parser is built on top of [Parboiled] (https://github.com/sirthias/parboiled).
- Data is provided as primitive types (int, boolean, double, etc.), strings, maps, list or JavaBeans objects.
- Helpers are type-safe.
- Handlebars.java is thread-safe.
- Passes 123 of 127 tests from the Mustache Spec.
- The 4 missing tests are: "Standalone Line Endings", "Standalone Without Previous Line", "Standalone Without Newline", "Standalone Indentation" all them from partials.yml.
- In short, partials works 100% if you ignore white spaces indentation.
Handlebars.java depends on:
+- org.parboiled:parboiled-java:jar:1.0.2:compile
| +- asm:asm:jar:3.3.1:compile
| +- asm:asm-util:jar:3.3.1:compile
| +- asm:asm-tree:jar:3.3.1:compile
| +- asm:asm-analysis:jar:3.3.1:compile
| \- org.parboiled:parboiled-core:jar:1.0.2:compile
\- org.slf4j:slf4j-api:jar:1.6.4:compile