Java fasterxml.jackson反序列化LocalDateTime时遇到WrongTokenException异常

3
  • Java 1.8
  • Spring Boot 1.5.8
  • faster.xml.jackson (jackson-module-parameter-names, jackson-datatype-jdk8, jackson-datatype-jsr310) 2.9.2

我有一个带时间戳的对象。

@JsonProperty("timestamp")
private LocalDateTime timestamp;  

我需要反序列化的LocalDateTime时间戳是:
{ 
   "year":2017,
   "month":"OCTOBER",
   "dayOfMonth":27,
   "dayOfWeek":"FRIDAY",
   "dayOfYear":300,
   "monthValue":10,
   "nano":460000000,
   "hour":4,
   "minute":47,
   "second":29,
   "chronology":{  
      "calendarType":"iso8601",
      "id":"ISO"
   }
}

我尝试使用以下方法对对象进行反序列化:

MyObject myObject=
         new ObjectMapper()
             .findAndRegisterModules()
             .treeToValue(jsonPayload, MyObject.class);

该应用程序在此调用时冻结,如果我中断调用,将会收到以下错误消息:
Error while stopping the container:
java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(Lcom/fasterxml/jackson/core/JsonParser;Ljava/lang/Class;Lcom/fasterxml/jackson/core/JsonToken;Ljava/lang/String;)Lcom/fasterxml/jackson/databind/JsonMappingException;
        at com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer.deserialize(LocalDateTimeDeserializer.java:138) ~[jackson-datatype-jsr310-2.9.2.jar!/:2.9.2]
        at com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer.deserialize(LocalDateTimeDeserializer.java:39) ~[jackson-datatype-jsr310-2.9.2.jar!/:2.9.2]
        at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:504) ~[jackson-databind-2.8.10.jar!/:2.8.10]
        at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:111) ~[jackson-databind-2.8.10.jar!/:2.8.10]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276) ~[jackson-databind-2.8.10.jar!/:2.8.10]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140) ~[jackson-databind-2.8.10.jar!/:2.8.10]
        at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3786) ~[jackson-databind-2.8.10.jar!/:2.8.10]
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2115) ~[jackson-databind-2.8.10.jar!/:2.8.10]
        at com.fasterxml.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:2612) ~[jackson-databind-2.8.10.jar!/:2.8.10]

更新:

完整的JSON如下:

{"valid":true,"version":"0.0.1",
"timestamp":{"year":2017,"month":"OCTOBER","dayOfMonth":27,"dayOfWeek":"FRIDAY","dayOfYear":300,"monthValue":10,"nano":460000000,"hour":4,"minute":47,"second":29,"chronology":{"calendarType":"iso8601","id":"ISO"}},
"tenant":"stackoverflow","uid":"10fa132f-2c92-4fa5-bcc2-ee6023281503"})

序列化使用:

String jsonString = new ObjectMapper().writeValueAsString(messageIndex);

对象属性:
@JsonProperty("version")
private String version;

@JsonProperty("timestamp")
private LocalDateTime timestamp;

@JsonProperty("tenant")
private String tenant;

@JsonProperty("dataSampleUid")
private UUID uid;

private boolean isValid;

LocalDateTime 是通过以下方式设置的:

LocalDateTime.now()

有使用 treeToValue 的理由吗?为什么不使用 jsonMapper.readValue(object, class) ? - mrkernelpanic
使用JsonNode可以验证模式。我尝试了readValue,但没有改变。问题是反序列化程序在处理LocalDateTime时出现问题,请参见错误片段的第3行和第4行。 - Daniel Eisenreich
我只是好奇,你能否将jackson依赖项(特别是jackson-datatype-jsr310)从版本2.9.2回退到早期版本,例如2.8.10? - mrkernelpanic
1
我写了一个小测试,其中包含一个时间戳的POJO。与您的JSON不同之处在于,当我对其进行序列化时,JSON看起来像{"timestamp":[2017,10,27,8,22]},而您的则显得过于冗长。也许您只需要检查一下序列化方面并稍作调整即可。 - mrkernelpanic
你的LocalDateTime的JSON表示不是JavaTimeModule处理它的方式。序列化的LocalDateTime看起来像对象的默认序列化(对象的所有可访问字段)。你能展示一下你如何序列化它吗?然而,当你反序列化时,你注册了JavaTimeModule,因此期望一个数组(就像@mrkernelpanic所说的那样)。 - JEY
@JEY更新了关于序列化的帖子。 - Daniel Eisenreich
1个回答

4

在序列化时,您没有注册任何模块,特别是JavaTimeModule,因此LocalDateTime将像任何其他对象一样被序列化(打印所有可访问字段)。但是,在反序列化部分,您注册了此模块,并且它们期望LocalDateTime采用特定的格式(默认为数组)。

如果您希望此功能正常工作,请更新序列化部分:

String jsonString = new ObjectMapper().findAndRegisterModules().writeValueAsString(messageIndex);

您应该在整个应用程序中重用同一个对象映射器,读者也是如此。这两种操作都因线程安全和实例相对较轻而需要这样做。

运行此代码,您将看到它正在正常工作,并且您将看到LocalDateTime序列化值的差异。

ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
MyObject data = new MyObject();
data.setTimestamp(LocalDateTime.now());
String result = mapper.writeValueAsString(data);
System.out.println(result);
JsonNode tree = mapper.reader().readTree(result);
mapper.treeToValue(tree, MyObject.class);

不做改变。 - Daniel Eisenreich
我添加了一个快速示例,运行它你就会看到。 - JEY
你说得对,我在编译之前进行了完全的清理,现在一切正常!非常感谢! - Daniel Eisenreich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接