Utils { public static List<Class<?>> getTypeArguments(Class<?> base, Class<?> implementation) { checkArgNotNull(base, "base"); checkArgNotNull(implementation, "implementation"); Map<Type, Type> resolvedTypes = new HashMap<Type, Type>(); Type type; Queue<Type> toCheck = new LinkedList<Type>(); toCheck.add(implementation); while (true) { if (toCheck.isEmpty()) return ImmutableList.of(); type = toCheck.remove(); Class<?> clazz; if (type instanceof Class) { clazz = (Class) type; if (base.isInterface()) { toCheck.addAll(Arrays.asList(clazz.getGenericInterfaces())); } } else if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; clazz = (Class) parameterizedType.getRawType(); TypeVariable<?>[] typeParameters = clazz.getTypeParameters(); Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); for (int i = 0; i < actualTypeArguments.length; i++) { resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); } } else { return ImmutableList.of(); } if (base.equals(getClass(type))) break; toCheck.add(clazz.getGenericSuperclass()); } Type[] actualTypeArguments; if (type instanceof Class) { actualTypeArguments = ((Class) type).getTypeParameters(); } else { actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); } List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>(); for (Type baseType : actualTypeArguments) { while (resolvedTypes.containsKey(baseType)) { baseType = resolvedTypes.get(baseType); } typeArgumentsAsClasses.add(getClass(baseType)); } return typeArgumentsAsClasses; } private  Utils(); static Character[] toObjectArray(char[] array); static Integer[] toObjectArray(int[] array); static Long[] toObjectArray(long[] array); static Short[] toObjectArray(short[] array); static Byte[] toObjectArray(byte[] array); static Float[] toObjectArray(float[] array); static Double[] toObjectArray(double[] array); static Boolean[] toObjectArray(boolean[] array); @SuppressWarnings({"unchecked"}) static T[] arrayOf(T firstElement, T... moreElements); @SuppressWarnings({"unchecked"}) static T[] arrayOf(T firstElement, T secondElement, T... moreElements); @SuppressWarnings({"unchecked"}) static T[] arrayOf(T[] firstElements, T lastElement); static String toString(Object obj); static boolean equal(T a, T b); static List<Class<?>> getTypeArguments(Class<?> base, Class<?> implementation); static Class<?> getClass(Type type); static boolean isBoxedType(Class<?> primitive, Class<?> boxed); static Constructor findConstructor(Class<?> type, Object[] args); static String humanize(long value); static final Character[] EMPTY_CHARACTER_OBJECT_ARRAY; static final Integer[] EMPTY_INTEGER_OBJECT_ARRAY; static final Long[] EMPTY_LONG_OBJECT_ARRAY; static final Short[] EMPTY_SHORT_OBJECT_ARRAY; static final Byte[] EMPTY_BYTE_OBJECT_ARRAY; static final Float[] EMPTY_FLOAT_OBJECT_ARRAY; static final Double[] EMPTY_DOUBLE_OBJECT_ARRAY; static final Boolean[] EMPTY_BOOLEAN_OBJECT_ARRAY; }
@SuppressWarnings({"unchecked", "InstantiatingObjectToGetClassObject"}) @Test public void testGetTypeArguments() { assertEquals(getTypeArguments(ArrayList.class, new ArrayList<String>() { }.getClass()), Arrays.asList(String.class)); assertEquals(getTypeArguments(Formatter.class, new Formatter<Integer>() { public String format(Integer object) { return null; } }.getClass()), Arrays.asList(Integer.class)); assertEquals(getTypeArguments(Formatter.class, NodeFormatter.class), Arrays.asList(Node.class)); }