Spring+Redis项目序列化java.time.Instant报错求助
Spring+Redis项目中Java 8 Instant序列化失败问题
问题复现步骤
- 项目搭建
- 使用IntelliJ IDEA 2023.1.4旗舰版创建Spring Initializr项目
- 选择Java语言、Gradle-Kotlin构建方式,Spring Boot版本为3.1.4
- 添加依赖:Lombok、Spring Web、Spring Data Redis(Access+Driver)
- 应用配置:在
src/main/resources/application.properties中添加Redis连接信息
(本地Redis容器运行正常,已验证6379端口可访问)spring.data.redis.host=localhost spring.data.redis.port=6379 - 自定义数据类
MyObjectpackage com.example.demo; import lombok.Data; import java.time.Instant; @Data public class MyObject { Instant timestamp; String textPayload; } - 配置类
AppConfigpackage com.example.demo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class AppConfig { @Bean public RedisTemplate<String, MyObject> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, MyObject> template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } } - 控制器
MyControllerpackage com.example.demo; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.time.Instant; @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @RequiredArgsConstructor @RestController public class MyController { RedisTemplate<String, MyObject> redisTemplate; @GetMapping("/save") public ResponseEntity<String> saveObject() { MyObject myObject = new MyObject(); myObject.setTimestamp(Instant.now()); myObject.setTextPayload("some data"); redisTemplate.opsForValue().set("myObject", myObject); return ResponseEntity.ok("Object saved"); } @GetMapping("/read") public ResponseEntity<MyObject> readObject() { return ResponseEntity.ok(redisTemplate.opsForValue().get("myObject")); } }
异常信息
调用/save接口时抛出以下异常:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.Instant` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.example.demo.MyObject["timestamp"]) ...(省略堆栈信息)
已尝试的无效方案
- 添加
jackson-datatype-jsr310依赖到build.gradle.ktsimplementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") - 在配置类中注册
ObjectMapperBean(两种写法)@Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); return objectMapper; }@Bean public ObjectMapper objectMapper() { return JsonMapper.builder() .addModule(new JavaTimeModule()) .build(); } - 注册
Jackson2ObjectMapperBuilderBean@Bean public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() { return new Jackson2ObjectMapperBuilder().modules(new JavaTimeModule()); }
正确解决方案
问题核心在于GenericJackson2JsonRedisSerializer默认会自行创建独立的ObjectMapper实例,不会自动复用Spring容器中配置好的ObjectMapper。需要手动创建注册了JavaTimeModule的ObjectMapper,并传递给GenericJackson2JsonRedisSerializer。
修改AppConfig中的redisTemplate Bean:
@Configuration public class AppConfig { @Bean public RedisTemplate<String, MyObject> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, MyObject> template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); // 手动配置ObjectMapper并注册JavaTimeModule ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); // 可选:关闭日期时间的时间戳序列化,转为ISO格式字符串 objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); template.setValueSerializer(new GenericJackson2JsonRedisSerializer(objectMapper)); return template; } }
另外,Spring Boot 3.x中jackson-datatype-jsr310已被包含在spring-boot-starter-json依赖中(Spring Web会间接引入),因此无需额外添加该依赖,之前添加的可以移除。
内容的提问来源于stack exchange,提问作者overwriter
相关产品推荐
相关产品推荐

