Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this article, we’ll learn how to get all cached keys in the Caffeine Cache when used with Spring’s Cache abstraction layer.

2. Spring Caching

Caching is an integral part of Spring Framework. It’s been a part of Spring’s ecosystem since the 3.1 version. Therefore, it has a set of well-defined and battle-tested interfaces.

Let’s have a look at the two main ones: CacheManager and Cache:

interface CacheManager {
    Cache getCache(String name);
    Collection<String> getCacheNames();
}

public interface Cache {
    String getName();
    Object getNativeCache();
    ValueWrapper get(Object key);
    <T> T get(Object key, @Nullable Class<T> type);
    <T> T get(Object key, Callable<T> valueLoader);
    void put(Object key, @Nullable Object value);
    ValueWrapper putIfAbsent(Object key, @Nullable Object value);
    void evict(Object key);
    void clear();
}

As we can see, CacheManager is simply a wrapper. A registry of cache regions that are available in the application. A Cache object, on the other hand, is a set of key-value pairs within the region.

None of them, though, provides a way to list available keys.

3. Setup

Before we explore our options for accessing the collection of all available keys, let’s define the CaffeineCacheManager used by our test application:

@Configuration
@EnableCaching
public class AllKeysConfig {

    @Bean
    CacheManager cacheManager() {
        return new CaffeineCacheManager();
    }
}

Then, let’s create a slow service that would populate the cache upon each call:

public class SlowServiceWithCache {

    @CachePut(cacheNames = "slowServiceCache", key = "#name")
    public String save(String name, String details) {
        return details;
    }
}

With both manager and service in place, we are ready to look for the keys in the slowServiceCache region.

4. Accessing All Cache Keys

As we’ve learned already, CacheManager does not expose any method to access all available keys. Neither does the Cache interface.

Therefore we need to use the knowledge of the actual cache implementation we’ve defined in our application. Let’s cast Spring’s generic interfaces to their appropriate Caffeine implementations.

We need to inject the CacheManager first:

@Autowired
CacheManager cacheManager;

Then let’s do a few simple cast operations to access the native Caffeine Cache:

CaffeineCacheManager caffeineCacheManager = (CaffeineCacheManager) cacheManager;
CaffeineCache cache = (CaffeineCache) caffeineCacheManager.getCache("slowServiceCache");
Cache<Object, Object> caffeine = cache.getNativeCache();

Then, let’s call caffeine.asMap(). Because it’s a map, we can access the keys simply by calling caffeine.asMap().keySet():

@Test
public void givenCaffeineCacheCachingSlowCalls_whenCacheManagerProperlyCasted_thenAllKeysAreAccessible() {
    slowServiceWithCache.save("first", "some-value-first");
    slowServiceWithCache.save("second", "other-value-second");

    Cache<Object, Object> caffeine = getNativeCaffeineCacheForSlowService();

    assertThat(caffeine.asMap().keySet()).containsOnly("first", "second");
}

4. Conclusion

In this article, we’ve learned how to access the collection of all available keys from the Caffeine cache used with Spring Cache. Knowing the actual cache we’re dealing with, accessing all available keys requires only a few simple cast operations.

As always, the code for this article is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.