Reputation: 9847
I'm trying to write a AsyncLoadingCache
that accepts a CacheWriter
and I'm getting an IllegalStateException
.
Here's my code:
CacheWriter<String, UUID> cacheWriter = new CacheWriter<String, UUID>() {
@Override
public void write(String key, UUID value) {
}
@Override
public void delete(String key, UUID value, RemovalCause cause) {
}
};
AsyncLoadingCache<String, UUID> asyncCache = Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.SECONDS)
.writer(cacheWriter)
.maximumSize(100L)
.buildAsync((String s) -> { /* <== line 41, exception occurs here */
return UUID.randomUUID();
});
And I'm getting this trace
Exception in thread "main" java.lang.IllegalStateException at com.github.benmanes.caffeine.cache.Caffeine.requireState(Caffeine.java:174) at com.github.benmanes.caffeine.cache.Caffeine.buildAsync(Caffeine.java:854) at com.mycompany.caffeinetest.Main.main(Main.java:41)
If I'll change the cache to a LoadingCache
or remove .writer(cacheWriter)
the code will run properly. What am I doing wrong? it seems I'm providing the right types to both objects.
Upvotes: 1
Views: 1292
Reputation: 9621
Unfortunately these two features are incompatible. While the documentation states this, I have updated the exception to communicate this better. In Caffeine.writer
it states,
This feature cannot be used in conjunction with {@link #weakKeys()} or {@link #buildAsync}.
A CacheWriter
is a synchronous interceptor for a mutation of an entry. For example, it might be used to evict into a disk cache as a secondary layer, whereas a RemovalListener
is asynchronous and using it would leave a race where the entry is not present in either caches. The mechanism is to use ConcurrentHashMap's
compute
methods to perform the write or removal, and call into the CacheWriter
within that block.
In AsyncLoadingCache
, the value materializes later when the CompletableFuture
is successful, or is automatically removed if null
or an error. When the entry is modified within the hash table, this future may be in-flight. This would mean that the CacheWriter
would often be called without the materialized value and likely cannot do very intelligent things.
From an API perspective, unfortunately telescoping builders (which use the type system to disallow incompatible chains) become more confusing than using runtime exceptions. Sorry for not making the error clear, which should now be fixed.
Upvotes: 3