I noticed that many people lean towards the getGenericSuperclass() solution:
class RootGeneric<T> {
public Class<T> persistentClass = (Class<T>)
((ParameterizedType)getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
However, this solution is error prone. It will not work properly if there are generics in the descendants. Consider this:
class Foo<S> extends RootGeneric<Integer> {}
class Bar extends Foo<Double> {}
Which type will Bar.persistentClass have? Class<Integer>? Nope, it will be Class<Double>. This will happen due to getClass() always returns the top most class, which is Bar in this case, and its generic super class is Foo<Double>. Hence, the argument type will be Double.
If you need a reliable solution which doesn't fail I can suggest two.
- Use
Guava. It has a class that was made exactly for this purpose: com.google.common.reflect.TypeToken. It handles all the corner cases just fine and offers some more nice functionality. The downside is an extra dependency. Given you've used this class, your code would look simple and clear, like this:
class RootGeneric<T> {
@SuppressWarnings("unchecked")
public final Class<T> persistentClass = (Class<T>) (new TypeToken<T>(getClass()) {}.getType());
}
- Use the custom method below. It implements a significantly simplified logic similar to the Guava class, mentioned above. However, I'd not guarantee it's error prone. It does solve the problem with the generic descendants though.
abstract class RootGeneric<T> {
@SuppressWarnings("unchecked")
private Class<T> getTypeOfT() {
Class<T> type = null;
Class<?> iter = getClass();
while (iter.getSuperclass() != null) {
Class<?> next = iter.getSuperclass();
if (next != null && next.isAssignableFrom(RootGeneric.class)) {
type =
(Class<T>)
((ParameterizedType) iter.getGenericSuperclass()).getActualTypeArguments()[0];
break;
}
iter = next;
}
if (type == null) {
throw new ClassCastException("Cannot determine type of T");
}
return type;
}
}