Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot construct instance of java.time.LocalDateTime - Jackson

I have two Spring Boot applications which communicate through JMS Messaging and ActiveMQ.

One app sends to the other app an object which contains a LocalDateTime property. This object is serialized to JSON in order to be sent to the other application.

The problem I'm facing is that Jackson is not able to deserialize the LocalDateTime property when it's trying to map the incoming json to my object. The LocalDateTime property has the following format when it arrives to the "listener app":

"lastSeen":{
  "nano":0,
  "year":2019,
  "monthValue":4,
  "dayOfMonth":8,
  "hour":15,
  "minute":6,
  "second":0,
  "month":"APRIL",
  "dayOfWeek":"MONDAY",
  "dayOfYear":98,
  "chronology":{
    "id":"ISO",
    "calendarType":"iso8601"
  }
}

The exception I'm getting is the following:

org.springframework.jms.support.converter.MessageConversionException: Failed to convert JSON message content; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of java.time.LocalDateTime

I was able to fix this issue temporarily by using the following annotations:

@JsonSerialize(as = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class, as = LocalDateTime.class)
private LocalDateTime lastSeen;

but they belong to jackson datatype jsr310 which is now DEPRECATED.

Is there any way/alternative to deserialize this LocalDateTime property without using the above annotations? Or how do I get this to work using the recommended jackson-modules-java8?

like image 419
Daniel Castillo Avatar asked Jan 26 '23 18:01

Daniel Castillo


1 Answers

I remember I did not have this problem with older versions of spring (or maybe I was LUCKY) But this is how I solved it in Spring boot 2.1.7.RELEASE:

First, add Jackson's support modules in order to support Java 8 features (TimeDate API)

    <dependency>
        <groupId>com.fasterxml.jackson.module</groupId>
        <artifactId>jackson-module-parameter-names</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jdk8</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
    </dependency>

Then register a default ObjectMapper bean with custom configurations (to support Java 8) in the Spring.

@Bean
@Primary
public ObjectMapper geObjMapper(){
    return new ObjectMapper()
            .registerModule(new ParameterNamesModule())
            .registerModule(new Jdk8Module())
            .registerModule(new JavaTimeModule());
}

NOTE: @Primary is used as a precautionary measure, so if there are other ObjectsMapper beans on the class-path, the spring will pick this one by default.

like image 157
Mr.Q Avatar answered Jan 31 '23 02:01

Mr.Q