ClassCastException when trying to get the generic class type

I tried using the code provided in this answer . I did this:

public class ListClass<T> {
  private class ObjectFactory<T> {
    //This should the the class of generic type T which is what I need
    public final Class<T> cls;
    @SuppressWarnings ("unchecked")
    public ObjectFactory()
    {
      //This three lines are from the linked answer - I don't really understand them
      Type type = getClass().getGenericSuperclass();
      ParameterizedType paramType = (ParameterizedType) type; //java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
      cls = (Class<T>) paramType.getActualTypeArguments()[0]; 
    }
    public T createNew(... some parameters ...) {
      return (T)new Expression(cls, "new", new Object[]{... some parameters ...}).getValue();
    }
  }
  public final ObjectFactory<T> factory = new ObjectFactory<T>();

  public generateItem() {
    //let add() be method that adds item of type T to this list
    this.add(factory.createNew(... some parameters ...));
  }
}

      

How am I wrong?

+3


source to share


2 answers


This method only works if the class is parameterized with a specific argument like this:

class Sub extends Super<String> {}

      

And then by extension:

new Super<String>() {}

      

But not like this:

class Sub<T> extends Super<T> {}

      

And not like this:

<T> Super<T> m() {
    return new Super<T>() {};
}

      

Usability getActualTypeArguments

is a property of a class, not an instance, so this class needs actual type arguments.




In your edit, what I recommend doing is creating a helper routine for this:

static <T> Class<T> getActualTypeArgument(Class<?> clazz, int i) {
    Type superclazz = getClass().getGenericSuperclass();
    ParameterizedType paramType = (ParameterizedType) superclazz;

    @SuppressWarnings("unchecked")
    final Class<T> actual =
        (Class<T>) paramType.getActualTypeArguments()[i];
    return actual;
}

      

Then use this on ListClass

:

class ListClass<T> {
    private ObjectFactory<T> factory = new ObjectFactory<T>(
        getActualTypeArgument(this.getClass(), 0));
}

      

And create ListClass

for example. in the following way:

ListClass<GameObject> list =
    new ListClass<GameObject>() {};

      

Consider also simply passing Class<T>

to:

class ListClass<T> {
    private ObjectFactory<T> factory;

    ListClass<T>(Class<T> type) {
        factory = new ObjectFactory(type);
    }

    static <T> ListClass<T> of(Class<T> type) {
        return new ListClass<T>(type);
    }
}

ListClass<GameObject> list =
    ListClass.of(GameObject.class);

      

+3


source


Citing docs on Class#getGenericSuperClass()

:

Corresponds to the type for the class that represents the superclass of the receiver class. For classes that represent base types, interfaces, and for java.lang.Object, the method is null.



Calling this class ObjectFactory<T>

will return a type Object

that is not ParameterizedType

.

+2


source







All Articles