Cache key issues with Jcache

1.6k views Asked by At

I am using JSR107 caching with Springboot. I have following method.

@CacheResult(cacheName = "books.byidAndCat")
public List<Book> getAllBooks(@CacheKey final String bookId, @CacheKey final BookCategory bookCat) {

return <<Make API calls and get actual books>>
}

First time it makes actual API calls, and second time it loads cache without issue. I can see the following part of log.

Computed cache key SimpleKey [cb5bf774-24b4-41e5-b45c-2dd377493445,LT] for operation CacheResultOperation[CacheMethodDetails ...

But the problem is I want to load cache without making even first API call, Simply needs to fill the cache like below.

String cacheKey  = SimpleKeyGenerator.generateKey(bookId, bookCategory).toString();     
        cacheManager.getCache("books.byidAndCat").put(cacheKey, deviceList);

When I am checking, hashcode of cachekeys are same in both cases, But it is making API calls. If the hashcode is same in both cases, why it is making API calls without considering the cache ?

When debugging spring classes identified that, org.springframework.cache.interceptor.SimpleKeyGenerator is used with the cache key generation even @CacheResult is there. EDIT and enhance the question :

Apart from that if getAllBooks has overloaded methods, and then call this cached method via separate overloaded method, in that case also method caching is not working.

2

There are 2 answers

1
Ruchira Kariyawasam On BEST ANSWER

As @Henri suggested, we can use the cacheput. But for that we need methods. With the below we can update the cache very similar to the cacheput,

//overloaded method both id and cat is available.

List<Object> bookIdCatCache = new ArrayList<>();
    bookIdCatCache.add(bookId);
    bookIdCatCache.add(deviceCat);
    Object bookIdCatCacheKey  = SimpleKeyGenerator.generateKey(bookIdCatCache.toArray(new Object[bookIdCatCache.size()]));
    cacheManager.getCache("books.byidAndCat").put(bookIdCatCacheKey , bookListWithIdAndCat);

//overloaded method only id is there

List<Object> bookIdCache = new ArrayList<>();
        String nullKey          = null
        bookIdCache.add(bookId);
        bookIdCache.add(nullKey);
        Object bookIdCacheKey  = SimpleKeyGenerator.generateKey(bookIdCache.toArray(new Object[bookIdCache.size()]));
        cacheManager.getCache("books.byidAndCat").put(bookIdCacheKey , bookListWithId);

//Not correct(My previous implementation)

String cacheKey  = SimpleKeyGenerator.generateKey(bookId, bookCategory).toString();

//Correct(This is getting from spring)

Object cacheKey  = SimpleKeyGenerator.generateKey(bookIdCatCache.toArray(new Object[bookIdCatCache.size()]));
6
Henri On

I'm not an expert of JSR107 annotations in the context of Spring. I use the Spring Cache annotations instead.

When using JSR107, the key used is a GeneratedCacheKey. So that's what you should put in your cache. Not the toString() of it. Note that SimpleKeyGenerator isn't returning a GeneratedCacheKey. It returns a SimpleKey which is the key used by Spring when using its own cache annotations instead of JSR-107. For JSR-107, you need a SimpleGeneratedCacheKey.

Then, if you want to preload the cache, just call getAllBooks before needing it.

If you want to preload the cache in some other way, a @javax.cache.annotation.CachePut should do the trick. See its javadoc for an example.