Simply, I have to override the way in which the cache chooses the right key because some fields (e.g., timestamp, message id, etc.) shouldn't be considered when retrieving a key.
I cannot modify the actual hash function of the key object because it is already used to recognize in my code.
Is it possibile with Guava Caches? And with a workaround?
This is my configuration:
CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).recordStats().
expireAfterWrite(DEFAULT_AGE, TimeUnit.DAYS).build(
new CacheLoader<Request, Response>() {
@Override
public Response load(Request request) {
return request.getResponse();
}
});
And this is my hash function (used somewhere else in my code):
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + code;
result = prime * result + messageID; // <= **this one shouldn't evaluated**
result = prime * result + Arrays.hashCode(payload);
result = prime * result + (int) (timestamp ^ timestamp >>> 32); // <= **this one shouldn't evaluated**
result = prime * result + (type == null ? 0 : type.hashCode());
result = prime * result + version;
return result;
}
Btw, is this kind of cache using its own implementation of hash function (e.g., through introspection) or is it using the default one?
** EDIT: **
As pointed out in the responses, the best way to achieve this result is a wrapper class.
My solution:
/**
* Nested class to store a request as a key in the cache. It is needed to
* normalize the variable fields of the normal requests.
*/
private static final class CachedRequest extends Request {
private static CachedRequest fromRequest(Request request) {
// set only the fields that cannot change between two same requests
// ...
}
@Override
public int hashCode() {
HashFunction hashFunction = Hashing.md5();
HashCode hashCode;
// ...
return hashCode.asInt();
}
@Override
public boolean equals(Object obj) {
// coherent with hashCode()
// ...
}
}
Guava - Caching Utilities. Guava provides a very powerful memory based caching mechanism by an interface LoadingCache<K,V>. Values are automatically loaded in the cache and it provides many utility methods useful for caching needs.
By default, Guava Cache will throw exceptions if you try to load a null value – as it doesn't make any sense to cache a null. But if null value means something in your code, then you can make good use of the Optional class as in the following example: 7.
The Object class defines both the equals () and hashCode () methods – which means that these two methods are implicitly defined in every Java class, including the ones we create: We would expect income.equals (expenses) to return true.
When an object (Say a String "John") is added to the HashMap with a key (Say '1') using the put () method, So, the HashCode is calculated based on the key (i.e. '1' ).
You could simply wrap your Request
objects into CachedRequest
objects, where CachedRequest
would implement hashCode()
and equals()
based on the desired fields, and provide access to the wrapped Request
.
I'm pretty sure, it's not possible with Guava. There are some legitimate cases for using a custom Equivalence, but they say they're too rare to be handled by the CacheBuilder
and MapMaker
.1 There's even com.google.common.base.Equivalence
, but it gets used only internally (see also here and here).
You need to make you own key out of the fields you want to use for the lookup, or wrap your Request
in another object defining equals
and hashCode
the way you want.
1The only case when something different from the default equals
/hashCode
gets used is with weakKeys
(softKeys
exists no more), and then it's the ==
/System.identityHashCode
combo. In no case you can choose the equivalence freely.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With