Search code examples
javajsonspringdeserializationfasterxml

Java fasterxml.jackson deserialize LocalDateTime wrongTokenException


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

I have a object with a timestamp.

@JsonProperty("timestamp")
private LocalDateTime timestamp;  

The LocalDateTime stamp I need to deserialize is:

{ 
   "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"
   }
}

I try to deserialize the object with:

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

The application freezes at this call and if I interrupt the call I get the following error message:

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]

UPDATE'S:

The whole JSON is:

{"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"})

Serialized with:

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

The object attributes:

@JsonProperty("version")
private String version;

@JsonProperty("timestamp")
private LocalDateTime timestamp;

@JsonProperty("tenant")
private String tenant;

@JsonProperty("dataSampleUid")
private UUID uid;

private boolean isValid;

The LocalDateTime is set with:

LocalDateTime.now()

Solution

  • When serializing you didn't register any module especially the JavaTimeModule therefore LocalDateTime are going to be serialized just like any other object (printing all their accessible fields). However in the deserialization part you registered this module and they expect a specific format for the LocalDateTime (by default an array).

    If you want this to work just update the serialization part:

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

    You should reuse the same object mapper through your application same is true for reader. Both because of thread-safety and because instances are relatively light-weight.

    Run this and you will see that it's working properly and you will see the differences in LocalDateTime serialized value.

    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);