Jackson jsr310中缺少ZonedDateTimeDeserializer [英] ZonedDateTimeDeserializer is missing in jackson jsr310

查看:2281
本文介绍了Jackson jsr310中缺少ZonedDateTimeDeserializer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下方式解析 ZonedDateTime

I'm parsing a ZonedDateTime using like this:

 @JsonSerialize(using = ZonedDateTimeSerializer.class)
 private ZonedDateTime expirationDateTime;

我需要能够正确反序列化此日期。但是,jackson没有提供解串器:

I need to be able to properly deserialize this date. However, there is no deserializer for this that is provided by jackson:

com.fasterxml.jackson.datatype.jsr310.deser

有没有理由错过它?什么是最常见的解决方法?

Is there a reason why it's missing? What is the most common workaround?

更新
这是我的方案:

Updated: Here is my scenario:

我创建 ZonedDateTime 像这样:

ZonedDateTime.of(2017, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC)

然后我序列化包含这样的日期:

Then I serialize the object that contains the date like this:

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 MVC Controller时:

And when I try to send it to Spring MVC Controller:

    mockMvc.perform(post("/endpoint/")
            .content(toJSON(myObject))
            .contentType(APPLICATION_JSON))
            .andExpect(status().isOk());

进入控制器内部的日期对象是不同的。

The date object that goes inside the controller is different.

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

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

推荐答案

2个值 2017-01-01T01:01:01.000000001Z 2017-01-01T01:01:01.000000001 Z [UTC] 实际上代表相同的瞬间,因此它们是等效的,可以毫无问题地使用(至少应该没有问题,因为它们代表同一时刻) 。

The 2 values 2017-01-01T01:01:01.000000001Z and 2017-01-01T01:01:01.000000001Z[UTC] actually represent the same instant, so they are equivalent and can be used without a problem (at least there should be no problems as they represent the same instant).

唯一的细节是杰克逊出于某种原因,在反序列化时将 ZoneId 值设置为UTC ,在这种情况下是多余的( Z 已经告诉偏移是UTC)。但它不应该影响日期值本身。

The only detail is that Jackson, for some reason, sets the ZoneId value to "UTC" when deserializing, which is redundant in this case (the Z already tells that the offset is "UTC"). But it shouldn't affect the date value itself.

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

A very simple way to get rid of this [UTC] part is to convert this object to OffsetDateTime (so it keeps the Z offset and don't use the [UTC] zone) and then back again to ZonedDateTime:

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

之后,<$ c的值$ c> z 变量将 2017-01-01T01:01:01.000000001Z (不含 [UTC] part)。

After that, the value of z variable will be 2017-01-01T01:01:01.000000001Z (without the [UTC] part).

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

But of course this is not ideal as you'd have to do it manually for all dates. A better approach is to write a custom deserializer (by extending com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer) that don't set the timezone when it's UTC:

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

Then you have to register this deserializer. If you use ObjectMapper, you need to add this to the JavaTimeModule:

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中配置它,配置将是这样的(未测试):

If you configure it in Spring, the config will be something like this (not tested):

<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>

这篇关于Jackson jsr310中缺少ZonedDateTimeDeserializer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆