Closed sivaprasadreddy closed 3 years ago
@sivaprasadreddy thanks for the sample but considering that you are defining the CacheManager
bean yourself, I don't think this should have been reported against Spring Boot.
Spring Data's GenericJackson2JsonRedisSerializer requires to serialize the type of the object. This is done automatically if you create the serializer with the String
-based constructor. If you provide your own mapper, then that feature must be enabled.
I believe the documentation of Spring Data Redis could be improved, I've created https://github.com/spring-projects/spring-data-redis/issues/2140
Just in case someone came across the same issue, it is solved by registering the RedisCacheManager
bean as follows:
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(JsonGenerator.Feature.IGNORE_UNKNOWN);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
RedisSerializer<Object> serializer = new GenericJackson2JsonRedisSerializer(objectMapper);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
.entryTtl(Duration.ofMinutes(1));
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(defaultRedisCacheConfiguration())
.build();
}
Just in case someone came across the same issue, it is solved by registering the
RedisCacheManager
bean as follows:@Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(JsonGenerator.Feature.IGNORE_UNKNOWN); objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); RedisSerializer<Object> serializer = new GenericJackson2JsonRedisSerializer(objectMapper); RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer)) .entryTtl(Duration.ofMinutes(1)); return RedisCacheManager.builder(redisConnectionFactory) .cacheDefaults(defaultRedisCacheConfiguration()) .build(); }
I used your configuration,When saving in redis, you can see the @class information, but when retrieve the value again, it prompts:
Could not read JSON:Unexpected token (START_OBJECT), expected VALUE_STRING: need String, Number of Boolean value that contains type id (for subtype of java.lang.Object)
Complete configuration
@Bean
public <T> RedisTemplate<String, T> redisTemplate(@Autowired LettuceConnectionFactory lettuceConnectionFactory) {
RedisTemplate<String, T> template = new RedisTemplate<>();
template.setConnectionFactory(lettuceConnectionFactory);
StringRedisSerializer keySerializer = new StringRedisSerializer();
RedisSerializer<Object> valueSerializer = RedisSerializer.json();
template.setKeySerializer(keySerializer);
template.setValueSerializer(valueSerializer);
template.setHashKeySerializer(keySerializer);
template.setHashValueSerializer(valueSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(JsonGenerator.Feature.IGNORE_UNKNOWN);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
RedisSerializer<Object> serializer = new GenericJackson2JsonRedisSerializer(objectMapper);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
.entryTtl(Duration.ofMinutes(1));
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
I am trying out basic example of using Redis as Cache provider and trying to customise it to use
GenericJackson2JsonRedisSerializer
instead of defaultJdkSerializationRedisSerializer
.When I call the same method which is cached 2nd time then it is throwing error with following stacktrace:
You can reproduce the issue using this repository https://github.com/sivaprasadreddy/spring-boot-redis-cache-demo
With default
JdkSerializationRedisSerializer
it is working fine.I also saw few issues opening with similar error but they are happening because of
spring-boot-devtools
which I am not using.Is it a bug or am I missing some configuration?