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

har*_*sai 5 java redis spring-data

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

java.lang.ClassCastException:无法将java.util.LinkedHashMap强制转换为MyObject

这是我的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

发现此处报告了相同的问题:Spring-data-redis @Cacheable java.lang.ClassCastException:无法将java.util.HashMap强制转换为java.lang.String

我研究了一段时间,但没有任何想法。请提出建议。在此先感谢一吨。

Nin*_*nja 8

原因

您已经自定义了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();
    // This methodo was deprecated in jackson 2.10 or higher use activateDefaultTyping intead of enableDefaultTyping 
    // objectMapper = objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

    objectMapper = objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

    return RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(1))
            .disableCachingNullValues()
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper)));
}
Run Code Online (Sandbox Code Playgroud)

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

  • objectMapper.activateDefaultTyping( objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY ); (4认同)

小智 5

它对我有用,只需在 Key、value和中设置一个GenericJackson2JsonRedisSerializer()带有参数的新值,noserializerhash keyvalue serializer

@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;
    }
Run Code Online (Sandbox Code Playgroud)


小智 0

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

  }
}
Run Code Online (Sandbox Code Playgroud)