2010-03-09

Java: Getting Parameter Type of Generic Collections

// in reply to yesterday's discussion & memo for myself

In Java 5.0 generic type parameterization were introduced, mainly to help programmers produce a more type-safe code. So, if in Java 1.4.2 and older you'd say

List l = new ArrayList()


in Java 5.0 and newer you're encouraged to specify list parameters:

List<String> l = new ArrayList<String>()


However, load of legacy code exists today that is not changed yet and is unlikely to be changed in the nearest future. Still sometimes there might be a need to figure out the actual parameter type of some list. Maybe I'm reinventing a wheel here, but here's my hack to check java.util.Collection of generic type objects. What it currently fails at is determining a parameter type of empty collections. Any suggestions are welcome.

private Class<?> getParamType(Collection<?> c) {
if (c.isEmpty()) {
// Not sure how to determine parameters of empty collections
return Object.class;
}

Iterator<?> i = c.iterator();
Class<?> paramType = i.next().getClass();
while (i.hasNext()) {
// If types of any two objects vary, return an `Object` class
if (!i.next().getClass().equals(paramType)) {
return Object.class;
}
}

// If all parameters are of the same type,
// we can consider this collection of objects with this type
return paramType;
}


And here's how it works:

// Generic list -- various objects
List genericList = new ArrayList(3);
genericList.add("FTW!");
genericList.add(100500);
genericList.add(new Date());
System.out.println(getParamType(genericList)); // class java.lang.Object
System.out.println(getParamType(genericList).equals(String.class)); // false

List<String> stringList = new ArrayList<String>(3);
stringList.add("FTW!");
stringList.add(100500 + "");
stringList.add(new Date().toString());
System.out.println(getParamType(stringList)); // class java.lang.String
System.out.println(getParamType(stringList).equals(String.class)); // true


Maybe Class object is not what you need, but you get the idea.

This method is inefficient with large collections. Alternatively, you can also iterate through collections and check every object using `instanceof` operator at once if you know a pre-definded set of possible parameters.

No comments: