diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java index 4ee22d64686..b7a72ee7304 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java @@ -19,6 +19,7 @@ package org.springframework.expression.spel.ast; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -260,7 +261,8 @@ public class MethodReference extends SpelNodeImpl { @Override public boolean isCompilable() { CachedMethodExecutor executorToCheck = this.cachedExecutor; - if (executorToCheck == null || !(executorToCheck.get() instanceof ReflectiveMethodExecutor)) { + if (executorToCheck == null || executorToCheck.hasProxyTarget() || + !(executorToCheck.get() instanceof ReflectiveMethodExecutor)) { return false; } @@ -274,8 +276,7 @@ public class MethodReference extends SpelNodeImpl { if (executor.didArgumentConversionOccur()) { return false; } - Method method = executor.getMethod(); - Class clazz = method.getDeclaringClass(); + Class clazz = executor.getMethod().getDeclaringClass(); if (!Modifier.isPublic(clazz.getModifiers()) && executor.getPublicDeclaringClass() == null) { return false; } @@ -400,6 +401,10 @@ public class MethodReference extends SpelNodeImpl { ObjectUtils.nullSafeEquals(this.target, target) && this.argumentTypes.equals(argumentTypes)); } + public boolean hasProxyTarget() { + return (this.target != null && Proxy.isProxyClass(this.target.getType())); + } + public MethodExecutor get() { return this.methodExecutor; } diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java index 06a102f5528..0150a6023cb 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java @@ -724,13 +724,32 @@ public class SpelReproTests extends AbstractExpressionTests { VarargsReceiver receiver = new VarargsReceiver(); VarargsInterface proxy = (VarargsInterface) Proxy.newProxyInstance( - getClass().getClassLoader(), new Class[]{VarargsInterface.class}, + getClass().getClassLoader(), new Class[] {VarargsInterface.class}, (proxy1, method, args) -> method.invoke(receiver, args)); assertEquals("OK", expr.getValue(new StandardEvaluationContext(receiver))); assertEquals("OK", expr.getValue(new StandardEvaluationContext(proxy))); } + @Test + public void testCompiledExpressionForProxy_SPR16191() { + SpelExpressionParser expressionParser = + new SpelExpressionParser(new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null)); + Expression expression = expressionParser.parseExpression("#target.process(#root)"); + + VarargsReceiver receiver = new VarargsReceiver(); + VarargsInterface proxy = (VarargsInterface) Proxy.newProxyInstance( + getClass().getClassLoader(), new Class[] {VarargsInterface.class}, + (proxy1, method, args) -> method.invoke(receiver, args)); + + StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + evaluationContext.setVariable("target", proxy); + + String result = expression.getValue(evaluationContext, "foo", String.class); + result = expression.getValue(evaluationContext, "foo", String.class); + assertEquals("OK", result); + } + @Test public void varargsAndPrimitives_SPR8174() throws Exception { EvaluationContext emptyEvalContext = new StandardEvaluationContext();