Skip to content

Munich-Airport/freemarker-java-8

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Java8 Date/Time Support For FreeMarker

This project is forked from the original but mostly "dead" project of amedia. See the original project here.

This is a tiny Java library that adds basic support for the new Java 8 date/time api to FreeMarker. It is not a perfect solution as FreeMarker doesn’t support adding custom built-ins. Hopefully FreeMarker will add native support in the future, but there are no implementation being worked on at the moment (http://freemarker.org/contribute.html).

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. We have also introduced some comparison methods.

Requirements

Java 8 or higher. Tested on Freemarker 2.3.23, but should at least work fine for all 2.3.x versions. Please file an issue if you have problems with other versions.

Installation

freemarker-java-8 is deployed to the Maven Central Repository. You can include the package in your Maven POM like this :

<dependency>
    <groupId>com.munich-airport.freemarker</groupId>
    <artifactId>freemarker-java8</artifactId>
    <version>2.0.0</version>
</dependency>

Make sure to replace the version with the current version found in the pom.

Usage

You need to configure FreeMarker with our package by adding the Java8ObjectWrapper.

this.configuration = new Configuration(); // Or get the configuration from your framework like DropWizard or Spring Boot.
final Java8Configuration java8Configuration = Java8Configuration.defaultConfiguration();
// Configure the java8 module
// e.g.: java8Configuration.setTimezoneStrategy(SystemTimezoneStrategy.INSTANCE);
this.configuration.setObjectWrapper(new Java8ObjectWrapper(Configuration.VERSION_2_3_23, java8Configuration));

Usage within Spring

Within a Spring project you can add this configuration class to your project:

import no.api.freemarker.java8.Java8ObjectWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class FreemarkerConfig extends FreeMarkerAutoConfiguration.FreeMarkerWebConfiguration {

    @Autowired
    private freemarker.template.Configuration configuration;

    @PostConstruct
    public void postConstruct() {
        final Java8Configuration java8Configuration = Java8Configuration.defaultConfiguration();
        configuration.setObjectWrapper(
                new Java8ObjectWrapper(freemarker.template.Configuration.getVersion(), java8Configuration)); // VERSION_2_3_26
    }

}

java.time support

We had to cheat a little bit to add format methods to our date.time classes. This is why you will see that our syntax differs from the default FreeMarker built-ins.

All format methods uses the java.time.format.DateTimeFormatter for formatting. For sake of completion we also added a isEqual(…​) to LocalTime instances. All bean methods of the java.time classes are still supported.

Table 1. java.time template methods
java.time class methods comment example

Clock

format()

This is a simple implementation where format just prints the toString() value of the object.

${myclock.format()}

Instant

format()

This is a simple implementation where format just prints the toString() value of the object.

${myinstant.format()}

LocalDate

format(), format(pattern)

Allows you to print a LocalDate on a default pattern, or by providing a custom pattern or a builtin format style or the static field name of the DateTimeFormatter class.

${mylocaldate.format()}, ${mylocaldate.format('yyyy MM dd')} or ${mylocaldate.format('FULL_DATE')} or ${mylocaldate.format('ISO_DATE')}

LocalDateTime

format(), format(pattern)

Allows you to print a LocalDateTime on a default pattern, or by providing a custom pattern or a builtin format style or the static field name of the DateTimeFormatter class.

${mylocaldatetime.format()}, ${mylocaldatetime.format('yyyy-MM-dd HH : mm : ss')} or ${mylocaldatetime.format('MEDIUM_DATETIME')} or ${mylocaldatetime.format('ISO_DATE_TIME')}

LocalTime

format(), format(pattern)

Allows you to print a LocalTime on a default pattern, or by providing a custom pattern or a builtin format style or the static field name of the DateTimeFormatter class.

${mylocaltime.format()}, ${mylocaltime.format('HH : mm : ss')} or ${mylocaltime.format('SHORT_TIME')} or ${mylocaltime.format('ISO_TIME')}

MonthDay

format(), format(pattern)

Allows you to print a MonthDay on a default pattern or by providing a custom pattern.

${mymonthday.format()} or ${mymonthday.format('MM dd')}

OffsetDateTime

format(), format(pattern)

Allows you to print a OffsetDateTime on a default pattern, or by providing a custom pattern or a builtin format style or the static field name of the DateTimeFormatter class.

${myoffsetdatetime.format()}, ${myoffsetdatetime.format('yyyy MM dd HH mm ss')} or ${myoffsetdatetime.format('FULL_DATETIME')} or ${myoffsetdatetime.format('IOS_OFFSET_DATE_TIME')}

OffsetTime

format(), format(pattern)

Allows you to print a OffsetTime on a default pattern, or by providing a custom pattern or a builtin format style or the static field name of the DateTimeFormatter class.

${myoffsettime.format()}, ${myoffsettime.format('HH mm ss')} or ${myoffsettime.format('MEDIUM_TIME')} or ${myoffsettime.format('IOS_OFFSET_TIME')}

Year

format(), format(pattern)

Allows you to print a Year on a default pattern or by providing a custom pattern.

${myyear.format()} or ${myyear.format('yyyy')}

YearMonth

format(), format(pattern)

Allows you to print a YearMonth on a default pattern or by providing a custom pattern.

${myyear.format()} or ${myyear.format('yyyy MM')}

ZonedDateTime

format(), format(pattern), format(pattern, zoneId)

Allows you to print a ZonedDateTime on a default pattern/timezone (see timezone strategies), or by providing a custom pattern or a builtin format style or the static field name of the DateTimeFormatter class.

${myzoneddatetime.format()} or ${myzoneddatetime.format('yyyy-MM-dd Z')} or ${myzoneddatetime.format('yyyy-MM-dd Z', 'Asia/Seoul')} or ${myzoneddatetime.format('ISO_ZONED_DATE_TIME', 'Asia/Seoul')}

ZoneId

format(), format(textStyle), format(textstyle, locale)

Prints the ZoneId display name. You can override the textstyle with one of these values [FULL, FULL_STANDALONE, SHORT, SHORT_STANDALONE, NARROW and NARROW_STANDALONE]. You can also override the locale, but Java only seems to have locale support for a few languages.

${myzoneid.format()} or ${myzoneid.format('short')} or ${myzoneid.format('short', 'no-NO')}

ZoneOffset

format(), format(textStyle)

Prints the ZoneOffset display name. You can override the textstyle with one of these values [FULL, FULL_STANDALONE, SHORT, SHORT_STANDALONE, NARROW and NARROW_STANDALONE]. You can also override the locale, but Java only seems to have locale support for a few languages.

${myzoneoffset.format()} or ${myzoneoffset.format('short')} or ${myzoneoffset.format('short', 'no-NO')}

Table 2. java.time comparison methods
java.time class methods comment example

LocalTime

isEqual(<LocalTime object>)

Can compare two LocalTime objects for equality.

${localTime.isEqual(anotherlocalTime)}

Table 3. supported default patterns
pattern

LONG_DATE

LONG_DATETIME

LONG_TIME

MEDIUM_DATE

MEDIUM_DATETIME

MEDIUM_TIME

SHORT_DATE

SHORT_DATETIME

SHORT_TIME

Timezone Strategies

Prior to version 2.0.0 all ZonedDateTime instances formatted using format() or format(pattern) were translated into the ZoneId retrieved by Environment.getCurrentEnvironment().getTimezone().toZoneId(). This leads to unexpected behavior as the purpose of ZonedDateTime is to have an instant in a specific timezone. Otherwise LocalDateTime could be used. From version 2.0.0 onwards, this behavior can be changed by providing a Java8Configuration with a specific TimezoneStrategy when creating the Java8ObjectWrapper. Due to backwards compability this behavior is still present when creating a Java8ObjectWrapper without a Java8Configuration. The Java8Configuration.defaultConfiguration() however uses a different TimezoneStrategy. There are currently 4 builtin strategies:

  1. EnvironmentTimezoneStrategy: Always uses the ZoneId provided by the Environment.getCurrentEnvironment(). This is the default strategy for version < 2.0.0. This strategy is used when creating a Java8ObjectWrapper without a Java8Configuration

  2. KeepingTimezoneStrategy: Does not change the ZoneId. This is the default strategy used when creating a Java8Configuration.defaultConfiguration().

  3. StaticTimezoneStrategy: Always uses the ZoneId provided when constructing this strategy.

  4. SystemTimezoneStrategy: Always uses the ZoneId provided by ZoneId.systemDefault()

About

Java library adding support for the Java 8 java.time api to FreeMarker.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 77.5%
  • Gherkin 22.5%