0

I have a problem to get the type of a list. The problem is While declaring I'm not specifying the type. I'm setting it only at run time.

I have a POJO class

public class MyObject<T> {

    private String name;
    private List<T> list;

//getter and setter
}

I have followed this SO question and tried my below code

public class ListType {

    public static void main(String[] args) throws NoSuchFieldException, SecurityException {
        ListType listType = new ListType();
    List<Integer> listInt = new ArrayList<Integer>();
    MyObject<Integer> myObjectInt = new MyObject<Integer>();
    myObjectInt.setList(listInt);
    listType.initialize(myObjectInt);

    MyObject<String> myObjectStr = new MyObject<String>();
    List<String> listStr = new ArrayList<String>();
    myObjectStr.setList(listStr);
    listType.initialize(myObjectStr);
    }

    private void initialize(MyObject myObject) throws NoSuchFieldException, SecurityException {
        List list = myObject.getList();
        ListType listType = new ListType();
        listType.getListType(list);
    }

    private void getListType(List list) throws NoSuchFieldException, SecurityException {
        Field stringListField = MyObject.class.getDeclaredField("list");
        ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType();
        Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0];
        System.out.println(stringListClass);
    }

}

Then I am getting following exception

Exception in thread "main" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
    at com.sample.listtype.ListType.getListType(ListType.java:35)
    at com.sample.listtype.ListType.initialize(ListType.java:27)
    at com.sample.listtype.ListType.main(ListType.java:15)

How to get the type if I'm setting at run time?

Community
  • 1
  • 1
iCode
  • 8,892
  • 21
  • 57
  • 91
  • 2
    *But how to get the type if I'm setting at run time?* A List has no type at run time ([erasure](http://docs.oracle.com/javase/tutorial/java/generics/erasure.html)) so the question doesn't really make sense. Better to tell us about what you are actually trying to do. – Radiodef Jan 13 '15 at 08:03

2 Answers2

2

I don't think that what you want to achieve is possible. However, a little change to the code can do the trick:

public class MyObject {
    private List<?> list;
    private Class<?> type;

    public <T> void setList(List<T> list, Class<T> c) {
        this.list = list;
        this.type = c;
    }

    public List<?> getList() {
        return list;
    }

    public Class<?> getType() {
        return type;
    }
}

Example code:

public static void main(String[] args) throws NoSuchFieldException,
        SecurityException {
    List<Integer> list = new ArrayList<Integer>();
    MyObject myObject = new MyObject();
    myObject.setList(list, Integer.class);

    System.out.println(myObject.getType());
}

Output:

class java.lang.Integer
Niels Billen
  • 2,189
  • 11
  • 12
  • 2
    Maybe making the whole `MyObject` class generic would be an option for OP too. It would not avoid the extra parameter because of type erasure, but would introduce a little more type safety. – André Stannek Jan 13 '15 at 08:31
  • Hi, I have edited the code. Please check. Now is there anyway how can I get the type? – iCode Jan 13 '15 at 08:39
  • @AndreStannek indeed making MyObject a generic class would be a lot safer, but then it would be possible to set the list to any type. I.e. MyObject can not set any lists of Double, and I guess that this functionality is necessary from the question. – Niels Billen Jan 13 '15 at 08:44
  • @iProgrammer, you get the type by calling the getType() method of MyObject as shown in the example. – Niels Billen Jan 13 '15 at 08:45
  • `MyObject myObjectInt = new MyObject();` I'm doing this. So why I need to declare a separate vairable and set and get through methods? – iCode Jan 13 '15 at 08:49
  • @iProgrammer it's because of type erasure. There is no generic type information at runtime. – André Stannek Jan 13 '15 at 09:01
1

The method getGenericType() has the return type Type which, amongst others, can be Class or ParameterizedType. It makes sense to me that it wouldn't return ParameterizedType if invoked on a field which has no parameterized type. It seems to return Class in this case. The javadoc is a little inconclusive on this one.

As for your question on how to get the actual type at runtime: Generic type information is erased at runtime. It is only used to ensure type safety at compile time. When you assign an object with the actual type ArrayList<Integer> to a variable with the static type List, you can't get the generic type of the actual object at runtime. What you could do is check the type of the objects contained in the list:

Class<?> foo = list.get(0).getClass();
André Stannek
  • 7,773
  • 31
  • 52