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?
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"
}
Since 2.10 ObjectMapper better to use
activateDefaultTyping(mapper.polymorphicTypeValidator, ObjectMapper.DefaultTyping.NON_FINAL)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With