Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 439
krionz Avatar asked Mar 10 '19 13:03

krionz


People also ask

How do you implement cache in spring boot?

If we want to enable a cache mechanism in a Spring Boot application, we need to add cache dependency in the pom. xml file. It enables caching and configures a CacheManager.

How do I evict a Redis cache in spring boot?

How to Evict a Cache? Spring provides two ways to evict a cache, either by using the @CacheEvict annotation on a method, or by auto-wiring the CacheManger and clearing it by calling the clear() method.


1 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.

like image 110
mp911de Avatar answered Sep 21 '22 11:09

mp911de