首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ZonedDateTimeDeserializer在杰克逊jsr310失踪了

ZonedDateTimeDeserializer在杰克逊jsr310失踪了
EN

Stack Overflow用户
提问于 2017-07-20 11:42:03
回答 2查看 5.9K关注 0票数 9

我使用这样的方法解析一个ZonedDateTime

代码语言:javascript
复制
 @JsonSerialize(using = ZonedDateTimeSerializer.class)
 private ZonedDateTime expirationDateTime;

我需要正确的反序列化这个日期。但是,杰克逊没有为此提供反序列化器:

代码语言:javascript
复制
com.fasterxml.jackson.datatype.jsr310.deser

它失踪有什么原因吗?最常见的解决办法是什么?

更新的:下面是我的场景:

我创建这样的ZonedDateTime

代码语言:javascript
复制
ZonedDateTime.of(2017, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC)

然后序列化包含日期的对象,如下所示:

代码语言:javascript
复制
public static String toJSON(Object o) {
    ObjectMapper objectMapper = new ObjectMapper();
    StringWriter sWriter = new StringWriter();
    try {
        JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(sWriter);
        objectMapper.writeValue(jsonGenerator, o);
        return sWriter.toString();
    } catch (IOException e) {
        throw new IllegalStateException(e);
    }
}

当我试图将它发送到Spring控制器时:

代码语言:javascript
复制
    mockMvc.perform(post("/endpoint/")
            .content(toJSON(myObject))
            .contentType(APPLICATION_JSON))
            .andExpect(status().isOk());

控制器内部的date对象是不同的。

以前:2017-01-01T01:01:01.000000001Z

后:2017-01-01T01:01:01.000000001Z[UTC]

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-20 13:00:34

两个值2017-01-01T01:01:01.000000001Z2017-01-01T01:01:01.000000001Z[UTC]实际上表示相同的瞬间,因此它们是等价的,可以在没有问题的情况下使用(至少不应该是问题,因为它们代表相同的瞬间)。

唯一的细节是,由于某种原因,Jackson在反序列化时将ZoneId值设置为"UTC“,这在本例中是多余的( Z已经告诉偏移量为"UTC")。但它不应影响日期值本身。

摆脱这个[UTC]部件的一个非常简单的方法是将这个对象转换为OffsetDateTime (因此它保留Z偏移量,而不使用[UTC]区域),然后再返回到ZonedDateTime

代码语言:javascript
复制
ZonedDateTime z = // object with 2017-01-01T01:01:01.000000001Z[UTC] value
z = z.toOffsetDateTime().toZonedDateTime();
System.out.println(z); // 2017-01-01T01:01:01.000000001Z

之后,z变量的值将是2017-01-01T01:01:01.000000001Z (没有[UTC]部分)。

但是,当然,这并不理想,因为您必须手动完成所有日期。更好的方法是编写自定义反序列化器(通过扩展com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer),在时区为UTC时不设置时区

代码语言:javascript
复制
public class CustomZonedDateTimeDeserializer extends InstantDeserializer<ZonedDateTime> {
    public CustomZonedDateTimeDeserializer() {
        // most parameters are the same used by InstantDeserializer
        super(ZonedDateTime.class,
              DateTimeFormatter.ISO_ZONED_DATE_TIME,
              ZonedDateTime::from,
              // when zone id is "UTC", use the ZoneOffset.UTC constant instead of the zoneId object
              a -> ZonedDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId.getId().equals("UTC") ? ZoneOffset.UTC : a.zoneId),
              // when zone id is "UTC", use the ZoneOffset.UTC constant instead of the zoneId object
              a -> ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId.getId().equals("UTC") ? ZoneOffset.UTC : a.zoneId),
              // the same is equals to InstantDeserializer
              ZonedDateTime::withZoneSameInstant, false);
    }
}

然后您必须注册这个反序列化器。如果使用ObjectMapper,则需要将其添加到JavaTimeModule

代码语言:javascript
复制
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
// add my custom deserializer (this will affect all ZonedDateTime deserialization)
module.addDeserializer(ZonedDateTime.class, new CustomZonedDateTimeDeserializer());
objectMapper.registerModule(module);

如果在Spring中配置它,配置将类似于这样(没有测试):

代码语言:javascript
复制
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" id="pnxObjectMapper">
    <property name="deserializersByType">
        <map key-type="java.lang.Class">
            <entry>
                <key>
                    <value>java.time.ZonedDateTime</value>
                </key>
                <bean class="your.app.CustomZonedDateTimeDeserializer">
                </bean>
            </entry>
        </map>
    </property>
</bean>
票数 3
EN

Stack Overflow用户

发布于 2019-04-11 13:58:15

我用这个:

代码语言:javascript
复制
        JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(DateTimeFormatter.ISO_DATE_TIME));
    javaTimeModule.addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45213696

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档