Fusion handlebars provides a light handlebars templating support.

Dependency

<dependency>
  <groupId>io.yupiik.fusion</groupId>
  <artifactId>fusion-handlebars</artifactId>
  <version>${fusion.version}</artifactId>
</dependency>

Usage

It starts from HandlebarsCompiler (available as a fusion bean) which compiles a template + its helpers and partials as a Template which supports to render the template.

Data can be map of primitives (or data which have a toString()) or lists for now. It tolerates that you pass a Supplier too as map value for a lazy evaluation.

// once per app
final var compiler = new HandlebarsCompiler();
final var tpl = compiler.compile(new HandlebarsCompiler.CompilationContext(
        new HandlebarsCompiler.Settings()
                .helpers(Map.of( // some helpers - can be Map.of() if you don't use them
                    "uppercase", o -> o.toString().toUpperCase(ROOT))
                .partials(Map.of(
                        "person", "{{person.name}} is {{person.age}} years old.")),
        "{{firstname}} {{uppercase lastname}}"));

// at runtime
final var rendering = tpl.render(Map.of(...)));

Each built-in helper data-variables

{{each xxx} supports the following data-variables:

  • @first (boolean): is the current element the first one,

  • @last (boolean): is the current element the last one,

  • @index (integer): 0-based index of current element.

If the xxx variable is not a Collection but a Map, the additional @key and @value data-variables are available.

Future

Technically it is possible to go further but it has to be proven useful, here are some ideas:

  1. Support records (potentially POJO but immutability would be a plus) as model,

  2. Support CompletionStage as model - requires to return a CompletionStage<String> instead but generally we can always await the model is available before the rendering and making helpers promise friendly has other drawbacks,

  3. Support to precompile the template at build time, this can use an API like public interface MyTemplates { @HandleBars(template = "myresource.handlebars") String myResource(MyRecordDataOrMap data); } and fusion processor would generate an implementation of this type which would be a bean. This option requires to override most of *Part implementations but is very feasible,

  4. Support more this cases, right now a few cases don't support this keyword,

  5. Support lookup, this is built-in in handlebars but has the drawback to rely on lookup at runtimes, maybe something to not add,

  6. Support streaming? If the output can be huge - assuming we support later Iterable or Stream for example - then we can replace the output String by a InputStream or a Publisher<ByteBuffer> for ex,

  7. Else support (in if blocks),

  8. ...