I am having an issue with generics and what I presume is type erasure whilst trying to reflect some generic information.
I am using a class based on http://www.artima.com/weblogs/viewpost.jsp?thread=208860 to do the reflection, but that isn't the issue.
The code below demonstrates the issue:
private <U extends MyClass1> U doSomething(MyClass2<U> p) {
Class<U> classIWant = null;
for (Class<?> c : GenericTypeUtils.getTypeArguments(MyClass2.class, p.getClass())) {
if (MyClass1.class.isAssignableFrom(c)) {
classIWant = c.asSubclass(MyClass1.class);
break;
}
}
}
Unfortunately the line
classIWant = c.asSubclass(MyClass1.class);
Shows the following error
java: incompatible types
required: java.lang.Class<U>
found: java.lang.Class<capture#4 of ? extends MyClass1>
And that's really confusing me. U extends MyClass1 and therefore U is a MyClass1.
Obviously there is some piece of type erasure I am not understanding here - can anybody help, please. BTW this is Java 1.7.0_40
Thanks
Conrad Winchester
The method asSubclass() is implemented like so
public <U> Class<? extends U> asSubclass(Class<U> clazz) {
if (clazz.isAssignableFrom(this))
return (Class<? extends U>) this;
else
throw new ClassCastException(this.toString());
}
with a return type of Class<? extends U>. Note, that your U and the U in the asSubclass method are completely unrelated type variables.
So the method asSubclass() returns a value declared with the type Class of some unknown subtype of U, where U in this case is MyClass1.
You are trying to assign this value to a variable of type Class with some known subtype of MyClass1. The compiler can't guarantee that they match and therefore doesn't allow compilation.
You can cast the returned value if you wish, but may end up getting ClassCastException at runtime, if the types don't match.
The Java compiler is unable to guarantee that the Class object c matches the generic type U. Because of type erasure, it is up to the compiler to guarantee type safety, and ensure that the Class coming back from c.asSubclass matches Class<U>, but it can't.
The asSubclass method returns a Class<? extends U>. In the Class class, U represents the type of Class passed into asSubclass. When you call it, that is c. But the compiler cannot guarantee that this return type matches your own declared <U extends MyClass1>. They could be different subclasses of MyClass1.
If you can guarantee that c.asSubclass will return a Class<U>, then cast it as a Class<U>:
classIWant = (Class<U>) c.asSubclass(MyClass1.class);
You will receive an "unchecked cast" warning. This is there because the compiler cannot guarantee that is really is a Class<U>, but you are saying that it is. Be careful as this may result in a hard-to-track-down ClassCastException elsewhere, even after you return the U. Do this only if you can guarantee the type safety yourself.
Related
I have following two classes:
class ProblematicConverter implements Converter<List<?>> {};
class NonProblematicConverter implements Converter<List> {};
And method of class Utils:
<T> void addConverter(Class<? extends T> cls, Converter<T> converter);
Now, first function invocation is ok but second produces error:
addConverter(List.class, new ProblematicConverter());
addConverter(List.class, new NonProblematicConverter());
Error says:
"The method addConverter(Class, Converter) in the type Utils is not applicable for the arguments (Class, ProblematicConverter)"
I do not understand why it's like that.
Based on your comment, I think the right thing to do here might be to use an unchecked cast on List.class, but first, the reason the code in the question doesn't compile is roughly:
T of addConverter is inferred to be List<?>.
The bounded wildcard in cls requires that its type argument be T or a subtype of T, but the raw type List is a supertype of List<?> (specified here).
Therefore, Class<List> is incompatible with the inferred type of cls which is Class<? extends List<?>>.
So, for example, either of the following two declarations would compile with the invocations in the question:
<T> void m(Class<T> cls, Converter<? extends T> converter) {}
<T> void m(Class<? super T> cls, Converter<T> converter) {}
That of course doesn't help you out, but it illustrates the relationship between List and List<?>.
You might see also these two answers of mine which discuss similar situations.
So anyway, based on your comment saying that you're trying to eliminate raw types and can't change the declaration of addConverter, what could be appropriate is to use an unchecked cast from Class<List> to Class<List<?>>:
#SuppressWarnings("unchecked")
static final Class<List<?>> WILD_LIST =
(Class<List<?>>) (Class<? super List<?>>) List.class;
This will let you call e.g.:
addConverter(WILD_LIST, new ProblematicConverter());
However, I'd like to point out that unchecked casting is not a general solution. It's a solution to this specific problem of converting e.g. a Class<GenericType> to a Class<GenericType<?>>. It's safe to do because GenericType<?> is a more restrictive type than the raw type GenericType and because Class has a very limited range of things it can do with its type argument.
If you could change the declaration of addConverter, I think I would recommend using something like Guava TypeToken instead of Class, because then you don't have this sort of problem.
The following types do not produce any compiler warnings:
public abstract Class<? extends BaseType> getSubclassType();
#Override
public Class<SubType> getSubclassType() {
return SubType.class;
}
The following concrete method produces an unchecked cast compiler warning:
public abstract <T extends BaseType> Class<T> getSubclassType();
#Override
public <T extends BaseType> Class<T> getSubclassType() {
return (Class<T>) SubType.class;
}
Is there any way to define the method with a generic type parameter (in the base class) and return the appropriate concrete type in the subclass without generating compiler warnings? Obviously, both examples that I've given above will work just fine, I just want to know if there is a more correct way to define the method. Note: I do know that I could do the following:
public abstract class BaseClass <T extends BaseType>
public abstract Class<T> getSubclassType();
I am wondering if there is a way to define the method header itself, with a generic type, without defining it on the class. And also, I am curious why the wildcard declaration does not give and warnings but the "equivalent" generic declaration does.
The two are very different.
In the first one, the caller does not know what the type argument of the Class that is returned is. The caller cannot make any assumptions about what that type argument is, other than it extends BaseType. The method can choose to return a Class whose type argument is any subtype of BaseType it wants, unknown to the caller.
In the second case, the method is a generic method and T is a type variable of the method. That means that the caller can choose T to be whatever it wants, and expect the method to magically work with T being that type. Notably, the method does not receive any arguments, which means the method does not have any information at runtime regarding what T is at all, and must nevertheless somehow figure out how to return a Class<T>. Obviously, this is impossible, unless it always returns null.
<D extends com.j256.ormlite.dao.Dao<T,?>,T> D getDao(Class<T> clazz)
I am not able to understand above statement
getDao(Class clazz) returns D
D having following constraints
D extends com.j256.ormlite.dao.Dao<T,?>
and extra ,T i am not able to understand.
Could you please explain it ?
This method has two type parameters, D and T, with D having an additional extends constraint, depending on T. Don't get confused by this <T,?>,T syntax; the ,T does not belong to the constraint, but is the second parameter, telling Java that T is not the name of a concrete class.
If you add a space or swap the parameters, it will be clearer. Here's a similar, but somewhat simpler example. These method signatures are all equivalent:
<D extends List<T>,T> D createListOf(Class<T> clazz) // your version
<D extends List<T>, T> D createListOf(Class<T> clazz) // extra space
<T, D extends List<T>> D createListOf(Class<T> clazz) // different order
Keep in mind that, even though it may seem apparent that T is another type parameter, this is not clear to Java. There could be an actual class named T, so we have to be explicit that T is a type parameter.
class T { ... } // this T is not what I want!
Conversely, type parameters are not restricted to single characters. You could also have a type parameter called Foo, or even String, if you want to utterly confuse your co-workers. Maybe that makes clear why the declaration of all type parameters using <...> is necessary.
// just a deterrent example; don't do this! String as parameter, not class
<String, Foo extends List<String>> Foo createListOf(Class<String> clazz)
This method will:
Return an object of type D
Where D is or extends com.j256.ormlite.dao.Dao, parametrized with an object of type T or extending/implementing T and an unknown type parameter
If given as argument a class of type T
It uses a lot of generic abstraction, which is not surprising given it delivers a DAO (Data Access Object).
I am trying to understand this method signature:
public final <T> FluentIterable<T> transform(Function<? super E,T> function)
(taken from http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/FluentIterable.html#transform%28com.google.common.base.Function%29)
I understand that transform returns a FluentIterable<T>, but I don't understand what the <T> before FluentIterable<T> means?
Further, in Function<? super E,T>, I understand what ? super E means, but I can't imagine how the compiler can check this - isn't E unknown at compile time, so how shall the compiler know, if ? is a supertype of E?
<T> means that this is a method with the generic type parameter T. This is similiar to <T> after a class name (like List<T>), just for methods.
E is not unknown at compile time. E is also a generic type parameter defined in the class definition:
public abstract class FluentIterable<E> extends Object implements Iterable<E>
When you create an instance of this class the compiler knows the type of E.
i've got this code:
public <T extends Scrapper> Class<T> getScrapper() {
return MyScrapper.class;
}
MyScrapper is a class implementing Scrapper interface. Why is this not working? U'm getting the following error in JDK7:
error: incompatible types
required: Class<T>
found: Class<MyScrapper>
where T is a type-variable:
T extends Scrapper declared in method <T>getScrapper()
P.S.
I've honestly tried searching for whole 30-40 minutes.
Update:
if i declare the method as public Class<? extends Scrapper> getScrapper() { it works. but I still don't understand why the original declaration was not compiling. what's wrong with it?
With a generic method like getScrapper(), the caller of the method determines what the actual type argument to the method is (T in this case). The caller could pick any subtype of Scrapper as T, and your method (which always returns MyScrapper.class) would not be returning the correct class.
Given the signature of the method, the caller of this method would expect to be able to do this:
Class<MyOtherScrapper> c = foo.<MyOtherScrapper>getScrapper();
Changing the method to return Class<? extends Scrapper> makes it no longer a generic method... there are no type parameters for the caller to set. Instead, the signature says that the method returns the class object for some unknown subtype of Scrapper, and MyScrapper.class does fit the bill for that.