From 519799e1cf414615ef0a7a26d5dde0478a47b96d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 6 Mar 2014 14:44:13 +0100 Subject: [PATCH] Fix double SPeL evaluation of parameter When a node of an SPeL expression was a call to a bean referenced in a method argument, the expression was resolved twice. The resolved arguments are now specified to MethodValueRef instead of resolving the arguments again in the constructor Issue: SPR-11445 --- .../expression/spel/ast/MethodReference.java | 6 ++-- .../expression/spel/SpelReproTests.java | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) 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 8cd7a42704b..adcfe7fca87 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 @@ -68,7 +68,7 @@ public class MethodReference extends SpelNodeImpl { throwIfNotNullSafe(getArgumentTypes(arguments)); return ValueRef.NullValueRef.instance; } - return new MethodValueRef(state); + return new MethodValueRef(state, arguments); } @Override @@ -246,11 +246,11 @@ public class MethodReference extends SpelNodeImpl { private final Object[] arguments; - public MethodValueRef(ExpressionState state) { + public MethodValueRef(ExpressionState state, Object[] arguments) { this.evaluationContext = state.getEvaluationContext(); this.value = state.getActiveContextObject().getValue(); this.targetType = state.getActiveContextObject().getTypeDescriptor(); - this.arguments = getArguments(state); + this.arguments = arguments; } @Override 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 b5fa273dc9b..bb5ac298455 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 @@ -29,6 +29,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Rule; import org.junit.Test; @@ -1825,6 +1826,39 @@ public class SpelReproTests extends AbstractExpressionTests { assertEquals("two", list.get(1)); } + @Test + public void SPR11445_simple() { + StandardEvaluationContext context = new StandardEvaluationContext(new Spr11445Class()); + Expression expr = new SpelExpressionParser().parseRaw("echo(parameter())"); + assertEquals(1, expr.getValue(context)); + } + + @Test + public void SPR11445_beanReference() { + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setBeanResolver(new Spr11445Class()); + Expression expr = new SpelExpressionParser().parseRaw("@bean.echo(@bean.parameter())"); + assertEquals(1, expr.getValue(context)); + } + + static class Spr11445Class implements BeanResolver { + + private final AtomicInteger counter = new AtomicInteger(); + + public int echo(int invocation) { + return invocation; + } + + public int parameter() { + return counter.incrementAndGet(); + } + + @Override + public Object resolve(EvaluationContext context, String beanName) throws AccessException { + return beanName.equals("bean") ? this : null; + } + } + @Test public void SPR11494() { Expression exp = new SpelExpressionParser().parseExpression("T(java.util.Arrays).asList('a','b')");