@ -26,6 +26,7 @@ import org.springframework.expression.EvaluationContext;
@@ -26,6 +26,7 @@ import org.springframework.expression.EvaluationContext;
import org.springframework.expression.MethodExecutor ;
import org.springframework.expression.TypedValue ;
import org.springframework.lang.Nullable ;
import org.springframework.util.ClassUtils ;
import org.springframework.util.ReflectionUtils ;
/ * *
@ -37,7 +38,9 @@ import org.springframework.util.ReflectionUtils;
@@ -37,7 +38,9 @@ import org.springframework.util.ReflectionUtils;
* /
public class ReflectiveMethodExecutor implements MethodExecutor {
private final Method method ;
private final Method originalMethod ;
private final Method methodToInvoke ;
@Nullable
private final Integer varargsPosition ;
@ -50,8 +53,13 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
@@ -50,8 +53,13 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
private boolean argumentConversionOccurred = false ;
/ * *
* Create a new executor for the given method .
* @param method the method to invoke
* /
public ReflectiveMethodExecutor ( Method method ) {
this . method = method ;
this . originalMethod = method ;
this . methodToInvoke = ClassUtils . getInterfaceMethodIfPossible ( method ) ;
if ( method . isVarArgs ( ) ) {
Class < ? > [ ] paramTypes = method . getParameterTypes ( ) ;
this . varargsPosition = paramTypes . length - 1 ;
@ -62,29 +70,33 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
@@ -62,29 +70,33 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
}
public Method getMethod ( ) {
return this . method ;
/ * *
* Return the original method that this executor has been configured for .
* /
public final Method getMethod ( ) {
return this . originalMethod ;
}
/ * *
* Find the first public class in the methods declaring class hierarchy that declares this method .
* Sometimes the reflective method discovery logic finds a suitable method that can easily be
* called via reflection but cannot be called from generated code when compiling the expression
* because of visibility restrictions . For example if a non public class overrides toString ( ) , this
* helper method will walk up the type hierarchy to find the first public type that declares the
* method ( if there is one ! ) . For toString ( ) it may walk as far as Object .
* because of visibility restrictions . For example if a non - public class overrides toString ( ) ,
* this helper method will walk up the type hierarchy to find the first public type that declares
* the method ( if there is one ! ) . For toString ( ) it may walk as far as Object .
* /
@Nullable
public Class < ? > getPublicDeclaringClass ( ) {
if ( ! this . computedPublicDeclaringClass ) {
this . publicDeclaringClass = discoverPublicClass ( this . method , this . method . getDeclaringClass ( ) ) ;
this . publicDeclaringClass =
discoverPublicDeclaringClass ( this . originalMethod , this . originalMethod . getDeclaringClass ( ) ) ;
this . computedPublicDeclaringClass = true ;
}
return this . publicDeclaringClass ;
}
@Nullable
private Class < ? > discoverPublicClass ( Method method , Class < ? > clazz ) {
private Class < ? > discoverPublicDeclaring Class ( Method method , Class < ? > clazz ) {
if ( Modifier . isPublic ( clazz . getModifiers ( ) ) ) {
try {
clazz . getDeclaredMethod ( method . getName ( ) , method . getParameterTypes ( ) ) ;
@ -94,12 +106,8 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
@@ -94,12 +106,8 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
// Continue below...
}
}
Class < ? > [ ] ifcs = clazz . getInterfaces ( ) ;
for ( Class < ? > ifc : ifcs ) {
discoverPublicClass ( method , ifc ) ;
}
if ( clazz . getSuperclass ( ) ! = null ) {
return discoverPublicClass ( method , clazz . getSuperclass ( ) ) ;
return discoverPublicDeclaringClass ( method , clazz . getSuperclass ( ) ) ;
}
return null ;
}
@ -113,17 +121,17 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
@@ -113,17 +121,17 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
public TypedValue execute ( EvaluationContext context , Object target , Object . . . arguments ) throws AccessException {
try {
this . argumentConversionOccurred = ReflectionHelper . convertArguments (
context . getTypeConverter ( ) , arguments , this . m ethod, this . varargsPosition ) ;
if ( this . m ethod. isVarArgs ( ) ) {
context . getTypeConverter ( ) , arguments , this . originalM ethod, this . varargsPosition ) ;
if ( this . originalM ethod. isVarArgs ( ) ) {
arguments = ReflectionHelper . setupArgumentsForVarargsInvocation (
this . m ethod. getParameterTypes ( ) , arguments ) ;
this . originalM ethod. getParameterTypes ( ) , arguments ) ;
}
ReflectionUtils . makeAccessible ( this . method ) ;
Object value = this . method . invoke ( target , arguments ) ;
return new TypedValue ( value , new TypeDescriptor ( new MethodParameter ( this . m ethod, - 1 ) ) . narrow ( value ) ) ;
ReflectionUtils . makeAccessible ( this . methodToInvoke ) ;
Object value = this . methodToInvoke . invoke ( target , arguments ) ;
return new TypedValue ( value , new TypeDescriptor ( new MethodParameter ( this . originalM ethod, - 1 ) ) . narrow ( value ) ) ;
}
catch ( Exception ex ) {
throw new AccessException ( "Problem invoking method: " + this . method , ex ) ;
throw new AccessException ( "Problem invoking method: " + this . methodToInvoke , ex ) ;
}
}