For getting a type's name in Java we call the getTypeName
function on the type's class. For example, this line of code:
System.out.println(String.class.getTypeName());
will print:
java.lang.String
But, when dealing with generic types, the following line of code won't compile (when T
is a generic type):
T.class.getTypeName()
Is there a way for getting a generic type's class (and get the type's name from it)?
For exapmle, if I have the following class:
package tries1;
public class Person {
}
and the following generic class:
class MyGenericClass<T> {
public String getParameterTypeName() {
}
}
the following code:
MyGenericClass<Person> g = new MyGenericClass<>();
System.out.println(g.getParameterTypeName());
should print:
tries1.Person
I don't have the generic type's class (that what I want to get...), or an instance of the generic type (so, I can't call getClass
on an instance).
Any idea?
What I have tried:
Searched for solution in the internet, and didn't find something helpful.
Also tried to use ParameterizedType
as described here: https://farizfadian.blogspot.com/2020/02/get-class-name-from-generic-java-class.html[^]:
class MyGenericClass<T> {
public String getParameterTypeName() {
return ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).
getActualTypeArguments()[0]).getTypeName();
}
}
but, got an exception that says: "class java.lang.Class cannot be cast to class java.lang.reflect.ParameterizedType (java.lang.Class and java.lang.reflect.ParameterizedType are in module java.base of loader 'bootstrap')
".
When I called it from a derived class as follows:
class MyGenericClass<T> {
class MyDerivedFromGeneric extends MyGenericClass<T> {
public String getParameterTypeName() {
return getParameterTypeNameImpl();
}
}
public String getParameterTypeName() {
MyDerivedFromGeneric dg = new MyDerivedFromGeneric();
return dg.getParameterTypeName();
}
protected String getParameterTypeNameImpl() {
return ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).
getActualTypeArguments()[0]).getTypeName();
}
}
I got an exception that says: "class sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to class java.lang.Class (sun.reflect.generics.reflectiveObjects.TypeVariableImpl and java.lang.Class are in module java.base of loader 'bootstrap')
".
When I removed the casting to Class<T>
:
protected String getParameterTypeNameImpl() {
return ((ParameterizedType) getClass().getGenericSuperclass()).
getActualTypeArguments()[0].getTypeName();
}
it prints:
T
(not tries1.Person
as expected.)
Another direction that I've tried is to use reflection on a defined field:
class MyGenericClass<T> {
public T t1;
public String getParameterTypeName() {
try {
var thisClass = getClass();
var t1Field = thisClass.getField("t1");
var t1Type = t1Field.getType();
return t1Type.getTypeName();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
but, it prints:
java.lang.Object
(again, not tries1.Person
as expected.)