@ -96,12 +96,12 @@ public abstract class GenericTypeResolver {
@@ -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 # resolveParameterized ReturnType
* @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 {
@@ -114,27 +114,27 @@ public abstract class GenericTypeResolver {
/ * *
* Determine the target type for the generic return type of the given
* < em > parameterize d< / em > method , where the type variable is declared
* on the given method .
* < em > generic metho d< / em > , where formal type variables are declared on
* the given method itself .
*
* < p > For example , given a factory method with the following signature ,
* if { @code resolveParameterized ReturnType ( ) } 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 resolveParameterized ReturnType ( ) } will
* { @code MyService . class } , { @code resolveReturnTypeForGenericMethod ( ) } will
* infer that the target return type is { @code MyService } .
*
* < pre > { @code public static < T > T createProxy ( Class < T > clazz ) } < / pre >
*
* < h4 > Possible Return Values < / h4 >
* < ul >
* < li > the target return type if it can be inferred < / li >
* < li > the { @link Method # getReturnType ( ) standard return type } , if
* the given { @code method } does not declare any { @link
* Method # getTypeParameters ( ) generic typ es} < / li >
* < li > the { @link Method # getReturnType ( ) standard return type } , if the
* < li > the target return type , if it can be inferred < / li >
* < li > the { @linkplain Method # getReturnType ( ) standard return type } , if
* the given { @code method } does not declare any { @linkplain
* Method # getTypeParameters ( ) formal type variabl es} < / li >
* < li > the { @linkplain Method # getReturnType ( ) standard return type } , if the
* target return type cannot be inferred ( e . g . , due to type erasure ) < / li >
* < li > { @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 < / li >
* < / ul >
@ -147,60 +147,59 @@ public abstract class GenericTypeResolver {
@@ -147,60 +147,59 @@ public abstract class GenericTypeResolver {
* @since 3 . 2
* @see # resolveReturnType
* /
public static Class < ? > resolveParameterized ReturnType ( 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 < Method > [ ] 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 < Method > [ ] 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 < generic ArgumentTypes. length ) {
if ( args . length < method ArgumentTypes. length ) {
return null ;
}
// Ensure that the generic type is declared directly on the method
// itself, not on the enclosing class or interface.
boolean locallyDeclaredGenericTyp eMatchesReturnType = false ;
for ( TypeVariable < Method > currentType : declaredGenericTyp es ) {
if ( currentType . equals ( genericReturnType ) ) {
// Ensure that the type variable (e.g., T) is declared directly on the method
// itself (e.g., via <T>) , not on the enclosing class or interface.
boolean locallyDeclaredTypeVariabl eMatchesReturnType = false ;
for ( TypeVariable < Method > currentTypeVariable : declaredTypeVariabl es ) {
if ( currentTypeVariable . equals ( genericReturnType ) ) {
if ( logger . isDebugEnabled ( ) ) {
logger . debug ( String . format (
"Found declared generic typ e [%s] that matches the target return type [%s]." ,
currentType , genericReturnType ) ) ;
"Found declared type variabl e [%s] that matches the target return type [%s]." ,
currentTypeVariable , genericReturnType ) ) ;
}
locallyDeclaredGenericTyp eMatchesReturnType = true ;
locallyDeclaredTypeVariabl eMatchesReturnType = true ;
break ;
}
}
if ( locallyDeclaredGenericTyp eMatchesReturnType ) {
for ( int i = 0 ; i < generic ArgumentTypes. length ; i + + ) {
final Type currentArgumentType = generic ArgumentTypes[ i ] ;
if ( locallyDeclaredTypeVariabl eMatchesReturnType ) {
for ( int i = 0 ; i < method ArgumentTypes. length ; i + + ) {
final Type currentMethod ArgumentType = method ArgumentTypes[ i ] ;
if ( currentArgumentType . equals ( genericReturnType ) ) {
if ( currentMethod ArgumentType . 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 ( currentMethod ArgumentType instanceof ParameterizedType ) {
ParameterizedType parameterizedType = ( ParameterizedType ) currentMethod ArgumentType ;
Type [ ] actualTypeArguments = parameterizedType . getActualTypeArguments ( ) ;
for ( int j = 0 ; j < actualTypeArguments . length ; j + + ) {
@ -209,7 +208,7 @@ public abstract class GenericTypeResolver {
@@ -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 {
@@ -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...