Click here to Skip to main content
15,868,141 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:

For getting a type's name in Java we call the getTypeName function on the type's class. For example, this line of code:

Java
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):

Java
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:

Java
package tries1;

public class Person {
    // ...
}

and the following generic class:

Java
class MyGenericClass<T> {
    public String getParameterTypeName() {
        // Here is the place where we should get the generic type (T) name.
    }
}

the following code:

Java
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[^]:

Java
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:

Java
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>:

Java
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:

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

Posted
Updated 19-Jun-22 19:43pm
v5
Comments
Richard MacCutchan 15-Jun-22 11:17am    
If you get an error in some code that you wrote then you need to show the code as well as the error details.
Shmuel Zang 15-Jun-22 12:22pm    
Added the code that throws the exception.
Richard MacCutchan 15-Jun-22 12:29pm    
The getClass() and getGenericSuperclass() methods return a class reference. You cannot cast a class to a ParameterizedType, as the two are completely different animals. See Class (Java Platform SE 8 )[^] for allowable options.
Shmuel Zang 15-Jun-22 17:08pm    
Yes, this is one of the not working examples that I've found in my search. What I asked here is for a working example.
Richard MacCutchan 16-Jun-22 4:00am    
This forum is for technical questions, not to provide free code samples. If you want working code then study the documentation, or use Google.

Due to type erasure, the compiler replaces the generic type (T) with its first bound (Object in our case). Therefore, when I tried to get the type of the defined generic field, I got Object (and not Person as I expected).

So, it looks like it's impossible to get the actual type of a generic parameter only from its generic declaration. If we want the actual type of a generic parameter, we should inject it to the class in another way (e.g. constructor parameter, abstract function that returns the actual type, etc...).

 
Share this answer
 
v2
I think you will find that these calls will only work on an actual object of a generated class. At compile time the T prefix does not have a value, it is just a marker for the compiler. See Class (Java Platform SE 8 )[^] for the available options.
 
Share this answer
 
Comments
Shmuel Zang 15-Jun-22 12:26pm    
I know that T.class won't work (also wrote it in the question). I asked if there is another way that I can use for getting the class of T.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900