diff --git a/org.springframework.core/src/main/java/org/springframework/core/GenericTypeResolver.java b/org.springframework.core/src/main/java/org/springframework/core/GenericTypeResolver.java
index 596a925ebdf..211b7d41984 100644
--- a/org.springframework.core/src/main/java/org/springframework/core/GenericTypeResolver.java
+++ b/org.springframework.core/src/main/java/org/springframework/core/GenericTypeResolver.java
@@ -107,7 +107,7 @@ public abstract class GenericTypeResolver {
* the given target class which is assumed to implement the generic interface
* and possibly declare a concrete type for its type variable.
* @param clazz the target class to check against
- * @param genericIfc the generic interface to resolve the type argument from
+ * @param genericIfc the generic interface or superclass to resolve the type argument from
* @return the resolved type of the argument, or null if not resolvable
*/
public static Class> resolveTypeArgument(Class clazz, Class genericIfc) {
@@ -127,7 +127,7 @@ public abstract class GenericTypeResolver {
* target class which is assumed to implement the generic interface and possibly
* declare concrete types for its type variables.
* @param clazz the target class to check against
- * @param genericIfc the generic interface to resolve the type argument from
+ * @param genericIfc the generic interface or superclass to resolve the type argument from
* @return the resolved type of each argument, with the array size matching the
* number of actual type arguments, or null if not resolvable
*/
@@ -137,26 +137,20 @@ public abstract class GenericTypeResolver {
private static Class[] doResolveTypeArguments(Class ownerClass, Class classToIntrospect, Class genericIfc) {
while (classToIntrospect != null) {
- Type[] ifcs = classToIntrospect.getGenericInterfaces();
- for (Type ifc : ifcs) {
- if (ifc instanceof ParameterizedType) {
- ParameterizedType paramIfc = (ParameterizedType) ifc;
- Type rawType = paramIfc.getRawType();
- if (genericIfc.equals(rawType)) {
- Type[] typeArgs = paramIfc.getActualTypeArguments();
- Class[] result = new Class[typeArgs.length];
- for (int i = 0; i < typeArgs.length; i++) {
- Type arg = typeArgs[i];
- result[i] = extractClass(ownerClass, arg);
- }
+ if (genericIfc.isInterface()) {
+ Type[] ifcs = classToIntrospect.getGenericInterfaces();
+ for (Type ifc : ifcs) {
+ Class[] result = doResolveTypeArguments(ownerClass, ifc, genericIfc);
+ if (result != null) {
return result;
}
- else if (genericIfc.isAssignableFrom((Class) rawType)) {
- return doResolveTypeArguments(ownerClass, (Class) rawType, genericIfc);
- }
}
- else if (genericIfc.isAssignableFrom((Class) ifc)) {
- return doResolveTypeArguments(ownerClass, (Class) ifc, genericIfc);
+ }
+ else {
+ Class[] result = doResolveTypeArguments(
+ ownerClass, classToIntrospect.getGenericSuperclass(), genericIfc);
+ if (result != null) {
+ return result;
}
}
classToIntrospect = classToIntrospect.getSuperclass();
@@ -164,11 +158,43 @@ public abstract class GenericTypeResolver {
return null;
}
+ private static Class[] doResolveTypeArguments(Class ownerClass, Type ifc, Class genericIfc) {
+ if (ifc instanceof ParameterizedType) {
+ ParameterizedType paramIfc = (ParameterizedType) ifc;
+ Type rawType = paramIfc.getRawType();
+ if (genericIfc.equals(rawType)) {
+ Type[] typeArgs = paramIfc.getActualTypeArguments();
+ Class[] result = new Class[typeArgs.length];
+ for (int i = 0; i < typeArgs.length; i++) {
+ Type arg = typeArgs[i];
+ result[i] = extractClass(ownerClass, arg);
+ }
+ return result;
+ }
+ else if (genericIfc.isAssignableFrom((Class) rawType)) {
+ return doResolveTypeArguments(ownerClass, (Class) rawType, genericIfc);
+ }
+ }
+ else if (genericIfc.isAssignableFrom((Class) ifc)) {
+ return doResolveTypeArguments(ownerClass, (Class) ifc, genericIfc);
+ }
+ return null;
+ }
+
/**
* Extract a class instance from given Type.
*/
private static Class extractClass(Class ownerClass, Type arg) {
- if (arg instanceof TypeVariable) {
+ if (arg instanceof ParameterizedType) {
+ return extractClass(ownerClass, ((ParameterizedType) arg).getRawType());
+ }
+ else if (arg instanceof GenericArrayType) {
+ GenericArrayType gat = (GenericArrayType) arg;
+ Type gt = gat.getGenericComponentType();
+ Class> componentClass = extractClass(ownerClass, gt);
+ return Array.newInstance(componentClass, 0).getClass();
+ }
+ else if (arg instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) arg;
arg = getTypeVariableMap(ownerClass).get(tv);
if (arg == null) {
@@ -178,12 +204,6 @@ public abstract class GenericTypeResolver {
arg = extractClass(ownerClass, arg);
}
}
- else if (arg instanceof GenericArrayType) {
- GenericArrayType gat = (GenericArrayType) arg;
- Type gt = gat.getGenericComponentType();
- Class> componentClass = extractClass(ownerClass, gt);
- arg = Array.newInstance(componentClass, 0).getClass();
- }
return (arg instanceof Class ? (Class) arg : Object.class);
}
diff --git a/org.springframework.core/src/test/java/org/springframework/core/GenericTypeResolverTests.java b/org.springframework.core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
new file mode 100644
index 00000000000..df595e3f2c0
--- /dev/null
+++ b/org.springframework.core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2002-2010 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.core;
+
+import java.util.Collection;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+/**
+ * @author Juergen Hoeller
+ */
+public class GenericTypeResolverTests {
+
+ @Test
+ public void testSimpleInterfaceType() {
+ assertEquals(String.class, GenericTypeResolver.resolveTypeArgument(MySimpleInterfaceType.class, MyInterfaceType.class));
+ }
+
+ @Test
+ public void testSimpleCollectionInterfaceType() {
+ assertEquals(Collection.class, GenericTypeResolver.resolveTypeArgument(MyCollectionInterfaceType.class, MyInterfaceType.class));
+ }
+
+ @Test
+ public void testSimpleSuperclassType() {
+ assertEquals(String.class, GenericTypeResolver.resolveTypeArgument(MySimpleSuperclassType.class, MySuperclassType.class));
+ }
+
+ @Test
+ public void testSimpleCollectionSuperclassType() {
+ assertEquals(Collection.class, GenericTypeResolver.resolveTypeArgument(MyCollectionSuperclassType.class, MySuperclassType.class));
+ }
+
+
+ public interface MyInterfaceType {
+ }
+
+ public class MySimpleInterfaceType implements MyInterfaceType {
+ }
+
+ public class MyCollectionInterfaceType implements MyInterfaceType> {
+ }
+
+
+ public abstract class MySuperclassType {
+ }
+
+ public class MySimpleSuperclassType extends MySuperclassType {
+ }
+
+ public class MyCollectionSuperclassType extends MySuperclassType> {
+ }
+
+}