Not directly, since the weak value can be garbage collected as soon as there are no more strong references to the object. What you could do however is use a ForwardingCache
backed by two separate caches, a weak-value cache and a timed-expiry cache, so that the time-based cache holds a strong reference to the object thereby keeping it in the weak-value cache. It'd look something like this:
public class WeakValuedExpiringCache<K, V> extends ForwardingCache<K, V> {
private final Cache<K, V> expiringCache;
private final Cache<K, V> weakCache;
public WeakValuedExpiringCache(CacheBuilder expiringSpec) {
expiringCache = expiringSpec.build();
weakCache = CacheBuilder.newBuilder().weakValues().build();
}
// weakCache is the canonical cache since it will hold values longer than
// expiration if there remain other strong references
protected Cache<K, V> delagate() {
return weakCache;
}
@override
public V get(K key, Callable<? extends V> valueLoader)
throws ExecutionException {
// repopulate the expiring cache if needed, and update the weak cache
V value = expiringCache.get(key, valueLoader);
weakCache.put(key, value); // don't call super.put() here
}
@Override
public void put(K key, V value) {
expiringCache.put(key, value);
super.put(key, value);
}
// Handle putAll(), cleanUp(), invalidate(), and invalidateAll() similarly
}
You can do the same thing with a ForwardingLoadingCache
as well, just like .get()
above you should load the value from the expiringCache
and .put()
it into the weakCache
in the relevant loading methods.