OffsetDateTime序列化与反序列化结果不一致原因及解决方案咨询
问题根因
- Jackson默认时区转换逻辑:Jackson默认开启了
DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE配置,反序列化日期时会自动将时间调整到Jackson上下文配置的时区(Spring Boot默认上下文时区为UTC,标识为Z)。你接口返回的原始值2021-10-21T23:59:59.999999999-18:00转换为UTC时间后刚好是2021-10-22T17:59:59.999999999Z,所以日期会跨天、时区标识变成Z。 - OffsetDateTime的equals规则:
OffsetDateTime的equals方法不仅会比较时间对应的瞬时点,还会严格比较时区偏移量,即使两个对象代表同一个全球瞬时时间,只要偏移量不同,equals就会返回false。你构造预期对象时用LocalDate.atTime(OffsetTime.MAX)得到的偏移量是-18:00,和反序列化得到的UTC偏移量+00:00不一致,所以校验失败。
修复方案
可根据业务需求选择任意一种方案:
- 方案1:关闭Jackson自动时区调整(保留原始偏移量)
在你现有的Jackson2ObjectMapperBuilderCustomizer配置中添加禁用自动时区调整的配置:
@Bean public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer(CustomAnnotationIntrospector customAnnotationIntrospector) { return builder -> builder.serializationInclusion(NON_NULL) .annotationIntrospector(customAnnotationIntrospector) // 新增下面这行,关闭反序列化自动调整到上下文时区 .featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE); }
改完后反序列化会保留原始响应里的-18:00偏移量,和你构造的预期对象完全一致,equals校验即可通过。
- 方案2:统一使用UTC时区(业务需要统一时区的场景)
构造预期对象时将时间转换为UTC时区的OffsetDateTime,和反序列化后的时区保持一致:
private Request getExpectedRequest() { LocalDate date = LocalDate.of(2021, Month.OCTOBER, 22); OffsetDateTime dateTime = date.atTime(OffsetTime.MAX) // 转换为同一瞬时的UTC时间 .atZoneSameInstant(ZoneOffset.UTC) .toOffsetDateTime(); return new Request(dateTime); }
- 方案3:仅校验瞬时时间是否一致(不关心偏移量的场景)
不要直接比较整个Request对象,单独比较日期的瞬时时间点:
// 把原来的assertEquals替换成下面的逻辑 Request actual = mapToObject(result.getResponse().getContentAsString(StandardCharsets.UTF_8), Request.class); Request expected = getExpectedRequest(); Assertions.assertEquals(expected.getDate().toInstant(), actual.getDate().toInstant()); // 其他字段正常校验...
内容的提问来源于stack exchange,提问作者Zhenyria
相关产品推荐
相关产品推荐

