Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Guava's TypeToken.isAssignableFrom method

I am using the Guava TypeToken class to test if instances of an arbitrary type can be assigned to objects of other type.

In the following code snippet, I am testing if types declared as List are assignable from List<String>, and viceversa:

TypeToken rawListType = new TypeToken<List>(){};
TypeToken parameterizedListType = new TypeToken<List<String>>(){};
System.out.println(rawListType.isAssignableFrom(parameterizedListType)); //true
System.out.println(parameterizedListType.isAssignableFrom(rawListType)); //false

Why the second call to isAssignableFrom returns false ?, given that the code below does compile, so I can assign List<String> from List (with a warning) ?:

List l = null;
List<String> l2 = null;
l = l2; 
l2 = l; //Type Safety Warning 

My intuition is that Guava is answering if instances of these types are assignable without warnings (?). If that is correct, how could I check for assignability in the sense of the compiler allowing me to assign an object to another one (with or without warnings), like it is shown in the second code snippet ?.

like image 458
Sergio Avatar asked Feb 24 '13 18:02

Sergio


1 Answers

As you said, we know the compiler will allow a generic type to be assigned from a raw type, but that doesn't mean assignability. The compiler is doing an implicit unchecked cast (hence the warning).

Since you really want to check assignability of the corresponding raw types, you could just use TypeToken.getRawType and then use Class.isAssignableFrom.

EDIT: As you pointed out, this methodology would count List<Integer> and List<String> assignable to and from each other. To avoid that I think you need a more generalized solution:

boolean checkRawAssignability(TypeToken<?> assigned, TypeToken<?> from) {

    //if from is a raw type, compare raw types instead
    final Type fromType = from.getType();
    if (fromType instanceof Class<?>) {
        return assigned.getRawType().isAssignableFrom((Class<?>)fromType);
    }

    //otherwise use normal methodology
    return assigned.isAssignableFrom(from);
}

Note that this solution does not consider array types.

like image 61
Paul Bellora Avatar answered Nov 15 '22 01:11

Paul Bellora