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

使用JCache API的Redisson反序列化仅返回String引发类型转换异常

JCache + Redisson 存储LocalDateTime 反序列化异常解决方案

嘿,我来帮你分析下这个问题——你遇到的ClassCastException本质是Redisson在反序列化时,没能正确识别Redis中存储的字符串应该转换为LocalDateTime类型,下面拆解原因和解决办法:

问题回顾

你用JCache(JSR-107)结合Redisson存储<String, LocalDateTime>键值对,存储时Jackson能把LocalDateTime序列化成2018-01-23T11:59:34.997834这样的字符串,但调用cache.get()时却抛出类型转换异常,因为返回的是String而非预期的LocalDateTime。

你的核心代码如下:

测试代码

@Test 
public void getCacheInline() { 
    Config redissonCfg = new Config(); 
    redissonCfg 
        .setCodec(new JsonJacksonCodec(buildObjectMapper())) 
        .useSingleServer() 
        .setAddress("redis://redis:6379"); 

    MutableConfiguration<String, LocalDateTime> jcacheConfig = new MutableConfiguration<String, LocalDateTime>() 
        .setTypes(String.class, LocalDateTime.class) 
        .setExpiryPolicyFactory((Factory<ExpiryPolicy>) () -> new CreatedExpiryPolicy(new Duration(SECONDS, 100))); 

    Configuration<String, LocalDateTime> configuration = RedissonConfiguration.fromConfig(redissonCfg, jcacheConfig); 
    Cache<String, LocalDateTime> cache = cacheManager.createCache(CACHE_NAME, configuration); 

    LocalDateTime expectedDateTime = LocalDateTime.now(); 
    cache.put("testKey", expectedDateTime); 
    // 抛出异常:java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.time.LocalDateTime 
    LocalDateTime actualDateTime = cache.get("testKey"); 
    assertThat(actualDateTime, is(equalTo(expectedDateTime))); 
}

ObjectMapper构建代码

private ObjectMapper buildObjectMapper() { 
    ObjectMapper objectMapper = new ObjectMapper(); 
    objectMapper.registerModule(new JavaTimeModule()); 
    objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false); 
    objectMapper.configure(WRITE_DATES_AS_TIMESTAMPS, false); 
    objectMapper.configure(READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false); 
    objectMapper.setSerializationInclusion(NON_NULL); 
    return objectMapper; 
}

核心原因

问题出在两个地方:

  1. 缺少类型元数据:你配置的JsonJacksonCodec是通用的,序列化时只存储了LocalDateTime的字符串内容,没有附带类型信息,导致Jackson反序列化时不知道要转换成LocalDateTime,只能返回原始字符串。
  2. JCache类型声明未被有效利用:虽然你在MutableConfiguration中调用了setTypes声明了键值类型,但Redisson的JCache实现需要Codec层面的配合才能把这些类型信息用于反序列化。

两种解决方案

方案一:给ObjectMapper添加类型信息支持

通过开启Jackson的默认类型序列化,让Redis中存储的JSON附带类型元数据,这样反序列化时就能明确目标类型:

修改你的buildObjectMapper()方法:

private ObjectMapper buildObjectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new JavaTimeModule());
    objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.configure(WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.configure(READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
    objectMapper.setSerializationInclusion(NON_NULL);
    
    // 新增:开启类型信息存储,告诉Jackson反序列化时的目标类型
    objectMapper.activateDefaultTyping(
        LaissezFaireSubTypeValidator.instance,
        ObjectMapper.DefaultTyping.ALL,
        JsonTypeInfo.As.PROPERTY
    );
    return objectMapper;
}

方案二:使用指定键值类型的JsonJacksonCodec

如果不想全局开启类型信息,可以直接在创建JsonJacksonCodec时指定键和值的具体类型,让Redisson明确知道反序列化的目标类型:

修改你的Redisson配置部分:

@Test 
public void getCacheInline() { 
    Config redissonCfg = new Config(); 
    
    // 构建指定类型的Codec
    JsonJacksonCodec codec = new JsonJacksonCodec(String.class, LocalDateTime.class, buildObjectMapper());
    redissonCfg.setCodec(codec)
               .useSingleServer()
               .setAddress("redis://redis:6379"); 

    MutableConfiguration<String, LocalDateTime> jcacheConfig = new MutableConfiguration<String, LocalDateTime>() 
        .setTypes(String.class, LocalDateTime.class) 
        .setExpiryPolicyFactory((Factory<ExpiryPolicy>) () -> new CreatedExpiryPolicy(new Duration(SECONDS, 100))); 

    Configuration<String, LocalDateTime> configuration = RedissonConfiguration.fromConfig(redissonCfg, jcacheConfig); 
    Cache<String, LocalDateTime> cache = cacheManager.createCache(CACHE_NAME, configuration); 

    LocalDateTime expectedDateTime = LocalDateTime.now(); 
    cache.put("testKey", expectedDateTime); 
    
    // 现在可以正确获取LocalDateTime
    LocalDateTime actualDateTime = cache.get("testKey"); 
    assertThat(actualDateTime, is(equalTo(expectedDateTime))); 
}

这个方案更适合缓存类型固定的场景,不需要修改全局的ObjectMapper配置。

额外优化建议

你还可以在JCache配置中显式指定Codec属性,确保优先级最高:

jcacheConfig.setAttribute(RedissonConfiguration.REDISSON_CODEC_ATTRIBUTE, codec);

这样可以避免其他默认配置覆盖你的Codec设置。

内容的提问来源于stack exchange,提问作者Pedro R.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:13:30