必须显式配置 Jackson2JsonRedisSerializer 并注册 JavaTimeModule,否则 LocalDateTime 反序列化会因 Jackson 缺失时间模块而失败,抛出 Cannot construct instance 异常。

必须显式配置 Jackson2JsonRedisSerializer 并注册 JavaTimeModule,否则默认反序列化会失败。
为什么 Redis 取出 LocalDateTime 会报 Cannot construct instance of java.time.LocalDateTime
Spring Boot 的 RedisTemplate 默认使用 JdkSerializationRedisSerializer,但一旦你换成 JSON 序列化(比如为了可读性或跨语言兼容),Jackson 就必须能识别 LocalDateTime。而 Jackson 默认不支持 Java 8 时间类型——它看到 {"year":2023,"month":"JANUARY",...} 这种对象结构时,根本不知道怎么拼成一个 LocalDateTime 实例,于是抛出 InvalidDefinitionException。
这不是 Redis 或 Spring Data Redis 的 bug,是 Jackson 模块缺失的典型表现。
- 错误日志里一定包含
no Creators, like default constructor, exist - 即使你存的时候用了
@JsonFormat,取的时候没配模块照样失败 -
GenericJackson2JsonRedisSerializer也不能自动解决,它只提供泛型包装,不自带JavaTimeModule
如何正确配置 Jackson2JsonRedisSerializer
核心是两件事:用对序列化器类 + 注入带 JavaTimeModule 的 ObjectMapper。
推荐写法(Spring Boot 2.6+ / 3.x):
@Bean
public RedisTemplate<string object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<string object> template = new RedisTemplate();
template.setConnectionFactory(factory);
// key 用 String 序列化器
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// value 用 Jackson,并手动注入支持 LocalDateTime 的 ObjectMapper
Jackson2JsonRedisSerializer<object> serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule()); // 关键!必须注册
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 防止输出毫秒数
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}</object></string></string>
- 别直接 new
ObjectMapper()后不注册模块——这是最常见漏点 -
WRITE_DATES_AS_TIMESTAMPS必须关掉,否则LocalDateTime会被序列化成数字数组 - 如果项目已用
@ConfigurationProperties配置了全局ObjectMapper,要确认它是否也注册了JavaTimeModule,否则这里会覆盖失效
遇到 UnrecognizedPropertyException 怎么办?
这通常不是时间类型问题,而是字段不匹配引发的“连带故障”。比如缓存里存的是旧版 DTO(无 remark 字段),升级后新代码的 DTO 加了该字段,但反序列化时 Jackson 默认拒绝未知字段。
修复方式(加在上面的 ObjectMapper 初始化之后):
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- 这个配置和
JavaTimeModule是正交的,必须同时存在才能既支持时间类型又容忍字段变化 - 不要用
GenericJackson2JsonRedisSerializer代替——它底层也是靠ObjectMapper,同样需要模块注册 - 如果用
@Cacheable注解,确保其使用的CacheManager也指向这个自定义RedisTemplate,否则注解走的还是默认序列化路径
最容易被忽略的是:JavaTimeModule 必须在 ObjectMapper 实例化后立即注册,且不能被其他配置覆盖;另外,不同环境(dev/test/prod)的依赖树里若混入多个 Jackson 版本,JavaTimeModule 可能加载失败而不报错,只默默退化为默认行为。











