diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
index 4a67ca6869522ed0dad402a049484be3d49b4fe5..c3369ef1191feb7cc29d7e288c8f19408ef50fcd 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
@@ -646,7 +646,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
&& factoryMethod.getName().equals(mbd.getFactoryMethodName())
&& factoryMethod.getParameterTypes().length >= minNrOfArgs) {
- Class> returnType = GenericTypeResolver.resolveParameterizedReturnType(factoryMethod, args);
+ Class> returnType = GenericTypeResolver.resolveReturnTypeForGenericMethod(factoryMethod, args);
if (returnType != null) {
returnTypes.add(returnType);
}
diff --git a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java
index d4dda19c52b4a2552b137458b764fc0da89c78c4..9c025c0ba5d067656acd2305cdf765a8d68373db 100644
--- a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java
+++ b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java
@@ -96,12 +96,12 @@ public abstract class GenericTypeResolver {
/**
* Determine the target type for the generic return type of the given method,
- * where the type variable is declared on the given class.
+ * where formal type variables are declared on the given class.
*
* @param method the method to introspect
* @param clazz the class to resolve type variables against
* @return the corresponding generic parameter or return type
- * @see #resolveParameterizedReturnType
+ * @see #resolveReturnTypeForGenericMethod
*/
public static Class> resolveReturnType(Method method, Class> clazz) {
Assert.notNull(method, "Method must not be null");
@@ -114,27 +114,27 @@ public abstract class GenericTypeResolver {
/**
* Determine the target type for the generic return type of the given
- * parameterized method, where the type variable is declared
- * on the given method.
+ * generic method, where formal type variables are declared on
+ * the given method itself.
*
*
For example, given a factory method with the following signature,
- * if {@code resolveParameterizedReturnType()} is invoked with the reflected
+ * if {@code resolveReturnTypeForGenericMethod()} is invoked with the reflected
* method for {@code creatProxy()} and an {@code Object[]} array containing
- * {@code MyService.class}, {@code resolveParameterizedReturnType()} will
+ * {@code MyService.class}, {@code resolveReturnTypeForGenericMethod()} will
* infer that the target return type is {@code MyService}.
*
*
{@code public static T createProxy(Class clazz)}
*
* Possible Return Values
*
- * - the target return type if it can be inferred
- * - the {@link Method#getReturnType() standard return type}, if
- * the given {@code method} does not declare any {@link
- * Method#getTypeParameters() generic types}
- * - the {@link Method#getReturnType() standard return type}, if the
+ *
- the target return type, if it can be inferred
+ * - the {@linkplain Method#getReturnType() standard return type}, if
+ * the given {@code method} does not declare any {@linkplain
+ * Method#getTypeParameters() formal type variables}
+ * - the {@linkplain Method#getReturnType() standard return type}, if the
* target return type cannot be inferred (e.g., due to type erasure)
* - {@code null}, if the length of the given arguments array is shorter
- * than the length of the {@link
+ * than the length of the {@linkplain
* Method#getGenericParameterTypes() formal argument list} for the given
* method
*
@@ -147,60 +147,59 @@ public abstract class GenericTypeResolver {
* @since 3.2
* @see #resolveReturnType
*/
- public static Class> resolveParameterizedReturnType(Method method, Object[] args) {
+ public static Class> resolveReturnTypeForGenericMethod(Method method, Object[] args) {
Assert.notNull(method, "method must not be null");
Assert.notNull(args, "args must not be null");
- final TypeVariable[] declaredGenericTypes = method.getTypeParameters();
- final Type genericReturnType = method.getGenericReturnType();
- final Type[] genericArgumentTypes = method.getGenericParameterTypes();
-
if (logger.isDebugEnabled()) {
- logger.debug(String.format(
- "Resolving parameterized return type for [%s] with concrete method arguments [%s].",
+ logger.debug(String.format("Resolving return type for [%s] with concrete method arguments [%s].",
method.toGenericString(), ObjectUtils.nullSafeToString(args)));
}
- // No declared generic types to inspect, so just return the standard return type.
- if (declaredGenericTypes.length == 0) {
+ final TypeVariable[] declaredTypeVariables = method.getTypeParameters();
+ final Type genericReturnType = method.getGenericReturnType();
+ final Type[] methodArgumentTypes = method.getGenericParameterTypes();
+
+ // No declared type variables to inspect, so just return the standard return type.
+ if (declaredTypeVariables.length == 0) {
return method.getReturnType();
}
// The supplied argument list is too short for the method's signature, so
// return null, since such a method invocation would fail.
- if (args.length < genericArgumentTypes.length) {
+ if (args.length < methodArgumentTypes.length) {
return null;
}
- // Ensure that the generic type is declared directly on the method
- // itself, not on the enclosing class or interface.
- boolean locallyDeclaredGenericTypeMatchesReturnType = false;
- for (TypeVariable currentType : declaredGenericTypes) {
- if (currentType.equals(genericReturnType)) {
+ // Ensure that the type variable (e.g., T) is declared directly on the method
+ // itself (e.g., via ), not on the enclosing class or interface.
+ boolean locallyDeclaredTypeVariableMatchesReturnType = false;
+ for (TypeVariable currentTypeVariable : declaredTypeVariables) {
+ if (currentTypeVariable.equals(genericReturnType)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format(
- "Found declared generic type [%s] that matches the target return type [%s].",
- currentType, genericReturnType));
+ "Found declared type variable [%s] that matches the target return type [%s].",
+ currentTypeVariable, genericReturnType));
}
- locallyDeclaredGenericTypeMatchesReturnType = true;
+ locallyDeclaredTypeVariableMatchesReturnType = true;
break;
}
}
- if (locallyDeclaredGenericTypeMatchesReturnType) {
- for (int i = 0; i < genericArgumentTypes.length; i++) {
- final Type currentArgumentType = genericArgumentTypes[i];
+ if (locallyDeclaredTypeVariableMatchesReturnType) {
+ for (int i = 0; i < methodArgumentTypes.length; i++) {
+ final Type currentMethodArgumentType = methodArgumentTypes[i];
- if (currentArgumentType.equals(genericReturnType)) {
+ if (currentMethodArgumentType.equals(genericReturnType)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format(
- "Found generic method argument at index [%s] that matches the target return type.", i));
+ "Found method argument type at index [%s] that matches the target return type.", i));
}
return args[i].getClass();
}
- if (currentArgumentType instanceof ParameterizedType) {
- ParameterizedType parameterizedType = (ParameterizedType) currentArgumentType;
+ if (currentMethodArgumentType instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType) currentMethodArgumentType;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (int j = 0; j < actualTypeArguments.length; j++) {
@@ -209,7 +208,7 @@ public abstract class GenericTypeResolver {
if (typeArg.equals(genericReturnType)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format(
- "Found method argument at index [%s] that is parameterized with a type that matches the target return type.",
+ "Found method argument type at index [%s] that is parameterized with a type argument that matches the target return type.",
i));
}
@@ -219,7 +218,7 @@ public abstract class GenericTypeResolver {
// Consider adding logic to determine the class of the
// J'th typeArg, if possible.
logger.info(String.format(
- "Could not determine the target type for parameterized type [%s] for method [%s].",
+ "Could not determine the target type for type argument [%s] for method [%s].",
typeArg, method.toGenericString()));
// For now, just fall back...
diff --git a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
index 338529a48986c70c2cf1f5adddc73d28bd8f95dd..344dcef5418bddc0cf8852142e0e625c7589e79d 100644
--- a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
+++ b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
@@ -73,51 +73,51 @@ public class GenericTypeResolverTests {
* @since 3.2
*/
@Test
- public void parameterizedMethodReturnTypes() {
+ public void genericMethodReturnTypes() {
Method notParameterized = findMethod(MyTypeWithMethods.class, "notParameterized", new Class[] {});
- assertEquals(String.class, resolveParameterizedReturnType(notParameterized, new Object[] {}));
+ assertEquals(String.class, resolveReturnTypeForGenericMethod(notParameterized, new Object[] {}));
Method notParameterizedWithArguments = findMethod(MyTypeWithMethods.class, "notParameterizedWithArguments",
new Class[] { Integer.class, Boolean.class });
assertEquals(String.class,
- resolveParameterizedReturnType(notParameterizedWithArguments, new Object[] { 99, true }));
+ resolveReturnTypeForGenericMethod(notParameterizedWithArguments, new Object[] { 99, true }));
Method createProxy = findMethod(MyTypeWithMethods.class, "createProxy", new Class[] { Object.class });
- assertEquals(String.class, resolveParameterizedReturnType(createProxy, new Object[] { "foo" }));
+ assertEquals(String.class, resolveReturnTypeForGenericMethod(createProxy, new Object[] { "foo" }));
Method createNamedProxyWithDifferentTypes = findMethod(MyTypeWithMethods.class, "createNamedProxy",
new Class[] { String.class, Object.class });
// one argument to few
- assertNull(resolveParameterizedReturnType(createNamedProxyWithDifferentTypes, new Object[] { "enigma" }));
+ assertNull(resolveReturnTypeForGenericMethod(createNamedProxyWithDifferentTypes, new Object[] { "enigma" }));
assertEquals(Long.class,
- resolveParameterizedReturnType(createNamedProxyWithDifferentTypes, new Object[] { "enigma", 99L }));
+ resolveReturnTypeForGenericMethod(createNamedProxyWithDifferentTypes, new Object[] { "enigma", 99L }));
Method createNamedProxyWithDuplicateTypes = findMethod(MyTypeWithMethods.class, "createNamedProxy",
new Class[] { String.class, Object.class });
assertEquals(String.class,
- resolveParameterizedReturnType(createNamedProxyWithDuplicateTypes, new Object[] { "enigma", "foo" }));
+ resolveReturnTypeForGenericMethod(createNamedProxyWithDuplicateTypes, new Object[] { "enigma", "foo" }));
Method createMock = findMethod(MyTypeWithMethods.class, "createMock", new Class[] { Class.class });
- assertEquals(Runnable.class, resolveParameterizedReturnType(createMock, new Object[] { Runnable.class }));
+ assertEquals(Runnable.class, resolveReturnTypeForGenericMethod(createMock, new Object[] { Runnable.class }));
Method createNamedMock = findMethod(MyTypeWithMethods.class, "createNamedMock", new Class[] { String.class,
Class.class });
assertEquals(Runnable.class,
- resolveParameterizedReturnType(createNamedMock, new Object[] { "foo", Runnable.class }));
+ resolveReturnTypeForGenericMethod(createNamedMock, new Object[] { "foo", Runnable.class }));
Method createVMock = findMethod(MyTypeWithMethods.class, "createVMock",
new Class[] { Object.class, Class.class });
assertEquals(Runnable.class,
- resolveParameterizedReturnType(createVMock, new Object[] { "foo", Runnable.class }));
+ resolveReturnTypeForGenericMethod(createVMock, new Object[] { "foo", Runnable.class }));
// Ideally we would expect String.class instead of Object.class, but
- // resolveParameterizedReturnType() does not currently support this form of
+ // resolveReturnTypeForGenericMethod() does not currently support this form of
// look-up.
Method extractValueFrom = findMethod(MyTypeWithMethods.class, "extractValueFrom",
new Class[] { MyInterfaceType.class });
assertEquals(Object.class,
- resolveParameterizedReturnType(extractValueFrom, new Object[] { new MySimpleInterfaceType() }));
+ resolveReturnTypeForGenericMethod(extractValueFrom, new Object[] { new MySimpleInterfaceType() }));
// Ideally we would expect Boolean.class instead of Object.class, but this
// information is not available at run-time due to type erasure.
@@ -125,7 +125,7 @@ public class GenericTypeResolverTests {
map.put(0, false);
map.put(1, true);
Method extractMagicValue = findMethod(MyTypeWithMethods.class, "extractMagicValue", new Class[] { Map.class });
- assertEquals(Object.class, resolveParameterizedReturnType(extractMagicValue, new Object[] { map }));
+ assertEquals(Object.class, resolveReturnTypeForGenericMethod(extractMagicValue, new Object[] { map }));
}
diff --git a/src/dist/changelog.txt b/src/dist/changelog.txt
index 9f1766ee2ebe5d86366ce0f0b16bd0ebc4449166..bcb7659bd66e5d4de3dd428548c0e10075371576 100644
--- a/src/dist/changelog.txt
+++ b/src/dist/changelog.txt
@@ -7,7 +7,7 @@ Changes in version 3.2 M2 (2012-08-xx)
--------------------------------------
* spring-test module now depends on junit:junit-dep (SPR-6966)
-* now inferring return type of parameterized factory methods (SPR-9493)
+* now inferring return type of generic factory methods (SPR-9493)
* SpEL Tokenizer now supports methods on integers (SPR-9612)
* introduced support for case-insensitive null literals in SpEL expressions (SPR-9613)
* now using BufferedInputStream in SimpleMetaDataReader to double performance (SPR-9528)