【问题标题】:LocalDateTime field: MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT tokenLocalDateTime 字段:MismatchedInputException:无法从 START_OBJECT 令牌中反序列化 `java.lang.String` 的实例
【发布时间】:2021-07-13 20:25:17
【问题描述】:

我有一个主课:

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class ContentModel implements Serializable {
    @JsonProperty("serviceData")
     private ServiceData serviceData;
}

和嵌套类:

 @NoArgsConstructor
 @AllArgsConstructor
 @Data
 @Builder
 public class ServiceData implements Serializable {
    @JsonProperty ("dateTimeMessageSend")
    private LocalDateTime dateTimeMessageSend;
 }

我正在尝试通过使用自定义反序列化器来反序列化:

public class LocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {
   private static final long serialVersionUID = 1L;
   protected LocalDateTimeDeserializer() {
        super(LocalDateTime.class);
    }

   @Override
   public LocalDateTime deserialize(final JsonParser jp, final DeserializationContext ctxt)
         throws IOException {
       return LocalDateTime.parse(jp.readValueAs(String.class));
    }
 }

这就是我如何配置我的 objectMapper:

  JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
    this.objectMapper.registerModule(javaTimeModule);
    this.objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    this.objectMapper.registerModule(new Jdk8Module());
    this.objectMapper.findAndRegisterModules();
 

应用程序在以下 json 之外接收:

{
 "serviceData": {
    "dateTimeMessageSend": {
       "month": "APRIL",
       "dayOfYear": 109,
       "dayOfWeek": "MONDAY",
       "nano": 183251000,
       "year": 2021,
       "monthValue": 4,
       "dayOfMonth": 19,
       "hour": 14,
       "minute": 52,
       "second": 44,
       "chronology": {
          "calendarType": "iso8601",
          "id": "ISO"
         }
      },
    }
 }

在 LocalDateTime 反序列化时,我收到异常:

 MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token

我想,jackson 将“dateTimeMessageSend”识别为一个对象并且无法将其解析为字符串。

解决问题的方法是什么?

  1. 修改源 json,例如将 LocalDateFormat 更改为 String。 (什么是不受欢迎的)
  2. objectMapper 或/和 LocalDateTimeDeserializer 的进一步自定义

【问题讨论】:

  • 如果您收到 那个 JSON,那么发件人没有注册 JavaTimeModule。强烈建议修复发件人。如果您无法修复发件人,则需要一个 custom 反序列化程序,该反序列化程序使用 LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) 方法从该 JSON 对象数据中实例化 LocalDateTime
  • 安德烈亚斯,有些事情正在变得清晰起来。但是您所说的“发件人已修复”是什么意思?
  • 该 JSON 的发送者不应该这样构建它。应该是"dateTimeMessageSend": "2021-04-19T14:52:44.183251"如果可能,需要修复发送代码才能做到这一点。然后在您端(接收端)解析将正常工作,无需自定义反序列化器。
  • 是的,安德烈亚斯。我在发送者对象映射器 JavaTimeModule 中注册。问题就解决了。

标签: java jackson deserialization localdatetime


【解决方案1】:

似乎对您实际收到的内容存在一些误解 当 Jackson 调用您的 LocalDateTimeSerializer 时,在 deserialize 方法中。

你不只是得到一个长字符串,比如 { "month": "APRIL", "dayOfYear": 109, ... }。 因此,您不能只是简单地调用

jp.readValueAs(String.class);

你在这里有一个MismatchedInputExcpetion,因为解析器 遇到{ 而不是字符串"something"

实际上你得到了一个令牌流(以{开头) 您应该使用到关闭的} 令牌, 从中提取相关部分, 并从这些部分构建一个LocalDateTime 对象。

例如见Baeldung - Getting started with deserialization in Jackson, 特别是那里给出的自定义解串器示例。 按照本教程,您可以像这样实现deserialize 方法:

@Override
public LocalDateTime deserialize(final JsonParser jp, final DeserializationContext ctxt)
         throws IOException {
    JsonNode node = jp.getCodec().readTree(jp);
    int year = ((NumericNode) node.get("year")).asInt();
    int monthValue = ((NumericNode) node.get("monthValue")).asInt();
    int dayOfMonth = ((NumericNode) node.get("dayOfMonth")).asInt();
    int hour = ((NumericNode) node.get("hour")).asInt();
    int minute = ((NumericNode) node.get("minute")).asInt();
    int second = ((NumericNode) node.get("second")).asInt();
    return LocalDateTime.of(year, monthValue, dayOfMonth, hour, minute, second);
}

请注意,接收到的 JSON 树中有相当多的冗余表示 LoclDateTime。例如:它包含"month": "APRIL" "monthValue": 4。因此,您不需要提取所有 树中的值,但只有一些值。

【讨论】:

  • 你是对的。这是一个解决方案。但我找到了更简单的方法。我在发送者对象映射器 JavaTimeModule 中注册。问题就解决了
  • @Andrew 是的,在发送方和接收方都使用"dateTimeMessageSend": "2021-04-19T14:52:44" 之类的东西要简单得多。
猜你喜欢
  • 1970-01-01
  • 2019-06-01
  • 2013-10-23
  • 2019-12-13
  • 2019-02-08
  • 2017-09-23
  • 1970-01-01
  • 2018-05-22
  • 1970-01-01
相关资源
最近更新 更多