I'm trying to create a test project based on Springboot with a Redis Cache.
I'm facing a problem as deserialization from Redis is not working properly
So, to be more precise, I'm running a demo app and the first time I make request to the Cached endpoint it has no problems, as it is read from database and cached on Redis.
The second request fails because of deserialization of the object read from Redis fails.
Debugging the code, it seems the object provided by Redis is a LinkedHashMap, instead of the Entity I tried to save.
Here is my simple app code base:
POM
org.springframework.boot
spring-boot-starter-parent
3.5.15
..
21
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-cache
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-data-redis
....
........
Service:
@Service
@RequiredArgsConstructor
public class TextoService implements Serializable{
@Autowired
private TextoRepository repository;
@Cacheable(value = "textoCache", key = "#id")
public Optional getById(Integer id){
return this.repository.findById(id);
}
}
Redis Config
@Configuration
public class RedisConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory, ObjectMapper mapper) {
// JSON serializer for values
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer(mapper);
// String serializer for keys
StringRedisSerializer stringSerializer = new StringRedisSerializer();
// Default cache configuration
RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer))
.entryTtl(Duration.ofMinutes(30)) // Default TTL: 30 minutes
.disableCachingNullValues()
.prefixCacheNameWith("app:cache:");
// Per-cache configurations with different TTLs
Map cacheConfigurations = Map.of(
"users", defaultConfig
.entryTtl(Duration.ofMinutes(5))
.prefixCacheNameWith("app:users:"),
"profiles", defaultConfig
.entryTtl(Duration.ofMinutes(10))
.prefixCacheNameWith("app:profiles:")
);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(defaultConfig)
.withInitialCacheConfigurations(cacheConfigurations)
.transactionAware()
.build();
}
}
When running I get this error log the second time I make the request:
java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class com.demo.cache_redis.entitiy.Texto (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.demo.cache_redis.entitiy.Texto is in unnamed module of loader 'app')
at com.demo.cache_redis.controller.TextoController.getById(TextoController.java:31) ~[classes/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:258) ~[spring-web-6.2.19.jar:6.2.19]
And debuggin the code, on the controller side I get this:
But It shoukld be an Optional
What I am missing here?
Either the redis object is not correctly stored or incorrectly retrieved
I'm following this guide
Help