2

I have an error when I try to deserialize this attribute:

@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime deliveryDate;

This is the deserialization class:

public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    @Override
    public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {

        if (parser.getCurrentToken().equals(JsonToken.VALUE_STRING)) {
            String rawDate = parser.getText();
            return LocalDateTime.parse(rawDate);
        } else {
            throw context.wrongTokenException(parser, JsonToken.VALUE_STRING, "Expected string.");
    }
}

And the serialization class:

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

    @Override
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {

        gen.writeString(value.toString());
    }

This is the error I get:

"timestamp":1513962011642,"status":400,"error":"Bad Request","exception":"org.springframework.http.converter.HttpMessageNotReadableException","message":"Could not read document: Text '2017-12-22T16:00:00.874Z' could not be parsed, unparsed text found at index 23 

Do you know why?

Thanks!

Anna
  • 839
  • 2
  • 17
  • 33

2 Answers2

1

tl;dr

Process as an Instant rather than LocalDateTime.

Instant.parse( "2017-12-22T16:00:00.874Z" )

Details

Not sure of your original data from JSON. If your input data is 1513962011642, it appears to be a count since an epoch, presumably an epoch reference date of 1970-01-01T00:00:00Z, the first moment of 1970 in UTC.

Instant instant = Instant.ofEpochMilli( 1_513_962_011_642L ) ;

If the original input is 2017-12-22T16:00:00.874Z, directly parse as an Instant. That string is in standard ISO 8601 format. The Z on the end is short for Zulu and means UTC.

The java.time classes use the standard formats by default when parsing/generating strings.

Instant instant = Instant.parse( "2017-12-22T16:00:00.874Z" ) ;

A LocalDateTime purposely lacks any concept of a time zone or offset from UTC, so it does not represent an actual moment and is not a point on the timeline. You are mistakenly trying to fit your value into the wrong class, where the fact it is a UTC value cannot be represented.

Instead, process that input as an Instant object. An instant represents a point on the timeline in UTC with a resolution of nanoseconds.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

Actually the error is pretty straightforward, it says that spring can't deserialize this string "2017-12-22T16:00:00.874Z" to LocalDateTime. If you will run the next code you will see the same error:

public static void main(String[] args) {
    System.out.println(LocalDateTime.parse("2017-12-22T16:00:00.874Z"));
}

The source of the error is character 'Z' at index 23. If you will remove this character the code above will work. So i would recommend you to check why this 'Z' character is present in the string while your serializer doesn't add it.

Mikita Harbacheuski
  • 2,193
  • 8
  • 16
  • 1
    Poor advice. Discarding the `Z` is throwing away information, the fact that this string represents a moment in UTC. The real issue is that the input should be processed as a `Instant` rather than as a `LocalDateTime`. – Basil Bourque Dec 22 '17 at 17:48
  • While i admit that Z can be present it the string i didn't suggest to remove it. And the question isn't about necessity of presence of this character. The question is - why the error occurs, the answer is - deserializer can't deserialize such string because of presence of Z character which isn't added during serialization. And advice is to figure out why it is present. Different format on server and client could be the reason but i can't be such categorial as you because i don't have enough details. – Mikita Harbacheuski Dec 22 '17 at 18:15
  • Thanks for the explanation :) – Anna Dec 26 '17 at 14:18