This tutorial is going to illustrate how to serialize Java 8 LocaleDate with Jackson in Spring Boot. Besides, we also get through how to serialize other types of Java 8 Date Time API.
1. Overview
Java 8 introduced us a new Date-Time API to work with date and time (known as JSR-310), and some of the typical types of the new API are LocalDate, LocalDateTime, ZonedDateTime. During the time we develop our software, we may want to serialize some objects contain those types into JSON using Jackson. However, Jackson core library doesn’t support the Java 8 new Date-Time API by default. Therefore, when Jackson serializes those types, it treats them as normal Java objects and results are not incorrect date-time formats. For example, let’s see how the current LocalDate (at the time writing) is serialized into JSON by Jackson:
1 2 3 4 5 6 7 |
@Test public void testJava8DateTimeJackson() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); System.out.println(objectMapper.writerWithDefaultPrettyPrinter() .writeValueAsString(LocalDate.now())); } |
The JSON is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "year" : 2017, "month" : "DECEMBER", "era" : "CE", "dayOfMonth" : 30, "dayOfWeek" : "SATURDAY", "dayOfYear" : 364, "leapYear" : false, "monthValue" : 12, "chronology" : { "id" : "ISO", "calendarType" : "iso8601" } } |
While the output we might want is just: “2017-12-30”.
To enable Jackson to support the new Java 8 Date Time API, we will need to use JavaTimeModule, a class that registers capability of serializing java.time objects with the Jackson core. And that class is included in the jackson-datatype-jsr310 module.
2. Prerequisites
2.1. Jackson Library Dependency
We will need to include Jackson core and jackson-datatype-jsr310 in our classpath. To use those with Maven:
1 2 3 4 5 6 7 8 9 10 |
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.9.3</version> </dependency> |
2.2. POJO Class
For all examples in this tutorial, we will use a POJO called Member defined as follows:
1 2 3 4 5 6 7 8 9 10 |
public class Member { private Long id; private String firstName; private String lastName; private LocalDate birthDate; private LocalDateTime registeredDateTime; //getters and setters } |
3. Serialize Java 8 LocalDate With Jackson
Let’s see how we serialize Java 8 LocalDate with Jackson in the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Member member = new Member(); member.setId(1L); member.setFirstName("Tom"); member.setLastName("Sawyer"); member.setBirthDate(LocalDate.of(2001, Month.APRIL, 20)); member.setRegisteredDateTime(LocalDateTime.of( 2017, Month.JUNE, 29, 20, 40, 59)); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); System.out.println(objectMapper.writerWithDefaultPrettyPrinter() .writeValueAsString(member)); |
Firstly we need to initialize an ObjectMapper object. Then we will need to register it a JavaTimeModule object. And finally, we configure the value of the WRITE_DATES_AS_TIMESTAMPS feature to false which indicates that the dates object will be serialized as textual values instead of timestamps.
Running the example will give us the result:
1 2 3 4 5 6 7 |
{ "id" : 1, "firstName" : "Tom", "lastName" : "Sawyer", "birthDate" : "2001-04-20", "registeredDateTime" : "2017-06-29T20:40:59" } |
4. Change Serialization Format Of LocalDate With Jackson
To change the serialization format of a LocalDate object with Jackson, we simply annotate the fields with @JsonFormat annotation and specify the desired date-time pattern. For example, let’s change the format of the birthDate field to yyyy/MM/dd.
1 2 3 4 5 6 7 8 9 |
public class Member { private Long id; private String firstName; private String lastName; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy/MM/dd") private LocalDate birthDate; private LocalDateTime registeredDateTime; } |
Running the example again will give us the result:
1 2 3 4 5 6 7 |
{ "id" : 1, "firstName" : "Tom", "lastName" : "Sawyer", "birthDate" : "2001/04/20", "registeredDateTime" : "2017-06-29T20:40:59" } |
5. Serialize Java 8 LocalDate With Jackson In Spring Boot
To serialize Java 8 LocalDate with Jackson and other types as well in Spring Boot, firstly, we need to include the jackson-datatype-jsr310 in the classpath, for example:
1 2 3 4 5 6 7 8 |
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency> |
Secondly, we need to we configure the value of the WRITE_DATES_AS_TIMESTAMPS features to false in the application.properties file, for example:
1 |
spring.jackson.serialization.write-dates-as-timestamps=false |
Next, let’s see a sample Ret controller written in Spring Boot as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@RestController public class MemberController { @RequestMapping("/member") public Member getDefaultMember() { Member member = new Member(); member.setId(1L); member.setFirstName("Tom"); member.setLastName("Sawyer"); member.setBirthDate(LocalDate.of(2001, Month.APRIL, 20)); member.setRegisteredDateTime(LocalDateTime.of(2017, Month.JUNE, 29, 20, 40, 59)); return member; } } |
When we make a request to the above API, the birthDate will be returned in the correct text format yyyy-MM-dd:
1 2 3 4 5 6 |
@Test public void getMemberTest() throws Exception { this.mockMvc.perform(get("/member")).andDo(print()).andExpect(status().isOk()) .andExpect(jsonPath("$.birthDate").value("2001-04-20")); } |
6. Conclusions
The tutorial has illustrated us how to serialize Java 8 LocaleDate with Jackson in Spring Boot. We got through both how to configure Jackson to work independently and to work with Spring Boot as well. Notice that the configuration also works for other types of Java 8 Date Time API such as LocalDateTime, ZonedDateTime, etc.
The sample source code presented in this tutorial is available on my Github project. It’s both a Maven and Gradle based project. Therefore, it’s is easy to be imported in IDE such as Eclipse, IntelliJ, etc.
Below are other related tutorials for your references:
Ignore Unknown Properties or New Fields in Jackson
How to Configure Logging in Spring Boot