【问题标题】:Spring-data-redis @Cacheable java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyObjectSpring-data-redis @Cacheable java.lang.ClassCastException: java.util.LinkedHashMap 不能转换为 MyObject
【发布时间】:2018-08-07 13:18:25
【问题描述】:

我正在使用 spring-data-redis 在我的 Spring Boot 应用程序中缓存数据。我使用 Mongo 作为我的主要数据源,使用 Redis 作为缓存。当我第一次点击 API 时,它会从 Mongo 获取记录并将其保存在缓存中,并将 MyObject 正确返回给客户端。但是当我第二次点击 API 时,它会在缓存中找到记录,并在尝试将其反序列化回 MyObject 时,它 .总是遇到强制转换异常:

java.lang.ClassCastException: java.util.LinkedHashMap 不能被强制转换 到我的对象

这是我的 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;
    }
}

在这里发现同样的问题:Spring-data-redis @Cacheable java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String

我研究了很长时间,但没有任何想法。请建议。 非常感谢。

【问题讨论】:

  • 更新:这可以通过使用具有泛型的不同序列化程序并传入 ObjectMapper 来解决。使用 Jackson2JsonRedisSerializer 和 objectSerializer.setObjectMapper(objectMapper)。
  • 没有解决原来的问题。
  • 使用 Jackson2JsonRedisSerializer 可以解决您的具体情况,但它不是可扩展的解决方案,因为您不能向 redisTemplate 添加多个 Jackson2JsonRedisSerializer

标签: java redis spring-data


【解决方案1】:

我可以序列化和反序列化任何对象。在此示例中,缓存管理器设置为 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();

  }
}

【讨论】:

    【解决方案2】:

    只需在键、值serializerhash keyvalue serializer 中设置一个新的GenericJackson2JsonRedisSerializer()no 参数,它就对我有用

    @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;
        }
    

    【讨论】:

      【解决方案3】:

      原因

      你自定义了objectMapper,Redis值中没有类名。所以不能反序列化成真正的类型。

      可以查看redis值,redis值中没有"@class" : "com.xxxx.xxx.entity.xx"

      我的解决方案

      @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)));
      }
      

      我在深入研究GenericJackson2JsonRedisSerializer.class的源代码后使用objectMapper.enableDefaultTyping()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-22
        • 2015-04-30
        • 2022-01-14
        • 2014-02-08
        相关资源
        最近更新 更多