Sergio
Sergio

Reputation: 8670

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 ?.

Upvotes: 6

Views: 1633

Answers (1)

Paul Bellora
Paul Bellora

Reputation: 55233

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.

Upvotes: 3

Related Questions