JSR-107 JCache compatibility adapter for Caffeine caching library
—
The Cache Operations system provides the complete JSR-107 Cache interface implementation with both synchronous and asynchronous operations. The CacheProxy and LoadingCacheProxy classes implement all standard caching operations backed by Caffeine's high-performance cache engine.
Core caching functionality for storing, retrieving, and checking cache entries.
/**
* Get value by key, returns null if not present
* @param key the key to look up
* @return the associated value or null
*/
public @Nullable V get(K key);
/**
* Get multiple values by keys
* @param keys the set of keys to look up
* @return map of found key-value pairs
*/
public Map<K, V> getAll(Set<? extends K> keys);
/**
* Check if a key exists in the cache
* @param key the key to check
* @return true if key exists and hasn't expired
*/
public boolean containsKey(K key);
/**
* Store a key-value pair in the cache
* @param key the key to store
* @param value the value to associate with the key
*/
public void put(K key, V value);
/**
* Store multiple key-value pairs in the cache
* @param map the map of key-value pairs to store
*/
public void putAll(Map<? extends K, ? extends V> map);
/**
* Store key-value pair only if key is not already present
* @param key the key to store
* @param value the value to associate with the key
* @return true if the key was absent and value was stored
*/
public boolean putIfAbsent(K key, V value);Usage Examples:
Cache<String, Integer> cache = cacheManager.getCache("numbers", String.class, Integer.class);
// Basic operations
cache.put("one", 1);
cache.put("two", 2);
Integer value = cache.get("one"); // Returns 1
boolean exists = cache.containsKey("two"); // Returns true
// Bulk operations
Map<String, Integer> batch = Map.of(
"three", 3,
"four", 4,
"five", 5
);
cache.putAll(batch);
Set<String> keys = Set.of("one", "three", "five");
Map<String, Integer> results = cache.getAll(keys);
// Conditional put
boolean added = cache.putIfAbsent("six", 6); // Returns true
boolean notAdded = cache.putIfAbsent("six", 60); // Returns false, value unchangedThread-safe atomic operations that combine read and write operations.
/**
* Atomically get current value and store new value
* @param key the key to update
* @param value the new value to store
* @return the previous value or null if key was absent
*/
public @Nullable V getAndPut(K key, V value);
/**
* Atomically get current value and remove the entry
* @param key the key to remove
* @return the previous value or null if key was absent
*/
public V getAndRemove(K key);
/**
* Atomically get current value and replace with new value
* @param key the key to replace
* @param value the new value to store
* @return the previous value or null if key was absent
*/
public V getAndReplace(K key, V value);
/**
* Replace value only if current value equals expected value
* @param key the key to replace
* @param oldValue the expected current value
* @param newValue the new value to store
* @return true if replacement occurred
*/
public boolean replace(K key, V oldValue, V newValue);
/**
* Replace value only if key is currently mapped to some value
* @param key the key to replace
* @param value the new value to store
* @return true if replacement occurred
*/
public boolean replace(K key, V value);Usage Examples:
Cache<String, AtomicInteger> counters = cacheManager.getCache("counters", String.class, AtomicInteger.class);
// Initialize counter
counters.put("requests", new AtomicInteger(0));
// Atomic get-and-update operations
AtomicInteger oldCounter = counters.getAndPut("requests", new AtomicInteger(1));
AtomicInteger removedCounter = counters.getAndRemove("requests");
// Conditional replacement
counters.put("status", new AtomicInteger(0));
boolean replaced = counters.replace("status", new AtomicInteger(0), new AtomicInteger(1));
// Simple replacement
boolean updated = counters.replace("status", new AtomicInteger(2));Various methods for removing entries from the cache.
/**
* Remove entry by key
* @param key the key to remove
* @return true if key was present and removed
*/
public boolean remove(K key);
/**
* Remove entry only if current value equals expected value
* @param key the key to remove
* @param oldValue the expected current value
* @return true if removal occurred
*/
public boolean remove(K key, V oldValue);
/**
* Remove multiple entries by keys
* @param keys the set of keys to remove
*/
public void removeAll(Set<? extends K> keys);
/**
* Remove all entries from the cache
*/
public void removeAll();
/**
* Clear all entries from the cache without triggering listeners
*/
public void clear();Usage Examples:
Cache<String, String> cache = cacheManager.getCache("data", String.class, String.class);
// Populate cache
cache.putAll(Map.of("key1", "value1", "key2", "value2", "key3", "value3"));
// Remove single entry
boolean removed = cache.remove("key1"); // Returns true
// Conditional removal
boolean conditionalRemove = cache.remove("key2", "value2"); // Returns true
boolean failedRemove = cache.remove("key3", "wrongValue"); // Returns false
// Bulk removal
cache.removeAll(Set.of("key2", "key3"));
// Remove all entries
cache.removeAll(); // Triggers entry removed events
// Clear cache (no events)
cache.clear();Support for asynchronous cache loading with completion callbacks.
/**
* Asynchronously load multiple entries, optionally replacing existing values
* @param keys the set of keys to load
* @param replaceExistingValues whether to replace existing cached values
* @param completionListener callback for completion or failure notification
*/
public void loadAll(Set<? extends K> keys,
boolean replaceExistingValues,
CompletionListener completionListener);Usage Examples:
Cache<String, User> userCache = cacheManager.getCache("users", String.class, User.class);
// Asynchronous loading with completion listener
Set<String> userIds = Set.of("user1", "user2", "user3");
userCache.loadAll(userIds, false, new CompletionListener() {
@Override
public void onCompletion() {
System.out.println("Loading completed successfully");
}
@Override
public void onException(Exception e) {
System.err.println("Loading failed: " + e.getMessage());
}
});
// Loading with replacement
userCache.loadAll(userIds, true, null); // No completion listenerAtomic entry processing operations for complex cache manipulations.
/**
* Atomically process a single cache entry
* @param key the key to process
* @param entryProcessor the processor to apply
* @param arguments additional arguments for the processor
* @return result from the entry processor
*/
public <T> @Nullable T invoke(K key, EntryProcessor<K, V, T> entryProcessor, Object... arguments);
/**
* Atomically process multiple cache entries
* @param keys the set of keys to process
* @param entryProcessor the processor to apply
* @param arguments additional arguments for the processor
* @return map of processing results
*/
public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys,
EntryProcessor<K, V, T> entryProcessor,
Object... arguments);Usage Examples:
Cache<String, Integer> cache = cacheManager.getCache("counters", String.class, Integer.class);
// Entry processor to increment counter
EntryProcessor<String, Integer, Integer> incrementProcessor =
(entry, arguments) -> {
Integer current = entry.getValue();
if (current == null) {
current = 0;
}
Integer newValue = current + 1;
entry.setValue(newValue);
return newValue;
};
// Process single entry
Integer result = cache.invoke("counter1", incrementProcessor);
// Process multiple entries
Set<String> keys = Set.of("counter1", "counter2", "counter3");
Map<String, EntryProcessorResult<Integer>> results =
cache.invokeAll(keys, incrementProcessor);
// Handle results
for (Map.Entry<String, EntryProcessorResult<Integer>> entry : results.entrySet()) {
try {
Integer value = entry.getValue().get();
System.out.println(entry.getKey() + " = " + value);
} catch (EntryProcessorException e) {
System.err.println("Processing failed for " + entry.getKey() + ": " + e.getMessage());
}
}Extended cache implementation with automatic loading capabilities.
/**
* Extended cache that automatically loads missing entries using configured CacheLoader
*/
public final class LoadingCacheProxy<K, V> extends CacheProxy<K, V> {
/**
* Get value by key, loading if necessary using the configured CacheLoader
* @param key the key to look up
* @return the associated value (loaded if not present)
* @throws CacheException if loading fails
*/
@Override
public @Nullable V get(K key);
/**
* Get multiple values by keys, loading missing entries as needed
* @param keys the set of keys to look up
* @return map of key-value pairs (missing entries are loaded)
* @throws CacheException if loading fails
*/
@Override
public Map<K, V> getAll(Set<? extends K> keys);
}Usage Examples:
// Configure cache with loader
CaffeineConfiguration<String, User> config = new CaffeineConfiguration<String, User>()
.setTypes(String.class, User.class)
.setCacheLoaderFactory(() -> new DatabaseUserLoader())
.setReadThrough(true);
Cache<String, User> userCache = cacheManager.createCache("users", config);
// Automatic loading on cache miss
User user = userCache.get("user123"); // Loads from database if not cached
// Bulk loading
Set<String> userIds = Set.of("user1", "user2", "user3");
Map<String, User> users = userCache.getAll(userIds); // Loads missing usersAccess to cache metadata and administrative operations.
/**
* Get the cache name
* @return the name of this cache
*/
public String getName();
/**
* Get the associated cache manager
* @return the CacheManager that created this cache
*/
public CacheManager getCacheManager();
/**
* Check if the cache is closed
* @return true if the cache has been closed
*/
public boolean isClosed();
/**
* Close the cache and release resources
*/
public void close();
/**
* Get cache configuration
* @param clazz the configuration class to retrieve
* @return immutable copy of the configuration
*/
public <C extends Configuration<K, V>> C getConfiguration(Class<C> clazz);
/**
* Unwrap cache to specific implementation type
* @param clazz the class to unwrap to
* @return unwrapped instance
*/
public <T> T unwrap(Class<T> clazz);
/**
* Get iterator over cache entries
* @return iterator for cache entries
*/
public Iterator<Cache.Entry<K, V>> iterator();Install with Tessl CLI
npx tessl i tessl/maven-com-github-ben-manes-caffeine--jcache