[英]Spring-data-redis @Cacheable java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyObject
I am using spring-data-redis for caching data in my spring boot app.我正在使用 spring-data-redis 在我的 spring boot 应用程序中缓存数据。 I am using Mongo as my primary data source and Redis as a cache.我使用 Mongo 作为我的主要数据源,使用 Redis 作为缓存。 When I hit the API for the first time, it fetches record from Mongo and saves it in Cache, and returns MyObject correctly to the client.当我第一次访问 API 时,它从 Mongo 获取记录并将其保存在缓存中,然后将 MyObject 正确返回给客户端。 But when I hit the API second time, it finds the record in the Cache, and while trying to deserialize that back into MyObject, it.但是当我第二次访问 API 时,它在缓存中找到了记录,并且在尝试将其反序列化回 MyObject 时,它。 always runs into a cast exception:总是遇到强制转换异常:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyObject java.lang.ClassCastException: java.util.LinkedHashMap 无法转换为 MyObject
Here is my Redis Configuration:这是我的 Redis 配置:
public class MyConfiguration {
@Bean
public CacheManager cacheManager(RedisTemplate<String, MyObject> redisTemplate) {
return new RedisCacheManager(redisTemplate);
}
@Bean
public RedisTemplate<String, MyObject> redisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper) {
StringRedisSerializer serializer = new StringRedisSerializer();
GenericJackson2JsonRedisSerializer hashValueSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);
RedisTemplate<String, MyObject> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(serializer);
redisTemplate.setValueSerializer(hashValueSerializer);
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
Found same problem reported here: Spring-data-redis @Cacheable java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String发现这里报告了同样的问题: Spring-data-redis @Cacheable java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String
I researched for quite some time but have no ideas.我研究了一段时间但没有想法。 Please suggest.请建议。 Thanks a ton in advance.提前致谢。
It worked for me by simply setting a new GenericJackson2JsonRedisSerializer()
with no
arguments, in both Key, value serializer
and hash key
, value serializer
通过简单地在 Key, value serializer
和hash key
, value serializer
中设置一个no
参数的新GenericJackson2JsonRedisSerializer()
对我有用
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory, ObjectMapper objectMapper) {
final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
// value serializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// hash value serializer
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
logger.info("wiring up Redistemplate...");
return redisTemplate;
}
Reason原因
You have customized the objectMapper, and there is no class name in the Redis value.你自定义了objectMapper,Redis value中没有类名。 So it can't be deserialized into the real type.所以不能反序列化为真实类型。
You can check the redis value, there is no "@class": "com.xxxx.xxx.entity.xx" in the redis value.可以查看redis值,redis值中没有"@class": "com.xxxx.xxx.entity.xx" 。
My solution我的解决方案
@Bean
public RedisCacheConfiguration redisCacheConfiguration(ObjectMapper objectMapper) {
// Do not change the default object mapper, we need to serialize the class name into the value
objectMapper = objectMapper.copy();
objectMapper = objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(1))
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper)));
}
I use the objectMapper.enableDefaultTyping()
after digging into the source code of the GenericJackson2JsonRedisSerializer.class在深入研究 GenericJackson2JsonRedisSerializer.class 的源代码后,我使用了objectMapper.enableDefaultTyping()
It works for me to serialize and deserialize any Object.它适用于我序列化和反序列化任何对象。 In this example the cache manager is set TTL you can remove this if you want.在此示例中,缓存管理器设置为 TTL,您可以根据需要将其删除。
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Value("${spring.redis.host}")
private String redisHostName;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(redisHostName, redisPort));
}
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
@Bean
@Primary
public RedisCacheManager redisCacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
.entryTtl(Duration.ofMinutes(1))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
redisCacheConfiguration.usePrefix();
return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(lettuceConnectionFactory)
.cacheDefaults(redisCacheConfiguration).build();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.