I'm trying to implement org.springframework.cache.Cache The cached value is stored as JSON in a SQL database. In the Cache interface, there are multiple get methods.
ValueWrapper get(Object key); <T> T get(Object key, @Nullable Class<T> type); <T> T get(Object key, Callable<T> valueLoader); This is the first one that is used (without type or any generic information). The problem is that since I save the value as JSON, I'd like to have the return value of the cached methods to help deserialize it.
How can I force spring to use the method <T> T get(Object key, @Nullable Class<T> type); when using the @Cacheable annotation ?
My cache implementation (kotlin) :
class SqlCache( private val name: String, private val expiration: Duration, private val cacheRepository: CacheRepository, ): Cache { private val isoObjectMapper = ObjectMapper() .registerModule(KotlinModule()) .registerModule(JavaTimeModule()) .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) override fun getName(): String { return name } override fun getNativeCache(): Any { return cacheRepository } // The method called by spring ! override fun get(key: Any): Cache.ValueWrapper? { val cache = cacheRepository.find(name = name, key = key.toString()) ?: return null val value = isoObjectMapper.readValue(cache.value, UserModel::class) return SimpleValueWrapper(value) } override fun <T : Any?> get(key: Any, type: Class<T>?): T? { val cache = cacheRepository.find(name = name, key = key.toString()) ?: return null return isoObjectMapper.readValue(cache.value, type) } override fun <T : Any?> get(key: Any, valueLoader: Callable<T>): T? { return null } override fun put(key: Any, value: Any?) { cacheRepository.put( name = name, key = key.toString(), value = value, expiration = expiration, ) } override fun evict(key: Any) { cacheRepository.delete( name = name, key = key.toString(), ) } override fun clear() { } } Exemple of cache usage :
interface UserClientAdapter { @Cacheable(value = ["user-cache"], key = "#id") fun getUser(id: UUID): UserModel } So, in this last method, the user is well stored as a JSON string in the database. But when we try to get back the cache. This is the method ValueWrapper get(Object key); that is called. So I don't know the expected return type of the method.
1 Answer
You should refer to the RedisCache implementation class. extends AbstractValueAdaptingCache Implement the lookup method Write your deserialization method in the lookup method
protected Object lookup(Object key) { byte[] value = this.cacheWriter.get(this.name, this.createAndConvertCacheKey(key)); return value == null ? null : this.deserializeCacheValue(value); } If you still can't return your results
Then you need to debug CacheAspectSupport.java execute method,
which handles the hit Cache.ValueWrapper