Configure a new serializer for spring-boot redis cache config

I have been trying to change the default serializer for the spring-boot redis cache because i want to change from the Default to one of the Jackson2Json implementations. There are two implementations from the Jackson2Json library one of them is the: GenericJackson2JsonRedisSerializer, which i can use on the following bean instantiation:

@Bean @Primary public RedisCacheConfiguration defaultCacheConfig(ObjectMapper objectMapper) { return RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith( SerializationPair.fromSerializer( new StringRedisSerializer() ) ) .serializeValuesWith( SerializationPair.fromSerializer( new GenericJackson2JsonRedisSerializer(objectMapper) ) ) .prefixKeysWith(""); } 

When i use this serializer the serialization works fine, everything is stored on the redis server, but when o try to deserialize the JSON stored on the redis server i receive the following exception:

java.util.LinkedHashMap cannot be cast to tutorial.Person with root cause java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to tutorial.Person 

The cache is being used on the following way:

@Cacheable(cacheNames = "person", key = "'person:'.concat(#post.id)") public Person findPostAuthor(Post post){ } 

The serializer doesn't know how to convert from the LinkedHashMap to the Person, how can i tell him how to do it?

The other serializer i tried to work with was the Jackson2JsonRedisSerializer:

@Bean @Primary public RedisCacheConfiguration defaultCacheConfig(ObjectMapper objectMapper) { Jackson2JsonRedisSerializer<Person> serializer = new Jackson2JsonRedisSerializer<>(Person.class); serializer.setObjectMapper(objectMapper); return RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith( SerializationPair.fromSerializer( new StringRedisSerializer() ) ) .serializeValuesWith( SerializationPair.fromSerializer( serializer ) ) .prefixKeysWith(""); } 

On this way i would have to declare a bean for each object saved on the redis cache, but i can serialize / deserialize correctly.

When i insert a JSON directly on the redis cache, i can't deserialize it with this serializer the serializer just gives me a Person object with empty name, email, and id properties. Is there a way to fix this?

If there is a way to improve my question, please let me know.

3 Answers

GenericJackson2JsonRedisSerializer assumes Jackson's default typing. When you create GenericJackson2JsonRedisSerializer with an ObjectMapper instance, then make sure to configure default typing (enableDefaultTyping(…)).

Default typing works best with non-final types and requires a consistent property name for the type across all JSON payload so Jackson can identify the appropriate type to deserialize to.

Default typing uses a dynamic type marker and if your data source (Redis instance) isn't fully trusted, then this can become a security concern.

Jackson2JsonRedisSerializer is pinned to a specific type and removes the dynamic typing risk.

1

You could use Spring Data Redis

Add dependencies:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 

Enable Caching anad use Jackson2JsonRedisSerializer

package com.redis.demo.redisdemo.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; @EnableCaching @Configuration public class RedisConfig extends CachingConfigurerSupport { @Autowired private RedisConnectionFactory redisConnectionFactory; @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(objectMapper); RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(serializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(serializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) { RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory()); RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer())); return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration); } } 

Add Cacheable annotation at method to cache in redis

@Cacheable(value = "employee", key = "#id") public Employee getEmployee(Integer id) { log.info("Get Employee By Id: {}", id); Optional<Employee> employeeOptional = employeeRepository.findById(id); if (!employeeOptional.isPresent()) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Id Not foud"); } return employeeOptional.get(); } 

I know it's been a long time since the question was asked but may be there is somebody who still need the answer.

I had the same problem and I resolve it using JdkSerializationRedisSerializerinstead of GenericJackson2JsonRedisSerializer.

My RedisCacheConfiguration bean looks like:

return RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofHours("your-long-value")) .serializeKeysWith(SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer())); 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like