【问题标题】:Efficient way to have Jackson serialize Java 8 Instant as epoch milliseconds?让杰克逊将 Java 8 Instant 序列化为纪元毫秒的有效方法?
【发布时间】:2016-10-26 06:26:34
【问题描述】:

使用 Spring RestControllers 和 Jackson JSON 解析后端,前端使用 AngularJS。我正在寻找一种有效的方法让杰克逊将 Instant 序列化为纪元毫秒,以便随后方便地使用 JavaScript 代码。 (在浏览器端,我希望通过 Angular 的 Date Filter: {{myInstantVal | date:'short' }} 为我提供所需的日期格式。)

在 Java 方面,Jackson 将使用的 getter 很简单:

public Instant getMyInstantVal() { return myInstantVal; }

序列化不会按原样工作,因为jackson-datatype-jsr310 默认情况下不会为 Instant 返回 Epoch 毫秒。我考虑将 @JsonFormat 添加到上面的 getter 以将 Instant 变成前端可以使用的东西,但它存在两个问题:(1)我可以提供的模式显然仅限于 SimpleDateFormat 不提供一个“纪元毫秒”选项,以及 (2) 当我尝试将 Instant 作为格式化日期发送到浏览器时,Jackson 抛出异常,因为 @JsonFormat 注释需要 Instant 的 TimeZone 属性,这是我不希望的硬编码,因为它会因用户而异。

到目前为止,我的解决方案(并且工作正常)是使用@JsonGetter 创建一个替换getter,这导致Jackson 使用此方法来序列化myInstantVal

@JsonGetter("myInstantVal")
public long getMyInstantValEpoch() {
    return myInstantVal.toEpochMilli();
}

这是正确的做法吗?或者是否有一个很好的注释我可以放在 getMyInstantVal() 上,这样我就不必创建这些额外的方法?

【问题讨论】:

    标签: json spring jackson java-time


    【解决方案1】:

    您只需要阅读您链接到的自述文件。强调我的:

    如果启用了 SerializationFeature#WRITE_DATES_AS_TIMESTAMPS 功能,则大多数 JSR-310 类型都被序列化为数字(整数或小数),否则以标准 ISO-8601 字符串表示形式序列化。

    [...]

    时间戳的粒度通过伴随功能 SerializationFeature#WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS 和 DeserializationFeature#READ_DATE_TIMESTAMPS_AS_NANOSECONDS 控制。对于序列化,时间戳写为小数(小数),其中数字是秒,小数是小数秒,如果启用了 WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS(默认情况下),分辨率可以达到纳秒,具体取决于底层 JDK 实现。 如果禁用 WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS,则时间戳将写入整数毫秒。

    【讨论】:

    • 我不确定如何在我正在使用的 Spring XML 配置中设置该值,我正在使用 Spring RestControllers 以及它使用的任何默认 Jackson 配置。进一步研究...
    • docs.spring.io/spring/docs/current/javadoc-api/org/…。但我真的会避免 XML 配置。 Java 配置要好得多。
    • 另外两个人怎么样了? :-)
    • 也适用于使用spring-boot 的用户:您可以使用spring.jackson.* 前缀从application.properties 文件中设置任何杰克逊功能。例如,WRITE_DATES_AS_TIMESTAMPS 序列化功能可以使用spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=true 行启用。查看更多:Appendix A. Common application properties.
    • 在我看来,这是一个糟糕的解决方案。它会影响您使用 ObjectMapper 的所有其他 Instant 字段,如果您使用不同的 ObjectMapper(例如在单元测试中),它将不会生效。
    【解决方案2】:

    添加到 JB 的答案中,覆盖 Spring MVC 的默认 JSON 解析器以从 Instant(以及其他拥有它们的 Java 8 日期对象)中去除纳秒:

    1. 在 mvc:annotation-driven 元素中,指定您将覆盖默认的 JSON 消息转换器:

      <mvc:annotation-driven validator="beanValidator"> <mvc:message-converters register-defaults="true"> <beans:ref bean="jsonConverter"/> </mvc:message-converters> </mvc:annotation-driven>

    (默认情况下,上面的 register-defaults 是 true,很可能您希望保持 Spring 配置的其他转换器原样)。

    1. 覆盖 MappingJackson2HttpMessageConverter 如下:

      <beans:bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
      <beans:property name="objectMapper">
          <beans:bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
              <beans:property name="featuresToDisable">
                  <beans:array>
                      <util:constant static-field="com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS"/>
                  </beans:array>
              </beans:property>
          </beans:bean>
      </beans:property>
      

    第 1 步很重要,否则 Spring MVC 将忽略配置的 MJ2HMC 对象,而使用它自己的默认对象。

    部分 H/T this SO 帖子。

    【讨论】:

    【解决方案3】:

    在 Instant 属性的 JSON 响应中返回 epoch millis 的简单方法如下:

    @JsonFormat(shape = JsonFormat.Shape.NUMBER, timezone = "UTC")
    private Instant createdAt;
    

    这将导致以下响应:

    {
      ...
      "createdAt": 1534923249,
      ...
    }
    

    【讨论】:

    • 这对我不起作用。 @JsonFormat 注释似乎被忽略了。
    • @ShadowMan @JsonFormat 注释是否适用于同一类的其他属性?如果没有,请检查您的映射器是否没有注册任何自定义序列化程序。
    • fwiw 在 Instant 变量上的这两个注释:@JsonFormat(shape = JsonFormat.Shape.NUMBER_INT, timezone = "UTC")@JsonFormat(shape = JsonFormat.Shape.NUMBER, timezone = "UTC") 导致我遇到这种不幸的格式:1596745072.206033000
    • 这里的时区有什么意义?纪元总是从 1970 年 1 月 1 日 00:00 UTC 开始。
    • @ShadowMan 你解决了吗?我也仍然得到默认的 epoch+nanos 对象。
    猜你喜欢
    • 2019-10-03
    • 2017-11-09
    • 1970-01-01
    • 1970-01-01
    • 2013-11-11
    • 1970-01-01
    • 2016-07-21
    • 2019-10-14
    • 2014-06-22
    相关资源
    最近更新 更多