FreshMarker – Custom String Types

Have patience. All things are difficult before they become easy.

Saadi

Some additions to a framework are so trivial that they don’t really deserve their own article. On the other hand, as a developer, you may ask yourself why this addition has taken so long.

FreshMarker is a lightweight template engine that is based on the syntax of FreeMarker. In contrast to FreeMarker, however, a whole range of features such as include, import, namespaces and XML processing are not implemented. Instead, FreshMarker shines with a plug-in system that allows support for temporal data types, paths, files, international phonenumbers and public holidays.

For unknown data types, FreshMarker uses the interpretation of the class as a Java Bean by default. This is a good solution for many POJO, DTO and Entity classes, but in some cases the class should be used as a primitive FreshMarker type.

In the following example, the Leitweg-ID from the article Leitweg ID – Ihre Nummer für die Behörde is to be output. As the Leitweg-ID is not supported by FreshMarker by default, we receive an error message. For FreshMarker, it looks as if a bean was addressed for output in the template and not a primitive type.

Configuration configuration = new Configuration();

Template template = configuration.getTemplate("id", "Leitweg-ID: ${id}!");
LeitwegId leitwegId = LeitwegId.parse("04011000-1234512345-06");
assertEquals("Leitweg-ID: 04011000-1234512345-06!", template.process(Map.of("id", leitwegId)));

In order for the Leitweg-ID to be output, either one of its attributes had to be specified or a separate plug-in had to be written. As there is no corresponding attribute for output in the Leitweg-ID, another solution must be found. The Leitweg-ID has a toString method to generate the desired display. The only thing missing is a simple way to create a TemplateString object from the Leitweg-ID.

Fortunately, FreshMarker has an internal map in which all supported types have a mapping to a FreshMarker model class. The only thing missing is a method for entering your own mapping there.

In the following example, the newly added Configuration#registerSimpleMapping method is used to create a mapping to TemplateString for the LeitwegId class.

Configuration configuration = new Configuration();
configuration.registerSimpleMapping(LeitwegId.class);

Template template = configuration.getTemplate("id", "Leitweg-ID: ${id}!");
LeitwegId leitwegId = LeitwegId.parse("04011000-1234512345-06");
assertEquals("Leitweg-ID: 04011000-1234512345-06!", template.process(Map.of("id", leitwegId)));

Another method is available for more complex mapping.

Configuration configuration = new Configuration();
configuration.registerSimpleMapping(LeitwegId.class, x -> "<<" + x + ">>");

Template template = configuration.getTemplate("id", "Leitweg-ID: ${id}!");
LeitwegId leitwegId = LeitwegId.parse("04011000-1234512345-06");
assertEquals("Leitweg-ID: <<04011000-1234512345-06>>!", template.process(Map.of("id", leitwegId)));

This feature is available in the latest version of FreshMarker on Maven Central.

<dependency>
    <groupId>de.schegge</groupId>
    <artifactId>freshmarker</artifactId>
    <version>0.5.5</version>
</dependency>

Leave a Comment