How can I register Handlebars helpers in a Micronaut application?

717 Views Asked by At

I am wondering where (or how) should I declare helpers for Handlebars in my Micronaut project?

I have tried following approach:


    public class Application {

        public static void main(String[] args) {
            Micronaut.run(Application.class);
            Handlebars handlebars = new Handlebars();
            handlebars.registerHelpers(HelperSource.class);
        }
    }

This had no effect. How can I register Handlebars helpers in a Micronaut application?

1

There are 1 best solutions below

2
On

There is no configuration to register Handlebars helpers in current Micronaut 1.0 GA release. However, there is a simple workaround you can apply to overcome this limitation. To make helpers registration possible you have to access io.micronaut.views.handlebars.HandlebarsViewsRenderer class and its inner property handlebars. The good news is that this property has a protected scope - it means that we can create another bean in the same package in our source code and we can inject HandlebarsViewsRenderer and access HandlebarsViewsRenderer.handlebars field. Having an access to this field we can execute handlebars.registerHelpers(...) method.

You can simply follow these steps:

1. Add Handlebars.java dependency

compile "com.github.jknack:handlebars:4.1.0"

It is important to add it in the compile scope, because runtime scope won't allow you to access HandlebarsViewsRenderer.handlebars object.

2. Create io.micronaut.views.handlebars.HandlebarsCustomConfig class

src/main/java/io/micronaut/views/handlebars/HandlebarsCustomConfig.java

package io.micronaut.views.handlebars;

import javax.inject.Singleton;
import java.util.Date;

@Singleton
public final class HandlebarsCustomConfig {

    public HandlebarsCustomConfig(HandlebarsViewsRenderer renderer) {
        renderer.handlebars.registerHelpers(new HelperSource());
    }

    static public class HelperSource {
        public static String now() {
            return new Date().toString();
        }
    }
}

Here in this class I have created a simple HelperSource class that exposes a single helper called {{now}}.

3. Load HandlebarsCustomConfig bean

package com.github.wololock.micronaut;

import io.micronaut.context.ApplicationContext;
import io.micronaut.runtime.Micronaut;
import io.micronaut.views.handlebars.HandlebarsCustomConfig;

public class Application {

    public static void main(String[] args) {
        final ApplicationContext ctx = Micronaut.run(Application.class);
        ctx.getBean(HandlebarsCustomConfig.class);
    }
}

This step is crucial. We need to load the bean, otherwise Micronaut would not create an instance of it and our helpers registration would not take place.

4. Create a view

src/main/resources/views/home.hbs

<!DOCTYPE html>
<html>
<head>
    <title>Home</title>
</head>
<body>
    <h1>Hello, world!</h1>
    <p>Now is {{now}}</p>
</body>
</html>

5. Run application and see the results

enter image description here

@Replaces alternative

You can use Micronauts @Replaces annotation to replace HandlebarsViewsRenderer with a custom implementation.

import io.micronaut.context.annotation.Replaces;
import io.micronaut.core.io.scan.ClassPathResourceLoader;
import io.micronaut.views.ViewsConfiguration;

import javax.inject.Singleton;
import java.util.Date;

@Singleton
@Replaces(HandlebarsViewsRenderer.class)
public final class CustomHandlebarsViewsRenderer extends HandlebarsViewsRenderer {

    public CustomHandlebarsViewsRenderer(ViewsConfiguration viewsConfiguration, 
                                  ClassPathResourceLoader resourceLoader, 
                                  HandlebarsViewsRendererConfiguration handlebarsViewsRendererConfiguration) {
        super(viewsConfiguration, resourceLoader, handlebarsViewsRendererConfiguration);

        this.handlebars.registerHelpers(new HelperSource());
    }

    static public class HelperSource {
        public static String now() {
            return new Date().toString();
        }
    }
}

It has a few advantages comparing to the previous solution:

  1. You don't have to create it in the io.micronaut.views.handlebars package.
  2. You don't have to get the bean in the main method to initialize it properly.