3

I use cqengine for collection indexation:

Attribute<UtilizationEntry, LocalDate> startDateAttr = new SimpleAttribute<UtilizationEntry, LocalDate>() {
    @Override
    public LocalDate getValue(UtilizationEntry object, QueryOptions queryOptions) {
        return object.getStartDate();
    }
};
IndexedCollection<UtilizationEntry> entries = new ConcurrentIndexedCollection<>();
entries.addIndex(NavigableIndex.onAttribute(startDateAttr)); // compilation error in this line

This code isn't compiled because:

Error:(61, 70) java: no suitable method found for onAttribute(com.googlecode.cqengine.attribute.Attribute<entities.UtilizationEntry,java.time.LocalDate>)
method com.googlecode.cqengine.index.navigable.NavigableIndex.<A,O>onAttribute(com.googlecode.cqengine.attribute.Attribute<O,A>) is not applicable
  (inferred type does not conform to equality constraint(s)
    inferred: java.time.chrono.ChronoLocalDate
    equality constraints(s): java.time.chrono.ChronoLocalDate,java.time.LocalDate)
method com.googlecode.cqengine.index.navigable.NavigableIndex.<A,O>onAttribute(com.googlecode.cqengine.index.support.Factory<java.util.concurrent.ConcurrentNavigableMap<A,com.googlecode.cqengine.resultset.stored.StoredResultSet<O>>>,com.googlecode.cqengine.index.support.Factory<com.googlecode.cqengine.resultset.stored.StoredResultSet<O>>,com.googlecode.cqengine.attribute.Attribute<O,A>) is not applicable
  (cannot infer type-variable(s) A,O
    (actual and formal argument lists differ in length))

Probably, it's a lack of library design: LocalDate implements ChronoLocalDate that extends Comparable<ChronoLocalDate>, it means that it's necessary to use wildcard bounds in generic method declaration. I guess, creating of LocalDate wrapper that implements Comparable<> is a workaround in this case.

Perhaps, there are some other solutions of this problem?

injecto
  • 829
  • 1
  • 10
  • 23

1 Answers1

5

I think, creating new classes, like a wrapper, is to much overhead for fixing a generic signature error. I’d create a delegation method like

@SuppressWarnings("unchecked")
static <A extends Comparable<A>,O>
               NavigableIndex<A,O> onAttribute(Attribute<O,? extends A> attribute) {
    return NavigableIndex.onAttribute((Attribute)attribute);
}

Actually, the problem lies in the declaration A extends Comparable<A> which should be A extends Comparable<? super A>, however fixing it here wouldn’t help, as this pattern is spread throughout the API and allowing such a return type here would just raise errors at the next API usage. But since, as far as I understood, Attribute only produces As but doesn’t consume them, we can relax the signature here and accept an Attribute<…,? extends A>, following the PECS pattern.

With this helper, your code should compile smoothly:

IndexedCollection<UtilizationEntry> entries = new ConcurrentIndexedCollection<>();
entries.addIndex(onAttribute(startDateAttr));
Community
  • 1
  • 1
Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thanks for a reminder about supression of compiler types restriction -- it saved a lot of memory to me. – injecto Nov 02 '15 at 08:03
  • 1
    Nice answer. I'm the author of CQEngine, I created [issue 45](https://github.com/npgall/cqengine/issues/45) to see if I can improve the API based on this answer in future. – npgall Nov 02 '15 at 18:41
  • I'm also running into this issue, and there also needs to be a solution for greaterThan/lessThan queries which reference Comparable. – jacob Dec 15 '16 at 14:38