Context:
There is an Infinispan (13.0.10) cache that uses a custom data type Quad<String, Long, Type, ValidityPeriod>
as key. As far as I can tell all hashCode()
and equals(Object o)
-methods are either auto-generated or implemented correctly.
Also the cache is used in Local Mode.
Question:
When I try to call cache.get(Object key)
with a Quad that I know the cache contains, I get null
. cache.containsKey(Object key)
also returns false
.
How is this possible?
Clarification:
I said that I know the cache contains the Quad
key because I have done the following using the Eclipse IDE debugger:
cache.entrySet().stream().filter(e -> e.getKey().hashCode == Quad.of(a, b, c, d).hashCode()).collect(toList());
// this returns a non-empty list with my expected return
cache.entrySet().stream().filter(e -> e.getKey().equals(Quad.of(a, b, c, d))).collect(toList());
// this returns a non-empty list with my expected return
Per Radim Vansa's suggestion I have also tried the following:
cache.entrySet().stream().collect(Collectors.toMap(Entry::getKey, Entry::getValue, (o1,o2) -> o1, ConcurrentHashMap::new)).get(Quad.of(a, b, c, d));
// this returns my expected return
Further Context (if needed): I am working on an older project where I am supposed to update from Infinispan Version 10 to 13. I have successfully done so and also integrated ProtoStream API instead of using the old JBossMarshaller. This version change is important because the retrieval stopped working after the update.
There are multiple Caches in use, some are indexed using custom data types such as Pair<K, V>
, Triple<L, M, R>
and Quad<A, B, C, D>
which are all generic. I have written some ProtoAdpaters for all of them and they work just fine.
I now have come across a problem, where there is an AdvancedCache that uses a Quad like this as key:
Quad<String, Long, Type, ValidityPeriod>
Quad overrides equals(Object o)
and hashCode
as follows:
public class Quad<A, B, C, D> {
// other code omitted for brevity
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Quad<?, ?, ?, ?>) {
final Quad<?, ?, ?, ?> other = (Quad<?, ?, ?, ?>) obj;
return Objects.equals(getFirst(), other.getFirst())
&& Objects.equals(getSecond(), other.getSecond())
&& Objects.equals(getThird(), other.getThird())
&& Objects.equals(getFourth(), other.getFourth());
}
return false;
}
public int hashCode() {
return Objects.hashCode(getFirst())
^ Objects.hashCode(getSecond())
^ Objects.hashCode(getThird())
^ Objects.hashCode(getFourth());
}
}
For reference Type
is structured along the lines of:
public class Type implements Serializable {
private int fieldA;
private int fieldB;
private String fieldC;
// hashCode and equals are auto-generated
// constructor, getters and setters omitted for brevity
}
ValidityPeriod
is something like this:
public class ValidityPeriod implements Serializable {
private LocalDate validFrom;
private LocalDate invalidFrom;
// hashCode and equals are auto-generated
// constructor, getters and setters omitted for brevity
}
The marshaller for LocalDate
uses the following adapter:
@ProtoAdapter(LocalDate.class)
public class LocalDateAdapter {
@ProtoFactory
LocalDate create(int year, short month, short day) {
return LocalDate.of(year, month, month);
}
@ProtoField(number = 1, required = true)
int getYear(LocalDate localDate) {
return localDate.getYear();
}
@ProtoField(number = 2, required = true)
short getMonth(LocalDate localDate) {
return (short) localDate.getMonth().getValue();
}
@ProtoField(number = 3, required = true)
short getDay(LocalDate localDate) {
return (short) localDate.getDayOfMonth();
}
}
I have tried to use the debugger to understand the internal workings of Infinispan but I don't seem to be able to pin down a concrete line producing this error.
As far as I know it has something to do with CacheImpl.get(Object, long, InvocationContext)
.
Update:
Ok, per Pruivo's suggestion I have tried to create a reprex. The strange thing however is that I have tried to copy every process that happens before the object is retrieved from the cache, but in the reprex I created it works.
Funny thing however is the following I tried:
I created two methods in ValidityPeriod
that do the following (almost like Infinispan Transformers):
public String toFormString() {
return String.format("%s§%s", validFrom, invalidFrom);
}
public static ValidityPeriod fromFormString(String form) {
String[] split = form.split("§");
return from(LocalDate.parse(split[0]),LocalDate.parse(split[1]));
}
Then I've changed the Quad to Quad<String, Long, Type, String>
while constructing the key for the cache with strings from these methods instead of the ValidityPeriod itself. Strangely enough, this fixes my original problem.
However, as this is a dirty fix, I am not content with keeping this solution permanent. There has to be something wrong with ValidityPeriod
is my guess.
I still am confused as to why the cache returns something different than it contains, so I will still leave my original question open.