Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize LocalDateTime from String with Jackson

Tags:

java

json

jackson

I'm trying to deserialize a String to LocalDateTime with Jackson but it doesn't work.

I have a data class with a LocalDateTime field:

@Data
public class Registration {
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
    private LocalDateTime timestamp;
}

I added the special Jackson datatype modules:

compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")

The serialization works fine with:

new ObjectMapper().registerModule(new JavaTimeModule()).writeValueAsString(registration);

Result String:

{"timestamp":"2018-09-03 10:09:35"}

But the deserialization doesn't work with:

new ObjectMapper().registerModule(new JavaTimeModule()).readValue(json.traverse(), Registration.class)

As error I get:

Cannot deserialize value of type `java.time.LocalDateTime` from String "2018-09-03 10:09:35": 
    Failed to deserialize java.time.LocalDateTime: 
        (java.time.format.DateTimeParseException) Text '2018-09-03 10:09:35' could not be parsed: 
            Unable to obtain LocalDateTime from TemporalAccessor: 
                {MinuteOfHour=9, NanoOfSecond=0, SecondOfMinute=35, MicroOfSecond=0, MilliOfSecond=0, HourOfAmPm=10},
                ISO resolved to 2018-09-03 of type java.time.format.Parsed

What am I missing? I'm confused that the serialization works but the deserialization doesn't.


MWE: (small gradle Java project)

Main.java:

import java.io.IOException;
import java.time.LocalDateTime;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

public class Main {

    public static void main(String[] args) throws IOException {
        Registration registration = new Registration();
        registration.setTimestamp(LocalDateTime.now());

         ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());

         String s = objectMapper.writeValueAsString(registration);
         TreeNode treeNode = objectMapper.readTree(s);

         //Fails here:
         Registration registration1 = objectMapper.readValue(treeNode.traverse(), Registration.class);

        System.out.println(registration1);
    }
}

class Registration {
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
    private LocalDateTime timestamp;

    public Registration() {
    }

    public LocalDateTime getTimestamp() {
        return this.timestamp;
    }

    public void setTimestamp(LocalDateTime localDateTime) {
        this.timestamp = localDateTime;
    }
}

build.gradle:

plugins {
    id 'java'
}

group 'dateMWE'
version '1.0-SNAPSHOT'

sourceCompatibility = 10

repositories {
    mavenCentral()
}

dependencies {
    compile("com.fasterxml.jackson.core:jackson-annotations:2.9.6")
    compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.6")
}
like image 767
Spenhouet Avatar asked Sep 03 '18 09:09

Spenhouet


2 Answers

The problem is not related with JSON deserialization, but rather with the time format string:

pattern = "yyyy-MM-dd hh:mm:ss"

Please notice that the hours are set as hh: this is a 12-hour formatter, which requires "AM" or "PM" values.

If the pattern is changed to

pattern = "yyyy-MM-dd HH:mm:ss"

the problem should be solved.

like image 108
Antot Avatar answered Oct 25 '22 21:10

Antot


Your ObjectMapper is not managed by spring since you are creating object with new. Configure ObjectMapper as Bean in your configuration file. You need to register the DateTimeFormat with your LocalDateTimeDeserializer. Then set your Deserializer in JavaTimeModule.

@Bean
public ObjectMapper objectMapper() {
    JavaTimeModule module = new JavaTimeModule();
    LocalDateTimeDeserializer localDateTimeDeserializer = new
            LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
    ObjectMapper objectMapperObj = Jackson2ObjectMapperBuilder.json()
            .modules(module)
            .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
            .build();
    return objectMapperObj;
}

Set the above configuration in your Spring configuration.

like image 12
Sangam Belose Avatar answered Oct 25 '22 21:10

Sangam Belose