From 605f0e7a22b4e8bf8effa33283e8bc7685d7d129 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Wed, 6 Jul 2011 09:15:32 +0000 Subject: [PATCH] Introduce GenericTypeResolver#resolveReturnTypeArgument Issue: SPR-8514 --- .../core/GenericTypeResolver.java | 31 +++++++++++++++++++ .../core/GenericTypeResolverTests.java | 17 ++++++++++ 2 files changed, 48 insertions(+) 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 de2502e962f..25b1d37b295 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 @@ -24,6 +24,8 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -102,6 +104,35 @@ public abstract class GenericTypeResolver { return (rawType instanceof Class ? (Class) rawType : method.getReturnType()); } + /** + * Resolve the single type argument of the given generic interface against the given + * target method which is assumed to return the given interface or an implementation + * of it. + * @param method the target method to check the return type of + * @param genericIfc the generic interface or superclass to resolve the type argument from + * @return the resolved parameter type of the method return type, or null + * if not resolvable or if the single argument is of type {@link WildcardType}. + */ + public static Class resolveReturnTypeArgument(Method method, Class genericIfc) { + Type returnType = method.getReturnType(); + Type genericReturnType = method.getGenericReturnType(); + ParameterizedType targetType; + if (returnType.equals(genericIfc)) { + if (genericReturnType instanceof ParameterizedType) { + targetType = (ParameterizedType)genericReturnType; + Type[] actualTypeArguments = targetType.getActualTypeArguments(); + Type typeArg = actualTypeArguments[0]; + if (!(typeArg instanceof WildcardType)) { + return (Class)typeArg; + } + } + else { + return null; + } + } + return GenericTypeResolver.resolveTypeArgument((Class)returnType, genericIfc); + } + /** * Resolve the single type argument of the given generic interface against * the given target class which is assumed to implement the generic interface 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 index df595e3f2c0..e419c0bc1f6 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/GenericTypeResolverTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/GenericTypeResolverTests.java @@ -20,6 +20,7 @@ import java.util.Collection; import static org.junit.Assert.*; import org.junit.Test; +import org.springframework.util.ReflectionUtils; /** * @author Juergen Hoeller @@ -46,6 +47,14 @@ public class GenericTypeResolverTests { assertEquals(Collection.class, GenericTypeResolver.resolveTypeArgument(MyCollectionSuperclassType.class, MySuperclassType.class)); } + @Test + public void testMethodReturnType() { + assertEquals(Integer.class, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "integer"), MyInterfaceType.class)); + assertEquals(String.class, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "string"), MyInterfaceType.class)); + assertEquals(null, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "raw"), MyInterfaceType.class)); + assertEquals(null, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "object"), MyInterfaceType.class)); + } + public interface MyInterfaceType { } @@ -66,4 +75,12 @@ public class GenericTypeResolverTests { public class MyCollectionSuperclassType extends MySuperclassType> { } + public class MyTypeWithMethods { + public MyInterfaceType integer() { return null; } + public MySimpleInterfaceType string() { return null; } + public Object object() { return null; } + @SuppressWarnings("rawtypes") + public MyInterfaceType raw() { return null; } + } + }