Java 8 Date/Time with FreeMarker

In previous article, we learn on how to create a simple CRUD Web Application using Spring Boot with FreeMarker as server side template engine. It's started by including spring-boot-starter-freemarker in our pom.xml.

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>

In the example, I'm using java.time.LocalDateTime for createdOn and updatedOn field of Note class

@Column(nullable = false, updatable = false) @CreatedDate private LocalDateTime createdOn; @Column(nullable = false) @LastModifiedDate private LocalDateTime updatedOn;

And because of this, I encounter problem when try to use this field (now properties) in my FreeMarker template. Let say, I want it in custom format.

Unfortunate even FreeMarker 2.3.29 (the one that included in spring-boot-starter-freemarker 2.1.8.RELEASE) still has no native support for LocalDateTime. Looking at FreeMarker official site, on contribution (wanted) page:

Support for Java 8 date/time API-s (this is actually certainly a difficult one). Note that there's a 3rd party solution for this, https://github.com/amedia/freemarker-java-8, but it's not as seamless as a native solution could be.

So if you want to use Java 8 date/time in your template, you would either to use above mentioned 3rd party solution or have to write your own. For me, as I'm quite lazy, I'll choose to use the solution that already available — freemarker-java8 library. The good thing is, the library has basic formatting support for all classes in the java.time api introduced in Java 8, using the new java.time.format.DateTimeFormatter.

freemarker-java8 is already available ar the Maven Central Repository. To use it, just add it in our pom.xml:

<dependency> <groupId>no.api.freemarker</groupId> <artifactId>freemarker-java8</artifactId> <version>1.3.0</version> </dependency>

We need to configure FreeMarker with our package by adding the Java8ObjectWrapper. Within a Spring Boot project you can add this configuration class to your project:

FreemarkerConfig.java
package com.dariawan.notesapp.config;

import no.api.freemarker.java8.Java8ObjectWrapper;
import org.springframework.context.annotation.Configuration;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

@Configuration
public class FreemarkerConfig implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof FreeMarkerConfigurer) {
            FreeMarkerConfigurer configurer = (FreeMarkerConfigurer) bean;
            configurer.getConfiguration().setObjectWrapper(new Java8ObjectWrapper(freemarker.template.Configuration.getVersion()));
        }
        return bean;
    }
}
                    

It'll enable java.time support for our template. In our example, I formatted LocalDateTime to custom format ""yyyy-MM-dd HH:mm:ss" (please check note-list.ftl):

${(note.createdOn).format('yyyy-MM-dd HH:mm:ss')} ${(note.updatedOn).format('yyyy-MM-dd HH:mm:ss')}

Will result:

http://localhost:8080/notes

http://localhost:8080/notes (Notes Page)