How to use GenericJackson2JsonRedisSerializer
Asked Answered
T

2

14

I am using Spring Data Redis in order to cache some data using @Cacheable. I have multiple types of objects that need to be cached and I need the data from Redis to be in JSON format. I know that, by default, the serializer used is JdkSerializationRedisSerializer, but with is the cached data is not human readable.

I order to save the data in JSON format I wanted to use GenericJackson2JsonRedisSerializer and I've created a custom ObjectMapper too:

  public RedisTemplate<Object, Object> redisTemplate (RedisConnectionFactory cf) {

    ObjectMapper objectMapper = new Jackson2ObjectMapperBuilder().failOnEmptyBeans(false)
        .failOnUnknownProperties(false)
        .indentOutput(false)
        .serializationInclusion(JsonInclude.Include.NON_NULL)
        .modules(
            // Optional
            new Jdk8Module(),
            // Dates/Times
            new JavaTimeModule()
        )
        .featuresToDisable(
            SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
            DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS,
            SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS
        ).build();


    GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);
    RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(cf);
    redisTemplate.setKeySerializer(genericJackson2JsonRedisSerializer);
    redisTemplate.setHashKeySerializer(genericJackson2JsonRedisSerializer);
    redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
    redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
    return redisTemplate;

Using this RedisTemplate doesn't work and I always get back this error:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to <some class>

As I understood, when deserializing, Jackson doesn't know the type of the specific object since it's Object and creates a LinkedHashMap to hold the data. Maybe I am wrong with this, but how can I achieve saving the cached data as JSON for multiple types of objects with @Cacheble?

Trolley answered 25/1, 2021 at 13:51 Comment(0)
T
16

You are right, you can achieve saving multiple types with GenericJackson2JsonRedisSerializer. But in your example, you provide custom ObjectMapper to GenericJackson2JsonRedisSerializer and GenericJackson2JsonRedisSerializer doesn't configure Jackson's default typing for you (you can check default constructor logic in GenericJackson2JsonRedisSerializer). You have to tune it on your own and add this to your ObjectMapper

objectMapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);

This will include type information to JSON. Like this

{
  "@class": "com.example.Foo",
  "field": "bar"
}
Tiana answered 25/1, 2021 at 21:43 Comment(2)
Hi Aleh! Thanks for your bringing light on the subject!Trolley
I'm having the same issue but I'm injecting ObjectMapper so it should be the same object mapper (with the same configuration) as the one that Spring uses throughout the application right (e.g when deserializing JSON body of http requests) ?Timeout
P
8

Since 2.10 ObjectMapper better to use

activateDefaultTyping(mapper.polymorphicTypeValidator, ObjectMapper.DefaultTyping.NON_FINAL)
Pyrogallate answered 17/5, 2022 at 5:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.