I'm using Spring Boot with Redis caching and Jackson2JsonRedisSerializer for serialization. My RedisConfig is set up like this:
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return objectMapper;
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory, ObjectMapper objectMapper) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashValueSerializer(serializer);
return redisTemplate;
}
@Bean
public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory, ObjectMapper objectMapper) {
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(redisCacheConfiguration)
.build();
}
}
When caching LocalDate, it seems to be stored as a String in Redis. But when I try to read it back, I'm getting this error:
class java.lang.String cannot be cast to class java.time.LocalDate
(java.lang.String and java.time.LocalDate are in module java.base of loader 'bootstrap')
What am I missing? How can I ensure LocalDate is properly deserialized when reading from cache?
Update: Fixing redisCacheManager as shown below temporarily solved my issue, but I don't want to manually set it like this every time.
Is there a dynamic serializer/deserializer in Redis that prevents casting exceptions?
@Bean
public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory, ObjectMapper objectMapper) {
Jackson2JsonRedisSerializer<Object> defaultSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(defaultSerializer));
Map<String, Class<?>> cacheTypeMap = new HashMap<>();
cacheTypeMap.put("initialFundPriceDate", LocalDate.class);
cacheTypeMap.put("fundPriceMap", FundCardPriceDto.class);
cacheTypeMap.put("currencyPriceMap", CurrencyPriceDto.class);
cacheTypeMap.put("fundCardAvgShares", BigDecimal.class);
cacheTypeMap.put("fundCardGenerateYield", BigDecimal.class);
cacheTypeMap.put("fundCardStandardDev", BigDecimal.class);
cacheTypeMap.put("fundCardDefinitionMap", FundDefinitionDto.class);
Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
for (Map.Entry<String, Class<?>> entry : cacheTypeMap.entrySet()) {
Jackson2JsonRedisSerializer<?> serializer =
new Jackson2JsonRedisSerializer<>(objectMapper, entry.getValue());
RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
cacheConfigurations.put(entry.getKey(), cacheConfig);
}
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(defaultCacheConfig)
.withInitialCacheConfigurations(cacheConfigurations)
.build();
}