Get Generic Type of Class At Runtime

How do I get a class instance of generic type T?

The short answer is, that there is no way to find out the runtime type of generic type parameters in Java. I suggest reading the chapter about type erasure in the Java Tutorial for more details.

A popular solution to this is to pass the Class of the type parameter into the constructor of the generic type, e.g.

class Foo<T> {
final Class<T> typeParameterClass;

public Foo(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}

public void bar() {
// you can access the typeParameterClass here and do whatever you like
}
}

Get generic type of class at runtime is not working

I have tried all possible way to get class of generic type.

This way that you found here is not working to retrieve the generic :

public Reader() {
clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}

because it retrieves statically the parameterized type defined in the immediate superclass of Reader, that in this case is Object.

Moving this code in the subclass constructor will not work either :

public ExcelReader() {
clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}

as it retrieves statically the parameterized type defined in the Reader class, that is T. As T doesn't have any bound, you will still get the Object class as returned class.

Which solution to apply in your case ?

Generics are erased after compilation. So to be aware that the parameterized type information used at runtime is Test here :

Reader<Test> reader = new ExcelReader<>();

you have to explicitly "pass" the Class representing the generic in your actual code.

To do that, add in the constructor a Class parameter representing the generic type and store it in a field. Now you have a way to refer the type at runtime.

public class ExcelReader<T> extends Reader<T> implements RowColumnReader<T> {

private Class<T> genericType;

public ExcelReader(Class<T> genericType){
this.genericType = genericType;
}
/*...*/
}

Now you can instantiate ExcelReader in this way :

ExcelReader<Test> excelReader = new ExcelReader<>(Test.class);

Get generic type of class at runtime with Python 3.6

I have figured out how to do it. For some reason, __orig_bases__ wasn't working but after rebuilding my Python 3.6 and using a VENV, it works. This is the final working method:

py_version = sys.version_info
if py_version >= (3, 8):
from typing import get_args


def get_generic_type_arg(cls):
t = cls.__orig_bases__[0]
if py_version >= (3, 8):
return get_args(t)[0]
else:
return t.__args__[0]

Python 3.6 also requires to install dataclasses as a library though it wasn't part of this issue. Also note that __args__ seems to be undocumented in Python 3.6 and removed from Python 3.8.

Get generic type of a class extends from a none generic type class

When I run (ParameterizedType)getClass().getGenericSuperclass(),
expect to be T, but it's PropertyEditorSupport, and can't be casted to
ParameterizedType;

If you want to have access to the T aka the type-parameter, the appropriate reflection method is Class.getTypeParameters.

// Test.java:
class Generic<T> {
}

class Main {

public static void main(String[] args) {

final Generic<Integer> gint1 = new Generic<Integer>();

System.err.println("gint1's type-parameter: "
+ gint1.getClass().getTypeParameters()[0]);
}
}

If you run the code above you get the following:

$ javac Test.java
$ java Main
gint1's type-parameter: T

Notice that the type parameter is not resolved as Integer but as T since this information in not available at run-time.

If access to this information is important for you, then you have two straight forward options.

A. the object contains a reference to the actual type class:

class Generic<T> {

public final Class<T> type;

public Generic(Class<T> type) {
this.type = type;
}

public Class<T> type() {
return type;
}
}

class Main {
public static void main(String[] args) {

final Generic<Integer> gint2 = new Generic<>(Integer.class);
System.err.println("gint2's type-parameter: " + gint2.type().getSimpleName());
}
}
// Output will be "gint2's type-parameter: Integer".

B. You create a subclass that gives a concrete class for that type-parameter:

import java.lang.reflect.*;

class Generic<T> {
}

class IntegerGeneric extends Generic<Integer> {
}

class Main {
public static void main(String[] args) {

final Generic<Integer> gint3 = new IntegerGeneric();
final Generic<Double> gint4 = new Generic<Double>() {};
System.err.println("gint3's type-parameter: "
+ ((ParameterizedType)gint3.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
System.err.println("gint4's type-parameter: "
+ ((ParameterizedType)gint4.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
}
// Output:
// gint3's type-parameter: class java.lang.Integer
// gint4's type-parameter: class java.lang.Double

Notice that gint4 class is not Generic<Double> but at anonymous inner class that extends it due to the {} following the constructor... this is an alternative to a full class DoubleGeneric ... declaration.

Of these two alternatives, A. and B., A. is preferable as in general one should avoid to rely on reflection; amongst other things it is more prone to hide run-time errors and the code is more difficult to maintain.

I want to know what's the different when use
(ParameterizedType)getClass().getGenericSuperclass() with a class has
a none generic type super class.

If you look-up the Type documentation, the class of the reference returned by this methods, it indicates that it is an "umbrella" super-interface for all object/data types available in the Java language including even primitives ... so for a class that does not have a generic superclass I guess it would return a subclass of type that reflect that...

A quick experiment reveals that in fact it would return a 'Class' object so it would be equivalent to to getSuperclass().

Perhaps others can give a more informed perspective on this, but I think this might have been a bit of a misnaming ... I think getSuperType() or something like that would have been more appropriate. Perhaps initially it only supported generics in an older Java version (1.5?) and eventually was extended to cover other data types but this is a wild guess of mine without looking into its history.

Instantiate generic class using runtime class of an object

Because of runtime type erasure, the runtime object created by MyClass<X> and MyClass<Y> will be identical. The fact that new MyClass<X>().myMethod() can be called on an X but not on a Y is a compile-time fact, not a run-time one. The compile-time question is "can it be called on this variable", not "can it be called on objects with the same result of getClass()".

You can create factory methods to create generic instances of your class based on the compile-time types of Class objects, or of the actual objects you wish to use it with:

public class MyClass<T> {
// ...

public static <T> MyClass<T> forClass(Class<T> c) {
return new MyClass<T>();
}

public static <T> MyClass<T> forObject(T object) {
return new MyClass<T>();
}
}

If you want your generic class's method to actually have runtime type checking, that's possible, too. Just store a Class object for the type in your MyClass instance, and use its isInstance() or cast() method to check the type of the argument to your method. You have to do this manually, because this is not what is usually done for ordinary generic classes, which is because it is usually unnecessary.

Get Class-object representation of generic parameter in Java

The reason why

Class<T> persistentClass = (Class<T>)
((ParameterizedType)getClass().getGenericSuperclass())
.getActualTypeArguments()[0];

works was because the superclass of this happens to be a class with a parameterised type as its superclass. Therefore you can get the actual type arguments of that type. The type parameters of superclasses are stored as metadata in the class file if you write them in the source file.

However, in your case, whatever is passed to the onCatch parameter is not going to have a superclass of Consumer<T>. After all, Consumer<T> is not a class! You need to use getGenericInterfaces and find the one that has the name that starts with java.util.function.Consumer.

System.out.println(
// I've assumed the Consumer interface is the first one, to keep it brief
((ParameterizedType)onCatch.getClass().getGenericInterfaces()[0])
.getActualTypeArguments()[0]
);

This would work if the caller calls onCatch like this:

onCatch(new Consumer<RuntimeException>() {
@Override
public void accept(RuntimeException e) {

}
});

The anonymous class will implement Consumer<RuntimeException>, and this information will be written to the class file representing the anonymous class.

However, if you use a lambda:

onCatch((RuntimeException e) -> {});

Then only a method like this is generated in the same class as the caller:

private static void lambda$caller$0(RuntimeException e) {

}

and at runtime, invokedynamic is used to create an instance that implements Consumer, and this is the bad news: the type parameter RuntimeException is not part of the generated class for this instance, for whatever reason.

The only way you can find RuntimeException now then, is if you somehow know who the caller is, and find the lambda$caller$0 method, and look at its parameter.

That said, everything I've wrote so far is pretty much all implementation detail, and I wouldn't use any of that in production code. I would say you should just add a Class<E> parameter:

onCatch(RuntimeException.class, e -> {});

It doesn't look that different on the caller's side anyway.

Java: How can I get generic type in runtime?

You cannot. At runtime, Java doesn't even know the actual generic type.

If the Optional is present, you can do optional.get().getClass(), but if the optional is absent there is absolutely no way to tell whether it is an Optional<String>, Optional<Integer>, or Optional<NuclearMissile>.



Related Topics



Leave a reply



Submit