Quarkus Freemarker

Freemarker is a very popular and mature templating engine. Its integration as a Quarkus extension provides developers ease of configuration, and offers support for native images. In this guide, you will learn how to easily render Freemarker templates in your application.

Hello World

If you want to use Freemarker you need to add the quarkiverse-freemarker extension first. In your pom.xml file, add:

<dependency>
    <groupId>io.quarkiverse</groupId>
    <artifactId>quarkiverse-freemarker</artifactId>
    <version>{project-version}</version>
</dependency>

We’ll start with a very simple template:

hello.ftl
Hello ${name}! (1)
1 ${name} is a value expression that is evaluated when the template is rendered.

Now let’s inject the template in the resource class.

HelloResource.java
package org.acme.quarkus.sample;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;

import freemarker.template.Template;
import io.quarkiverse.freemarker.runtime.TemplatePath;

@Path("hello")
public class HelloResource {

    @Inject
    @TemplatePath("hello.ftl") (1)
    Template hello;

    @GET
    @Produces(TEXT_PLAIN)
    public String hello(@QueryParam("name") String name) throws IOException, TemplateException {
        StringWriter stringWriter = new StringWriter();
        hello.process(Map.of("name", name), stringWriter); (2)
        return stringWriter.toString();
    }
}
1 The @TemplatePath qualifier specifies the template name, found in either jar resource paths or external file paths.
2 Map.of("name", name) provides the model.

If your application is running, you can request the endpoint:

$ curl -w "\n" http://localhost:8080/hello?name=bob
Hello bob!

Usage

The application code can either directly inject a Freemarker Template bean as we saw above. In that case it must provide a TemplatePath qualifier annotation with the name of the template to select.

Or it can inject a Freemarker Configuration bean, from which templates can be obtained programmatically. The Configuration is a Singleton DefaultBean that can be replaced by an application provided implementation.

The default Configuration bean is configured from quarkus exposed properties. Among those, 2 are build time:

  • resource-paths is a list of resource paths contained in the classpath (e.g. typically in jars of the application). Each path is traversed recursively, and all files get added as native resources when building a native image.

  • directives is a map of directive alias to directive class name. Each directive class is added as a shared variable in the Configuration bean.

Here is an example of using a Configuration bean instead of a Template bean:

    @Inject
    Configuration configuration;

    @GET
    @Produces(TEXT_PLAIN)
    public String hello(@QueryParam("name") String name, @QueryParam("ftl") String ftl) throws IOException, TemplateException {
        StringWriter stringWriter = new StringWriter();
        configuration.getTemplate(ftl).process(model, stringWriter);
        return stringWriter.toString();
    }

The rest of the configuration properties can be provided at runtime, such as a list of external filesystem paths where to find additional templates, and optional properties that can be configured on the Freemarker Configuration class.

Directives

Freemarker can be extended using custom directives. For instance if we wanted to transform some text in base64, we could write:

package org.acme.quarkus.sample;

public class Base64Directive implements TemplateDirectiveModel {
    @Override
    public void execute(Environment environment, Map map, TemplateModel[] templateModels, TemplateDirectiveBody body)
            throws TemplateException, IOException {
        StringWriter sw = new StringWriter();
        body.render(sw);
        byte[] bytes = Base64.getEncoder().encode(sw.toString().getBytes(UTF_8));
        environment.getOut().write(new String(bytes, UTF_8));
    }
}

Then we would have to configure the application with:

quarkus.freemarker.directives.base64=org.acme.quarkus.sample.Base64Directive

And finally, we would use it in templates such as:

Hello <@base64>$\{name}</@base64>!

This would be rendered as:

Hello Ym9i!

Data model

Freemarker supports Map or Object based data models. When using objects, it is important to configure quarkus.freemarker.object-wrapper-expose-fields=true if model classes do not have getters.

Additionnaly, they should be annotated with @RegisterForReflection to support native images.

Extension Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

Comma-separated list of absolute resource paths to scan recursively for templates. All tree folder from 'resource-paths' will be added as a resource. Unprefixed locations or locations starting with classpath will be processed in the same way. Defaults relevant for this option are documented on quarkus.freemarker.base-path

Environment variable: QUARKUS_FREEMARKER_RESOURCE_PATHS

list of string

The base path of this template set. Template set is a triple of base-path, includes and excludes serving to select a number of templates for inclusion in the native image. includes and excludes are relative to base-path. Use slash (/) as a path separator on all platforms. The value must not start with a slash. Do not set any base-path value if you want includes and excludes to be relative to root resource path. Defaults Option Default value in case none of quarkus.freemarker.[base-path|includes|excludes|resource-paths] is set Default value otherwise quarkus.freemarker.base-path freemarker/templates not set (interpreted as root resource path folder) quarkus.freemarker.includes ** not set (no files included) quarkus.freemarker.excludes not set (no files excluded) not set (no files excluded) The defaults described in the second column of the table are to achieve the backwards compatibility with the behavior of quarkus.freemarker.resource-paths before Quarkus Freemarker 0.2.0. Allowed combinations Setting base-path and/or excludes but not setting includes will result in a build time error. We have chosen this behavior (rather than using ** as a default for includes) to avoid including all resources inadvertently and thus bloating your native image.

Environment variable: QUARKUS_FREEMARKER_BASE_PATH

string

A comma separated list of globs to select FreeMarker templates for inclusion in the native image. includes are relative to base-path. Use slash (/) as a path separator on all platforms. The glob syntax is documented on quarkus.native.resources.includes. Example: quarkus.freemarker.includes = **.ftl

Environment variable: QUARKUS_FREEMARKER_INCLUDES

list of string

A comma separated list of globs not to include in the native image. excludes are relative to base-path. Use slash (/) as a path separator on all platforms. The glob syntax is documented on quarkus.native.resources.includes. Example: quarkus.freemarker.excludes = **/unwanted*

Environment variable: QUARKUS_FREEMARKER_EXCLUDES

list of string

Comma-separated of file system paths where freemarker templates are located

Environment variable: QUARKUS_FREEMARKER_FILE_PATHS

list of string

Set the preferred charset template files are stored in.

Environment variable: QUARKUS_FREEMARKER_DEFAULT_ENCODING

string

Sets how errors will appear. rethrow, debug, html-debug, ignore.

Environment variable: QUARKUS_FREEMARKER_TEMPLATE_EXCEPTION_HANDLER

string

If false, don’t log exceptions inside FreeMarker that it will be thrown at you anyway.

Environment variable: QUARKUS_FREEMARKER_LOG_TEMPLATE_EXCEPTIONS

boolean

Wrap unchecked exceptions thrown during template processing into TemplateException-s.

Environment variable: QUARKUS_FREEMARKER_WRAP_UNCHECKED_EXCEPTIONS

boolean

If false, do not fall back to higher scopes when reading a null loop variable.

Environment variable: QUARKUS_FREEMARKER_FALLBACK_ON_NULL_LOOP_VARIABLE

boolean

The string value for the boolean true and false values, usually intended for human consumption (not for a computer language), separated with comma.

Environment variable: QUARKUS_FREEMARKER_BOOLEAN_FORMAT

string

Sets the default number format used to convert numbers to strings.

Environment variable: QUARKUS_FREEMARKER_NUMBER_FORMAT

string

If true, the object wrapper will be configured to expose fields.

Environment variable: QUARKUS_FREEMARKER_OBJECT_WRAPPER_EXPOSE_FIELDS

boolean

List of directives to register with format name=classname

Environment variable: QUARKUS_FREEMARKER_DIRECTIVES

Map<String,String>

Additional named template sets

Type

Default

The base path of this template set. Template set is a triple of base-path, includes and excludes serving to select a number of templates for inclusion in the native image. includes and excludes are relative to base-path. Use slash (/) as a path separator on all platforms. The value must not start with a slash. Do not set any base-path value if you want includes and excludes to be relative to root resource path. Defaults Option Default value in case none of quarkus.freemarker.[base-path|includes|excludes|resource-paths] is set Default value otherwise quarkus.freemarker.base-path freemarker/templates not set (interpreted as root resource path folder) quarkus.freemarker.includes ** not set (no files included) quarkus.freemarker.excludes not set (no files excluded) not set (no files excluded) The defaults described in the second column of the table are to achieve the backwards compatibility with the behavior of quarkus.freemarker.resource-paths before Quarkus Freemarker 0.2.0. Allowed combinations Setting base-path and/or excludes but not setting includes will result in a build time error. We have chosen this behavior (rather than using ** as a default for includes) to avoid including all resources inadvertently and thus bloating your native image.

Environment variable: QUARKUS_FREEMARKER__TEMPLATE_SET_NAME__BASE_PATH

string

A comma separated list of globs to select FreeMarker templates for inclusion in the native image. includes are relative to base-path. Use slash (/) as a path separator on all platforms. The glob syntax is documented on quarkus.native.resources.includes. Example: quarkus.freemarker.includes = **.ftl

Environment variable: QUARKUS_FREEMARKER__TEMPLATE_SET_NAME__INCLUDES

list of string

A comma separated list of globs not to include in the native image. excludes are relative to base-path. Use slash (/) as a path separator on all platforms. The glob syntax is documented on quarkus.native.resources.includes. Example: quarkus.freemarker.excludes = **/unwanted*

Environment variable: QUARKUS_FREEMARKER__TEMPLATE_SET_NAME__EXCLUDES

list of string