I have a class Foo<T, U>
with the following constructor:
public Foo() {
clazz = Class<U>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
What I do in the constructor is getting the class of the argument U
. I need it because I use it for instantiating that class.
The problem is that it doesn't work when I have a subclass of Foo
that isn't a direct sublcass of it. Let me put it with an example.
I have the class Bar<T> extends Foo<T, Class1>
. Here, Class1
is not a variable but a class.
I also have the class Baz extends Bar<Class2>
. Class2
is a class too, not a variable.
The problem is that it fails when I try to instantiate Baz
(Baz -> Bar<Class2> -> Foo<T, Class2>
). I get an ArrayIndexOutOfBoundsException
because getActualTypeArguments()
returns an array containing only the class Class2
(size 1) and I'm trying to get the second element of the array. That's because I'm getting the arguments of Bar<Class2>
, instead of the ones of Foo.
What I want is to modify the Foo constructor some way I can get the class in the paramter U, doesn't matter if the class I instantiate is a direct subclass or not. I think I should can go up in the hierarchy of classes until reach the class Foo, cast it as ParameterizedType and get the arguments, but I couldn't find how.
Any idea?
Thanks in advance.
This is a nice approach -- it is the only way to actually get the generic type information compiled within the Java bytecode. Eveything else in terms of generics in Java is just type erasure. See below what appears to be a working solution. There are four scenarios:
clazz
will be null
)clazz = null
)This is the code (Test.java):
import java.lang.reflect.*;
import java.util.*;
class A<T1, T2>
{
Class<T2> clazz;
A()
{
Type sc = getClass().getGenericSuperclass();
Map<TypeVariable<?>, Class<?>> map = new HashMap<TypeVariable<?>, Class<?>>();
while (sc != null)
{
if (sc instanceof ParameterizedType)
{
ParameterizedType pt = (ParameterizedType) sc;
Type[] ata = pt.getActualTypeArguments();
TypeVariable[] tps = ((Class) pt.getRawType())
.getTypeParameters();
for (int i = 0; i < tps.length; i++)
{
Class<?> value;
if (ata[i] instanceof TypeVariable)
{
value = map.get(ata[i]);
}
else
{
value = (Class) ata[i];
}
map.put(tps[i], value);
}
if (pt.getRawType() == A.class)
{
break;
}
if (ata.length >= 1)
{
sc = ((Class) pt.getRawType()).getGenericSuperclass();
}
}
else
{
sc = ((Class) sc).getGenericSuperclass();
}
}
TypeVariable<?> myVar = A.class.getTypeParameters()[1];
clazz = map.containsKey(myVar) ? (Class<T2>) map.get(myVar) : null;
}
}
class Bar<T> extends A<T, String> {}
class Baz extends Bar<Integer> {}
class A2<T3, T1, T2> extends A<T1, T2> { }
class B<T> extends A2<Long, String, T> { }
class C extends B<Integer> { }
class D extends C { }
class Plain<T1, T2> extends A<T1, T2> {}
public class Test
{
public static void main(String[] args)
{
new D();
new Baz();
new A<String, Integer>();
new Plain<String, Integer>();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With