无法构造 java.time.LocalDateTime 的实例 - Jackson

Dan*_*llo 4 java spring jackson spring-jms java-8

我有两个 Spring Boot 应用程序,它们通过 JMS 消息传递和 ActiveMQ 进行通信。

一个应用程序向另一个应用程序发送一个包含 LocalDateTime 属性的对象。此对象被序列化为 JSON,以便发送到其他应用程序。

我面临的问题是 Jackson 在尝试将传入的 json 映射到我的对象时无法反序列化 LocalDateTime 属性。LocalDateTime 属性在到达“侦听器应用程序”时具有以下格式:

"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"
  }
}
Run Code Online (Sandbox Code Playgroud)

我得到的例外如下:

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

我能够通过使用以下注释暂时解决这个问题:

@JsonSerialize(as = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class, as = LocalDateTime.class)
private LocalDateTime lastSeen;
Run Code Online (Sandbox Code Playgroud)

但它们属于jackson 数据类型 jsr310,现在已弃用

有什么方法/替代方法可以在不使用上述注释的情况下反序列化这个 LocalDateTime 属性?或者我如何使用推荐的jackson-modules-java8 让它工作

Mr.*_*r.Q 7

我记得我在旧版本的 spring 上没有这个问题(或者我很幸运)但这是我在 Spring boot 2.1.7.RELEASE 中解决它的方法:

首先,添加Jackson 的支持模块以支持 Java 8 功能(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>
Run Code Online (Sandbox Code Playgroud)

然后在 Spring 中使用自定义配置(以支持 Java 8)注册一个默认的 ObjectMapper bean。

@Bean
@Primary
public ObjectMapper geObjMapper(){
    return new ObjectMapper()
            .registerModule(new ParameterNamesModule())
            .registerModule(new Jdk8Module())
            .registerModule(new JavaTimeModule());
}
Run Code Online (Sandbox Code Playgroud)

注意:@Primary 用作预防措施,因此如果类路径上还有其他 ObjectsMapper bean,则默认情况下 spring 会选择这个。