Spring Boot LocalDate field serialization and deserialization
Asked Answered
B

7

15

In Spring Boot 1.2.3.RELEASE with fasterxml what is the correct way of serializing and de-serializing a LocalDate field to ISO date formatted string?

I've tried:

  • spring.jackson.serialization.write-dates-as-timestamps:false in application.properties file,

  • including jackson-datatype-jsr310 in project and then using

    • @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") annotation

    • and @DateTimeFormat(iso=ISO.DATE) annotation,

  • adding Jsr310DateTimeFormatAnnotationFormatterFactory as formatter with:

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatterForFieldAnnotation(new Jsr310DateTimeFormatAnnotationFormatterFactory());
    }
    

None of the above helped.

Backfield answered 16/6, 2015 at 14:58 Comment(0)
B
30
compile ("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")

in build.gradle and then following annotations helped:

@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate birthday;

Update: if you are using Spring Boot 2.*, the dependency is already included via one of the "starters".

Backfield answered 16/6, 2015 at 20:40 Comment(5)
This fixed it for me. I encountered the deserialization issue when I upgraded to use the 1.3.0.BUILD.SNAPSHOT version of spring boot.Circuity
can you specified you solution?Kea
Yes you need the com.fasterxml.jackson.datatype:jackson-datatype-jsr310 dependency and then you can use @JsonDeserialize @JsonSerialize annotations with the LocalDate field using LocalDateSerializer like in the answer.Backfield
Doesn't work for me on SpringBoot 1.3.6.RELEASE ;/ Getting error: com.fasterxml.jackson.datatype.jsr310.ser.JSR310FormattedSerializerBase.findFormatOverrides(Lcom/fasterxml/jackson/databind/SerializerProvider;Lcom/fasterxml/jackson/databind/BeanProperty;Ljava/lang/Class;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value;Graceless
solved my problem. with LocalDateTime jackson deserialization, thanksKrutz
H
15

In my Spring Boot 2 applications

  • @JsonFormat annotation is used in REST controllers when (de)serializing JSON data.
  • @DateTimeFormat annotation is used in other controllers ModelAttributes when (de)serializing String data.

You can specify both on the same field (useful if you share DTO between JSON and Thymeleaf templates):

@JsonFormat(pattern = "dd/MM/yyyy") 
@DateTimeFormat(pattern = "dd/MM/yyyy")
private LocalDate birthdate;

Gradle dependency:

implementation group: 'org.springframework.boot', name: 'spring-boot-starter-json'

I hope this is all configuration you need for custom Date/Time formatting in Spring Boot 2.x apps.


For Spring Boot 1.x apps, specify additional annotations and dependency:

@JsonFormat(pattern = "dd/MM/yyyy")
@DateTimeFormat(pattern = "dd/MM/yyyy")
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate birthDate;

// or
@JsonFormat(pattern = "dd/MM/yyyy HH:mm")
@DateTimeFormat(pattern = "dd/MM/yyyy HH:mm")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime birthDateTime;
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.9.8'

Be aware that your API will throw "JSON parse error" if somebody sends a date in a wrong format. Mapping example:

@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate releaseDate;

Exception example:

HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type java.time.LocalDate from String "2002": Failed to deserialize java.time.LocalDate: (java.time.format.DateTimeParseException) Text '2002' could not be parsed at index 4; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.time.LocalDate from String "2002": Failed to deserialize java.time.LocalDate: (java.time.format.DateTimeParseException) Text '2002' could not be parsed at index 4

Hedonics answered 28/12, 2018 at 12:48 Comment(0)
R
5

If you want to use a custom Java Date formatter, add the @JsonFormat annotation.

@JsonFormat(pattern = "dd/MM/yyyy")
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate birthdate;*
Redstone answered 3/6, 2017 at 18:37 Comment(1)
You should offer a way to set it globally. Adding @JsonFormat for every POJO is tedious. The answer from @chen should be the best.Whitehot
D
5

Actually, it works if you just specify the dependency in the pom.xml.

With this, all my LocalDate fields automatically use the ISO format, no need to annotate them:

<!-- This is enough for LocalDate to be deserialized using ISO format -->
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

Tested on Spring Boot 1.5.7.

Dither answered 23/10, 2017 at 8:8 Comment(0)
N
3

Instead of specifying the serializer/deserializer for all your LocalDate attributes, you might be interested in registering it globally. You need to override the configuration of the default ObjectMapper used by Spring for serialization/deserialization. Here is an example:

@Configuration
public class ObjectMapperConfiguration {

    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();

        // Registro global do serializer/deserializer para datas sem horário
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer());
        simpleModule.addDeserializer(LocalDate.class, new LocalDateDeserializer());

        mapper.registerModule(simpleModule);
        return mapper;
    }
}

This way, Jackson will always use the specified serializer/deserializer for the data type defined, without the need to annotate your classes attributes.

Info: you must add the jackson-databind dependency to your pom.xml to have the custom serializer/deserializer code feature:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
</dependency>
News answered 21/8, 2022 at 23:3 Comment(0)
D
0
 @Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
    return builder -> {
        DateTimeFormatter localDateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        builder.serializerByType(LocalDate.class, new LocalDateSerializer(localDateFormatter));
        builder.deserializerByType(LocalDate.class, new LocalDateDeserializer(localDateFormatter));

        DateTimeFormatter localDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(localDateTimeFormatter));
        builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(localDateTimeFormatter));
    };
}
Divorcee answered 27/10, 2021 at 3:25 Comment(1)
You should have mentioned that this will set the format globally in the Spring app.Whitehot
O
0

You might be having LocalDateTime or LocalDate being used in different classes. Creating a config class and adding custom ObjectMapper bean can help:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CustomMapper {
    @Bean
    public ObjectMapper objectMapper(){
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
//The below helped me to solve the issue
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        return objectMapper;
    }
Ombre answered 18/6 at 11:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.