Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating a Caffeine LoadingCache using a Guava CacheLoader #766

Closed
Zuplyx opened this issue Sep 2, 2022 · 6 comments
Closed

Creating a Caffeine LoadingCache using a Guava CacheLoader #766

Zuplyx opened this issue Sep 2, 2022 · 6 comments

Comments

@Zuplyx
Copy link

Zuplyx commented Sep 2, 2022

Hi,

we are currently in the process of migrating from Guava cache to Caffeine. In our codebase we have several classes implementing Guava's CacheLoader. Ideally we'd like to leave these classes unchanged.
Is there a way to create a Caffeine LoadingCache using a Guava CacheLoader?
Maybe an analogue to CaffeinatedGuava's build method, but which directly returns the created Caffeine cache instead of wrapping it in a Guava cache?

@ben-manes
Copy link
Owner

I suppose it depends on which features of Guava's CacheLoader you are implementing. I think you could write an adapter without too much trouble.

Single loading

This is a 1-to-1 so you can use a method reference

LoadingCache<K, V> cache = Caffeine.newBuilder().build(guavaCacheLoader::load);

Bulk loading

This is slightly harder since Caffeine detects if loadAll is implemented at construction, so you should be mindful to use this only when appropriate. Otherwise a bulk getAll will call Guava's default method to throw an exception, which is not handled at runtime due to the prior detection. This differs from Guava which swallows the exception at runtime to fallback to singular loads.

LoadingCache<K, V> cache = Caffeine.newBuilder().build(new CacheLoader<K, V>() {
  public K load(K key) {
    return guavaCacheLoader.load(key);
  }
  public Map<K, V> loadAll(Set<? extends K> keys) {
    return guavaCacheLoader.loadAll(keys);
  }
});

If you don't mind using the bulk loadAll for singular lookups, then you could simplify this to a method reference.

LoadingCache<K, V> cache = Caffeine.newBuilder().build(CacheLoader.bulk(guavaCacheLoader::loadAll));

Reloading

If you customize the reload(key) method to use the old value, then the futures need to be converted. The future-converter library makes this easier.

import net.javacrumbs.futureconverter.java8guava.FutureConverter;

LoadingCache<K, V> cache = Caffeine.newBuilder().build(new CacheLoader<K, V>() {
  public K load(K key) {
    return guavaCacheLoader.load(key);
  }
  public CompletableFuture<? extends V> asyncReload(K key, V oldValue, Executor executor) {
    return FutureConverter.toCompletableFuture(guavaCacheLoader.reload(key, oldValue));
  }
});

ben-manes added a commit that referenced this issue Sep 4, 2022
The Guava adapters wrap the Caffeine implementations to masquerade under
their APIs. Sometimes users wish to use Caffeine's APIs without migrating
their Guava CacheLoader. The adapter is now available for use with our
cache builder.

```java
CacheLoader<K, V> caffeineLoader = CaffeinatedGuava.caffeinate(guavaLoader);
LoadingCache<K, V> caffeineCache = Caffeine.newBuilder().build(caffeineLoader);
```
@ben-manes
Copy link
Owner

I've exposed our existing adapters in the Guava package. I'm not sure when the next release will be, so you might review that code to embed something similar locally. It's a little more complex since it handles single, bulk, async loading, and some internal adaptation details.

CacheLoader<K, V> caffeineLoader = CaffeinatedGuava.caffeinate(guavaLoader);
LoadingCache<K, V> caffeineCache = Caffeine.newBuilder().build(caffeineLoader);

ben-manes added a commit that referenced this issue Sep 4, 2022
The Guava adapters wrap the Caffeine implementations to masquerade under
their APIs. Sometimes users wish to use Caffeine's APIs without migrating
their Guava CacheLoader. The adapter is now available for use with our
cache builder.

```java
CacheLoader<K, V> caffeineLoader = CaffeinatedGuava.caffeinate(guavaLoader);
LoadingCache<K, V> caffeineCache = Caffeine.newBuilder().build(caffeineLoader);
```
ben-manes added a commit that referenced this issue Sep 4, 2022
The Guava adapters wrap the Caffeine implementations to masquerade under
their APIs. Sometimes users wish to use Caffeine's APIs without migrating
their Guava CacheLoader. The adapter is now available for use with our
cache builder.

```java
CacheLoader<K, V> caffeineLoader = CaffeinatedGuava.caffeinate(guavaLoader);
LoadingCache<K, V> caffeineCache = Caffeine.newBuilder().build(caffeineLoader);
```
ben-manes added a commit that referenced this issue Sep 4, 2022
The Guava adapters wrap the Caffeine implementations to masquerade under
their APIs. Sometimes users wish to use Caffeine's APIs without migrating
their Guava CacheLoader. The adapter is now available for use with our
cache builder.

```java
CacheLoader<K, V> caffeineLoader = CaffeinatedGuava.caffeinate(guavaLoader);
LoadingCache<K, V> caffeineCache = Caffeine.newBuilder().build(caffeineLoader);
```
ben-manes added a commit that referenced this issue Sep 4, 2022
The Guava adapters wrap the Caffeine implementations to masquerade under
their APIs. Sometimes users wish to use Caffeine's APIs without migrating
their Guava CacheLoader. The adapter is now available for use with our
cache builder.

```java
CacheLoader<K, V> caffeineLoader = CaffeinatedGuava.caffeinate(guavaLoader);
LoadingCache<K, V> caffeineCache = Caffeine.newBuilder().build(caffeineLoader);
```
@Zuplyx
Copy link
Author

Zuplyx commented Sep 5, 2022

Thanks Ben. That's exactly what we needed.

@patric-r
Copy link

We're facing exactly the same situation as @Zuplyx.
We're in the transitioning phase from guava cache to your awesome Caffeine but we also have many Guava CacheLoader implementations.
However, this issue (including loadAll/reload feature which we heavily use as well ) prevents us from switching to caffeine.

@ben-manes This issue has been fixed more than two months ago. Any chance to get a release out soon?
I'm sure this will be an awesome improvement and helps many projects migrating to Caffeine from Guava.

Thanks and keep up the great work!

@ben-manes
Copy link
Owner

Sorry, I haven't had any time this week to think about it. I was hoping Solr would make progress on their broken key equality bug to confirm it was user error, but that seems to have stalled out. I'll try to revisit this over the weekend, but the code simple and easy to copy for local use.

@ben-manes
Copy link
Owner

Released in 3.1.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants