Парсинг времени с плавающим количеством миллисекунд

Есть ответ api-запроса, который автоматически парсится, выглядит это примерно вот так :

public class Message {

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSSSSSSSS]X")
private ZonedDateTime createdAt;

@Builder.Default
private String message = RandomUtils.getRuFaker().lorem().paragraph();

private Integer id;

private Integer topicId;}

Дело в том, что в объекте createdAt приходи время с разным количеством миллисекунд. Например :

  • 2021-05-19T08:51:16.404030Z
  • 2021-05-18T20:06:13.726886244Z

Как распарсить такое чтобы меньше костылей было?


Ответы (2 шт):

Автор решения: Aziz Umarov

Попробуйте так. Нужен будет кастомный Deserializer для поля и все будет хорошо.

public class Message {

  @JsonDeserialize(using = ZonedDateTimeDeserializer.class)
  private ZonedDateTime createdAt;

  @Builder.Default
  private String message = RandomUtils.getRuFaker().lorem().paragraph();

  private Integer id;

  private Integer topicId;
}

Собственно сам
ZonedDateTimeDeserializer.java

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.time.ZonedDateTime;

public class ZonedDateTimeDeserializer extends StdDeserializer<ZonedDateTime> {
  private static final long serialVersionUID = 1L;

  public ZonedDateTimeDeserializer() {
    this(null);
  }

  public ZonedDateTimeDeserializer(Class<?> vc) {
    super(vc);
  }

  @Override
  public ZonedDateTime deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
    JsonNode node = jp.getCodec().readTree(jp);
    final String date = node.textValue();
    return ZonedDateTime.parse(date);
  }
}

Можете тут

   return ZonedDateTime.parse(date);

парсить строку какую хотите в каком то либо формате.

И проверка

public static void main(String[] args) throws Exception {
    String json1 =
        "{ \"createdAt\": \"2021-05-19T08:51:16.404030Z\", \"message\": \"test\", \"id\":1,"
            + " \"topicId\": null}";
    String json2 =
        "{ \"createdAt\": \"2021-05-18T20:06:13.726886244Z\", \"message\": \"test\", \"id\":2,"
            + " \"topicId\": null}";

    ObjectMapper mapper = new ObjectMapper();

    Message message1 = mapper.readValue(json1, Message.class);
    Message message2 = mapper.readValue(json2, Message.class);
    System.out.println(message1.getCreatedAt()); //2021-05-19T08:51:16.404030Z
    System.out.println(message2.getCreatedAt());//2021-05-18T20:06:13.726886244Z
    System.out.println(message1.getCreatedAt().getNano()); // 404030000
    System.out.println(message2.getCreatedAt().getNano()); // 726886244

  }
→ Ссылка
Автор решения: Alexandr

Можете указать yyyy-MM-dd'T'HH:mm:ss[.SSSSSSSSS][.SSSSSS]X или yyyy-MM-dd'T'HH:mm:ss.[SSSSSSSSS][SSSSSS]X. Также будет корректно работать и без паттерна. Если у Вас все равно возникает ошибка при использовании указанных выше паттернов, то рекомендую Вам обновить версию Jackson-а.

package com.somepackage;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.Setter;
import lombok.ToString;

import java.time.ZonedDateTime;

class Main {

    @Setter
    @ToString
    public static class Message {

        @JsonFormat(
                shape = JsonFormat.Shape.STRING, 
                pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSSSSSSSS][.SSSSSS]X"
        )
        private ZonedDateTime createdAt;

    }

    public static void main(String[] args) throws Exception {
        final String json1 =
                "{\"createdAt\": \"2021-05-19T08:51:16.404030Z\"}";
        final String json2 =
                "{\"createdAt\": \"2021-05-18T20:06:13.726886244Z\"}";

        final ObjectMapper mapper =
                new ObjectMapper()
                        .registerModule(new JavaTimeModule());
        final Message message1 = mapper.readValue(json1, Message.class);
        System.out.println(message1);
        final Message message2 = mapper.readValue(json2, Message.class);
        System.out.println(message2);
    }
}

Результат:

Main.Message(createdAt=2021-05-19T08:51:16.404030Z[UTC])
Main.Message(createdAt=2021-05-18T20:06:13.726886244Z[UTC])
→ Ссылка