Say I have these classes:
class Container<T> {
private List<T> list;
}
And I have an instance of Container
, say
Container<?> instance = new Container<String>();
Is there a way to find out list
's actual type parameter at run-time? I.e., that it's a List
of String
, rather than a List
of java.lang.reflect.TypeVariable
.
I've been looking at Java's reflection (field.getGenericType()
), various libraries (Guava Reflect, Typetools, ClassMate, even ASM, etc.) but I can't figure it out.
I have no control over the Container
type, so I can't add any fields to it.
I realize it may not be possible at all due to erasure, although I don't mind messing with bytecode if that makes it possible.
EDIT I over-simplified my initial question. I have an additional piece of information available; I also have this type:
class StringContainerContainer {
private Container<String> container;
}
(And several more types like it, for different generic parameters.)
At run-time, I'm given the instance
object mentioned above. With a little refactoring of my codebase, I can also get to the StringContainerContainer
class (or whichever *ContainerContainer
class is relevant), which I can use to get a java.lang.reflect.Field
for container
.
With your edit, yes, you can find out that String
is the actual type parameter:
Field field = StringContainerContainer.class.getDeclaredField("container");
ParameterizedType gt = (ParameterizedType) field.getGenericType();
Class<?> arg = (Class<?>) gt.getActualTypeArguments()[0];
System.out.println(arg);
I should point out that this identifies the type argument of the container
field of StringContainerContainer
. Given how Container
is written, that also happens to be the type argument of its list
field, but that field isn't directly examined.