Spring Cache, Force to Set the Return Type
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...
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