简体   繁体   English

spring-data-redis @Cacheable java.lang.ClassCastException: java.util.LinkedHashMap 无法转换为 MyObject

[英]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 serializerhash 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.

相关问题 java.lang.ClassCastException:无法强制转换java.util.LinkedHashMap - java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast Java Spring rest java.lang.ClassCastException:java.util.LinkedHashMap 不能转换为 Cuestionario - Java Spring rest java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to Cuestionario java.lang.ClassCastException:java.util.LinkedHashMap 无法转换为 java.time.LocalDateTime - java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to java.time.LocalDateTime Spring websocket @messagemapping反序列化问题java.lang.ClassCastException:java.util.LinkedHashMap无法强制转换 - Spring websocket @messagemapping de-serialization issue java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast java.lang.ClassCastException:无法将java.util.LinkedHashMap强制转换为com。****。db。***** - java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.****.db.***** java.lang.ClassCastException:无法将java.util.LinkedHashMap强制转换为com.example.backendtest.Project - java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.example.backendtest.Project java.lang.ClassCastException:无法将java.util.LinkedHashMap转换为特定类 - java.lang.ClassCastException: Cannot cast java.util.LinkedHashMap to Specific class 如何修复“java.lang.ClassCastException:类 java.util.LinkedHashMap 无法转换为类”错误? - How to fix 'java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class' error? java.lang.ClassCastException:java.util.LinkedHashMap 无法转换为 com..dto.PersonDto - java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com..dto.PersonDto java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap无法转换为java.util.LinkedHashMap - java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to java.util.LinkedHashMap
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM