How to Get the Generic Type at Runtime

Java Generics: Accessing Generic Type at runtime

It is true that generics aren't generally known at runtime in Java, because they are implemented with Type Erasure.

Reflecting Generics?

However, you can stil extract some valuable information about the declared types (NOT the runtime objects' types), as presented in Ian Roberston's article Reflecting Generics and Prenkov's article Java Reflection: Generics.

Background on Generics and Type Erasure

Generics where introduced while conserving backwards compatibility at the source qnd binary level, hence some of their limitation, like:

  • the impossibility to have a short-hand form without at least some indicator for generics support (here, the so-called diamond operator <>),
  • the impossibility to inspect generic-types at runtime, because they had to be implemented with Type Erasure.

Further Reading

  • From The Java Tutorial:

    • section on Generic Types
    • section on Type Inference and Instantiation of Generic Classes
  • From the Java Language Specifications (JLS):

    • Java SE 5's JLS section on Types, Values and Variables
    • Java SE 7's JLS section on Types, Values and Variables
  • From good StackOverflow questions:

    • Java Raw Type and generics interaction
  • Others:

    • IBM Developer Series: Java Theory and Practice: Generics Gotchas (especially the sections The Road Not Taken, Generifying Existing Classes and Implications of Erasure).

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
}
}

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>.

Setting generic type at runtime

You can't. Generic type identifiers have to be known at compile time.

edit

as of other posts, it appears to be possible by dynamicly generating the method and invoking it - which has dangers of course. See Thomas' and Dathan's posts for more inforation.

what is Generic . and how to make possible to get the generic type on runtime

First we explain What is Generic

Generic in Java is one of important feature added in Java 5,

From Oracle's documentation:

Generics were introduced to the Java language to provide tighter type
checks at compile time and to support generic programming. To
implement generics, the Java compiler applies type erasure to:

  • Replace all type parameters in generic types with their bounds or
    Object if the type parameters are unbounded. The produced bytecode,
    therefore, contains only ordinary classes, interfaces, and methods.

  • Insert type casts if necessary to preserve type safety.

  • Generate bridge methods to preserve polymorphism in extended generic types.

Type erasure ensures that no new classes are created for parameterized
types; consequently, generics incur no runtime overhead.

Now how to make possible to get the generic type on runtime, with the help of this link

read: http://www.west-wind.com/weblog/posts/2011/Nov/11/Dynamically-creating-a-Generic-Type-at-Runtime

Get type of generic at runtime in Kotlin

You can achieve this using inline functions with reified types. So you're basically on the right track, but your when statement is checking this (which in your code is an instance of SomeClass<T> against String::class, Char::class, etc. You instead need to compare the class itself.

What I would recommend is to have an internal method which takes in a KClass<T> to switch on, and then a public inline reified function which provides the KClass to the internal method. For example:

@PublishedApi
internal fun <T : Any> SomeClass<T>.defaultSerializer(
clazz: KClass<T>
): KSerializer<T>? = when (clazz) {
String::class -> StringSerializer()
Char::class -> CharSerializer()
Double::class -> DoubleSerializer()
Float::class -> FloatSerializer()
Long::class -> LongSerializer()
Int::class -> IntSerializer()
Short::class -> ShortSerializer()
Byte::class -> ByteSerializer()
Boolean::class -> BooleanSerializer()
Unit::class -> UnitSerializer()
else -> null
} as KSerializer<T>?

inline fun <reified T: Any> SomeClass<T>.defaultSerializer(): KSerializer<T>? =
defaultSerializer(T::class)

Then, given an instance of SomeClass<String> you can just do:

someClassString.defaultSerializer()

The reason for the separate internal and public functions is to avoid inlining the full when block everywhere that it's used.

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);


Related Topics



Leave a reply



Submit