【问题标题】:How to make milliseconds optional in @JsonFormat for Timestamp parsing with Jackson?如何在@JsonFormat 中使毫秒为可选,以便使用杰克逊进行时间戳解析?
【发布时间】:2017-04-23 13:32:27
【问题描述】:

我的对象中有以下声明:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX")
private ZonedDateTime start;

当我解析诸如 2016-12-08T12:16:07.124Z 之类的时间戳(使用 Jackson Json De-serilaizer)时,它工作正常,但是一旦我收到时间戳没有毫秒(例如“2016 -12-08T12:16:07Z"),它会抛出异常。

我怎样才能在格式规范中使毫秒成为可选?

【问题讨论】:

    标签: java json jackson deserialization iso8601


    【解决方案1】:

    如果毫秒由 1 位或 2 位或 3 位数字组成,您可以使用此模式

    JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS][.SS][.S]X")
    

    可选部分顺序严格

    【讨论】:

      【解决方案2】:

      对于那些无法让[.SSS] 解决方案发挥作用的人,这就是我最终要做的。

      保留字段上的@JsonFormat 注释以进行序列化,但构建自定义反序列化器以解析可能未指定毫秒部分的日期。实现反序列化器后,您必须将其注册为 ObjectMapperSimpleModule

      class DateDeserializer extends StdDeserializer<Date> {
      
          private static final SimpleDateFormat withMillis = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
          private static final SimpleDateFormat withoutMillis = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
      
          public DateDeserializer() {
              this(null);
          }
      
          public DateDeserializer(Class<?> vc) {
              super(vc);
          }
      
          @Override
          public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
              String dateString = p.getText();
              if (dateString.isEmpty()) {
                  //handle empty strings however you want,
                  //but I am setting the Date objects null
                  return null;
              }
      
              try {
                  return withMillis.parse(dateString);
              } catch (ParseException e) {
                  try {
                      return withoutMillis.parse(dateString);
                  } catch (ParseException e1) {
                      throw new RuntimeException("Unable to parse date", e1);
                  }
              }
          }
      }
      

      现在您有了一个自定义反序列化器,剩下的就是注册它。我正在使用我的项目中已经拥有的 ContextResolver&lt;ObjectMapper&gt; 这样做,但是您使用 ObjectMapper 应该没问题。

      @Provider
      class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
      
          private final ObjectMapper mapper;
      
          public ObjectMapperContextResolver() {
              mapper = new ObjectMapper();
              SimpleModule dateModule = new SimpleModule();
              dateModule.addDeserializer(Date.class, new DateDeserializer());
              mapper.registerModule(dateModule);
          }
      
          @Override
          public ObjectMapper getContext(Class<?> type) {
              return mapper;
          }
      }
      

      【讨论】:

      • 关于如何在 JEE 应用程序中注册自定义 ObjectMapper 的非常有用的信息。
      【解决方案3】:

      如果您使用的是 Java 8,请尝试在方括号 [.SSS] 内指定 .SSS

      JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]X")
      

      【讨论】:

      • 成功了!谢谢!
      • 不适用于 Java 8 版本 102。JavaDoc 中也没有提到括号:docs.oracle.com/javase/8/docs/api/java/text/…
      • [.SSS] 仅适用于 3 位毫秒值。如果它是一位数或两位数,它会中断。例如。 2019-03-24T16:14:08.23 将需要 "yyyy-MM-dd'T'HH:mm:ss[.SS] 模式
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      • 1970-01-01
      • 2014-08-22
      • 2016-08-09
      • 2022-08-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多