0

I have got the following scenario were I have class Class<? extends IModel<?>> aCls and collection Collection<? extends IModel<?>> entitiesCollection and trying to pass them to method <T extends IModel<T>> void doIndex(Class<T> clz, Iterable<T> items) , but keep getting compile time exception. I tried wildcard capture and other ways, but no luck. I must be missing something obvious. Will appreciate any advice.

Multimap<Class<? extends IModel<?>>, IModel<?>> entityMultimap = ArrayListMultimap.create();

for (IModel<?> entity  : models) {

      Class<? extends IModel<?>> aCls = entity.getClass();
       entityMultimap.put(aCls, entity);          
    }



for (Class<? extends HasKey<?>> cls : entityMultimap.keySet()) {
   Collection<? extends IModel<?>> entitiesCollection = entityMultimap.get(cls);
        doIndex(cls, entitiesCollection);
}


public static <T extends IModel<T>> void doIndex(Class<T> clz, Iterable<T> items) {

    .....
}

Update: Someone has marked this as duplicate of the other generic wildcard related question. However this is very different case. What we have is

public static <T extends IModel<T>> void doIndex(Class<T> clz, Iterable<T> items) 

where params clz and items based on the same type T. One can use wildcard capture method in case when we have just one parameter. But here we have wildcarded variables cls and entitiesCollection :

 Class<? extends HasKey<?>> cls and
 Collection<? extends IModel<?>> entitiesCollection 

which have the similar relationship as clz and items, but I don't know how to pass them into doIndex.

husayt
  • 14,553
  • 8
  • 53
  • 81
  • what's your compilation errors? – James Jul 06 '14 at 00:03
  • That is the problem I can't even compile it. Error:) java: method doIndexFor in class A cannot be applied to given types; required: java.lang.Class,java.lang.Iterable found: java.lang.Class>,java.util.Collection> reason: no instance(s) of type variable(s) T exist so that argument type java.util.Collection> conforms to formal parameter type java.lang.Iterable – husayt Jul 06 '14 at 00:06

2 Answers2

2

A Foo<? extends IModel<?>> cannot be viewed as a Foo<T extends IModel<T>>. It's not the same. Each of the two ?s is independent and may refer to a different unknown something, but both Ts refer to the same unknown something.

If doIndex had two type parameters T and C in the form: <T,C extends IModel<T>>, you would be able to call it with either the Class parameter or the Iterable parameter, but still not both at once. So this would compile:

static <T,C extends IModel<T>> void doIndex(Class<C> clz, Iterable<C> items) {}
static {
    Class<? extends IModel<?>> cls = null;
    Collection<? extends IModel<?>> entitiesCollection = null;
    doIndex(cls, null);
    doIndex(null, entitiesCollection);
}

But this additional line would not compile:

    doIndex(cls, entitiesCollection);

Why? Same problem as before: the cls's ?s are not necessarily same unknown somethings as the entitiesCollection's ?s.

I don't know if there is a good solution. You might be able to make your call to doIndex work if you use type parameters like <T extends IModel<T>> on the calling methods too, and then use T throughout your code instead of question marks.

If that really cannot be done (which is sometimes the case), and you must use question marks everywhere, it sounds to me like the type parameters are not being useful and should be removed or bypassed. You probably know this, but an unsafe cast to remove the generics would get the job done even using the original method declaration:

static <T extends IModel<T>> void doIndex(Class<T> clz, Iterable<T> items) {}
static {
    Class<? extends IModel<?>> cls = null;
    Collection<? extends IModel<?>> entitiesCollection = null;
    doIndex((Class)cls, (Collection)entitiesCollection); // has a warning, but compiles
}

Or, the constraints on doIndex could be relaxed. This declaration of doIndex makes it work without a warning because it no longer cares if the types are the same:

static void doIndex(Class<? extends IModel<?>> clz, Iterable<? extends IModel<?>> items) {}

The advantage is also the disadvantage: doIndex can no longer ask that the Class and Iterable are compatible with each other. (However, if the iterable is not empty, the method could do a runtime check to see if the objects in it are compatible with the class parameter.)

The fundamental problem is that doIndex is demanding a constraint on the types of the parameters of its arguments, that you do not have the information to fulfill, because all your other type parameters are question marks.

Boann
  • 48,794
  • 16
  • 117
  • 146
0

If you have posted all the source, I could have tried it myself. But now, I can only take a guess. Try:

public static <T extends IModel<?>> void doIndex(Class<T> clz, Iterable<T> items)
James
  • 537
  • 3
  • 11