Netto
Netto

Reputation: 284

JAVA - Get generic implementation of a class

Imagine I have an abstract class defining a Generic Type. All subclasses will implement this Generic Type.

I can achive so by declaring a abstract method that forces the subclass to return that type. But is there a more elegant way to achieve this directly from the 'Class' object definition of the subclass?

public class GenericTest {
    public static void main(String[]args) throws Exception{
        Class strClass = ClazzImplString.class;
        Class intClass = ClazzImplInteger.class;

        Class implTypeStr = ((AbsClazz)strClass.getConstructor().newInstance()).getGenericType();
        Class implTypeInt = ((AbsClazz)intClass.getConstructor().newInstance()).getGenericType();

        System.out.println("implTypeStr: " + implTypeStr);
        System.out.println("implTypeInt: " + implTypeInt);
    } 
}
abstract class AbsClazz<GenericType> {
    abstract Class getGenericType();
}

class ClazzImplString extends AbsClazz<String> {
    public ClazzImplString() {}    
    @Override  Class getGenericType() {return String.class;}
}
class ClazzImplInteger extends AbsClazz<Integer> {
    public ClazzImplInteger() {}    
    @Override Class getGenericType() {return Integer.class;}
}

Thank you in advance

Upvotes: 4

Views: 241

Answers (4)

Konstantin Yovkov
Konstantin Yovkov

Reputation: 62864

You can set the return type for your abstract method to be the Class, parametrized with the generic type:

abstract class AbsClazz<T> {
    abstract Class<T> getGenericType();
}

Then, in your subclasses, you will be forced to implement a method, that returns the type provided in the class definition. For example:

class ClazzImplString extends AbsClazz<String> {
    public ClazzImplString() {}    
    @Override Class<String> getGenericType() {return String.class;}
}

Upvotes: 5

Bruno Ribeiro
Bruno Ribeiro

Reputation: 6197

You can avoid the getGenericType on each subtype getting ParameterizedType from subtypes.

An example look like this:

public abstract class AbsClazz<E extends Serializable> { }

public class ClazzImplInteger extends AbsClazz<Integer> { }

public class ClazzImplString extends AbsClazz<String> { }

public class GenericTest {

    public static void main(String[] args) {
        System.out.println("implTypeStr: " + getTypeFromGenericClass(ClazzImplString.class, 0));
        System.out.println("implTypeInt: " + getTypeFromGenericClass(ClazzImplInteger.class, 0));
    }

    public static Class<?> getTypeFromGenericClass(final Class<?> genericType, final Integer index) {
        final ParameterizedType type = (ParameterizedType) genericType.getGenericSuperclass();
        return (Class<?>) type.getActualTypeArguments()[index];
    }

}

This example will print:

implTypeStr: class java.lang.String
implTypeInt: class java.lang.Integer

Upvotes: 1

MightyPork
MightyPork

Reputation: 18861

Here is one crazy hack with reflection:

import java.lang.reflect.ParameterizedType;

class GenericClazz<T> {
    public Class<T> getType() {
        return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }
}

(source - one of my old projects: link)

Upvotes: 2

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279930

Yes, you can use reflection.

ParameterizedType genericSuperclass = (ParameterizedType) ClazzImplString.class.getGenericSuperclass();
Class<?> clazz = (Class<?>) genericSuperclass.getActualTypeArguments()[0];
System.out.println(clazz); // prints class java.lang.String

Upvotes: 5

Related Questions