当前位置: 首页 > news >正文

Jackson 序列化:Cannot deserialize value of type `java.time.LocalDateTime`

问题描述

使用 jackson 反序列化异常如下:

Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.time.LocalDateTime from String “2023-02-13 19:43:01”: Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text ‘2023-02-13 19:43:01’ could not be parsed at index 10
at [Source: (String)“{“code”:0,“message”:“OK”,“request_id”:“20230214155816454DFD3C7EAE510F39CE”,“data”:{“list”:[{“creative_create_time”:“2023-02-13 19:43:01”,“creative_id”:1757715969881150,“creative_modify_time”:“2023-02-13 19:43:02”}],“page_info”:{“page”:1,“page_size”:1,“total_number”:411,“total_page”:411}}}”; line: 1, column: 116] (through reference chain: com.xxx.core.domain.vo.AdResultVO[“data”]->com.xxx.core.domain.vo.AdDataVO[“list”]->java.util.ArrayList[0]->com.xxx.core.domain.vo.AdCreativityDetailsVO[“creative_create_time”])

LocalDateTime 类型的 creative_modify_time 字段反序列化失败,一看到日期字段序列化你可能就头疼了!大概率是 Jackson 配置上的问题。


原因分析:

项目使用 Springboot 技术框架,并使用 Jackson 做序列化工具。

那这里导致问题的原因是因为通常时间序列化成字符串的时候都是 yyyy-MM-dd HH:mm:ss

但是 Jackson 默认的序列化格式是国际化的时间标准格式:yyyy-MM-ddTHH:mm:ss,区别就在于中间多了个 T

我们找找源头,使用了 LocalTimeDeserializer 反序列化器:

在这里插入图片描述

我们继续看看实际的格式:

在这里插入图片描述

综上,对于这种 2023-02-13 19:43:01 字符串想要反序列化成 LocalDateTime 类型,需要我们自定义我们需要的 DateTimeFormatter


解决方案:

在 Spring 体系下,已经对 Jackson 做了很好的一层包装,也预留了口子,让我们能够很轻易的自定义序列化格式。

我们要做的就是在 Jackson2ObjectMapperBuilderCustomizer 中自定义配置,然后将其装配为 Bean,如下:

@Configuration
class LocalDateTimeSerializerConfig {
    @Value("\${spring.jackson.date-time-format:yyyy-MM-dd HH:mm:ss}")
    private val datetimepattern: String? = null

    fun localDateTimeSerializer(): LocalDateTimeSerializer {
        return LocalDateTimeSerializer(DateTimeFormatter.ofPattern(datetimepattern))
    }
    fun localDateTimeDeserializer():LocalDateTimeDeserializer{
        return LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(datetimepattern))
    }

    @Bean
    fun jackson2ObjectMapperBuilderCustomizer(): Jackson2ObjectMapperBuilderCustomizer {
        return Jackson2ObjectMapperBuilderCustomizer { builder: Jackson2ObjectMapperBuilder ->
            builder.serializerByType(LocalDateTime::class.java, localDateTimeSerializer())
            builder.deserializerByType(LocalDateTime::class.java,localDateTimeDeserializer())
        }
    }

}

这样就可以了,后面的配置就是 SpringBoot 自动将配置装配到我们的 ObjectMapper 对象中。

当然,依葫芦画瓢,你还可以自定义 LocalDate、LocalTime … 等自定义序列化配置 …

原理探索:

日期时间:

JSR310 规定了「日期时间」处理的新标准,并在 jdk1.8 的版本中进行了实现,其中你熟悉的 LocalDateTime、LocalDate 等就是 JSR310 标准的实现类。

Jackson 工具在进行「日期时间」序列化/反序列化的时候也采用 jdk1.8 中 JSR310 标准实现来处理。

不过 Jackson 单独罗列一个模块来粘合「Jackson 和 jdk1.8 的 JSR310 实现」,这个模块名就叫做 jackson-datatype-jsr310,你的项目里应该能看到这个包的引入。

Jackson 在全世界范围内流行,Spring 也将其作为默认的序列化框架,来对请求中的参数做 序列化和反序列化 行为。

当然,实际情况下,你应该也经常使用 Jackson, 尤其是 日期时间 类参数有着特殊的序列化需求,大部分工作 Spring 都帮你做了,你只需要添加你的个性化序列化方式即可(参数配置、Bean 实例等)

Jackson:

你应该也猜到了,Spring 这个中间者,会帮你初始化 ObjectMapper 实例,同时还会预留一个口子,方便你自定义配置。

其中关键的类是 Jackson2ObjectMapperBuilder,从名字应该也看出来了,该类专门用于构建 ObjectMapper。

熟悉 SpringBoot 的你应该知道,约定大于配置,所以,我们继续找到 自动装载 Bean 的类:JacksonAutoConfiguration

注意到其中 Jackson2ObjectMapperBuilder 装载的方法:

@Bean
@Scope("prototype")
@ConditionalOnMissingBean
Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(ApplicationContext applicationContext,
		List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
	Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
	builder.applicationContext(applicationContext);
	customize(builder, customizers);
	return builder;
}

我们再看需要的 参数 List<Jackson2ObjectMapperBuilderCustomizer.>,换句话说,Jackson2ObjectMapperBuilderCustomizer 就是给我们留的口子,我们实现它来达到自定义配置的目的。




相关参考:

  1. JSR310 标准
  2. JSRs: Java Specification Requests/JSR 310: Date and Time API

相关文章:

  • 自抗扰控制ADRC之微分器TD
  • Python 自己简单地造一个轮子.whl文件
  • C# 数据结构
  • 数据分析| Pandas200道练习题,使用Pandas连接MySQL数据库
  • 【函数栈帧的创建和销毁】 -- 神仙级别底层原理,你学会了吗?
  • Generated columns cannot be used in COPY
  • 2023年美赛C题 预测Wordle结果Predicting Wordle Results这题太简单了吧
  • 测试开发之Django实战示例 第十二章 创建API
  • Python 之 Matplotlib xticks 的再次说明、图形样式和子图
  • 2023美赛F题:绿色经济
  • 基于蜣螂算法改进的LSTM分类算法-附代码
  • 数字化系统使用率低的原因剖析
  • 【python百炼成魔】python之列表详解
  • ChatGPT国内镜像站初体验:聊天、Python代码生成等
  • K8s常见面试题总结
  • [TPAMI‘21] Heatmap Regression via Randomized Rounding
  • 【VictoriaMetrics】VictoriaMetrics集群伪分布式部署(二进制版)
  • springcloud+nacos+gateway案例
  • CSS 圆角边框 盒子阴影 文字阴影
  • 全志H3系统移植 | 移植主线最新uboot 2023.04和kernel 6.1.11到Nanopi NEO开发板
  • 智慧菜场团标试验:标准化的同时还能保留个性化吗?
  • 西安旅游:2024年营业收入约5.82亿元,同比增长5.88%
  • 老人在健身中心晕倒获AED急救,上海检察机关为何被感谢?
  • 北京一季度GDP为12159.9亿元,同比增长5.5%
  • 译者手记|如何量化家庭历史
  • 台积电一季度净利增长六成,预计今年AI芯片营收增长一倍