You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring+Redis项目序列化java.time.Instant报错求助

Spring+Redis项目中Java 8 Instant序列化失败问题

问题复现步骤

  • 项目搭建
    1. 使用IntelliJ IDEA 2023.1.4旗舰版创建Spring Initializr项目
    2. 选择Java语言、Gradle-Kotlin构建方式,Spring Boot版本为3.1.4
    3. 添加依赖:Lombok、Spring Web、Spring Data Redis(Access+Driver)
  • 应用配置:在src/main/resources/application.properties中添加Redis连接信息
    spring.data.redis.host=localhost
    spring.data.redis.port=6379
    
    (本地Redis容器运行正常,已验证6379端口可访问)
  • 自定义数据类MyObject
    package com.example.demo;
    
    import lombok.Data;
    import java.time.Instant;
    
    @Data
    public class MyObject {
        Instant timestamp;
        String textPayload;
    }
    
  • 配置类AppConfig
    package 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;
        }
    }
    
  • 控制器MyController
    package 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.kts
    implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
    
  • 在配置类中注册ObjectMapper Bean(两种写法)
    @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();
    }
    
  • 注册Jackson2ObjectMapperBuilder Bean
    @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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 00:46:07