From 4b323eca114e08a433af6f7a3b130d7b266689e3 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 4 Sep 2017 19:06:49 +0200 Subject: [PATCH] DATACMNS-1150 - Projection methods with SpEL expressions can now use method parameters. We now forward method parameters of methods on projection interfaces to the expression evaluation. The parameters are exposed via an array named "args". --- .../SpelEvaluatingMethodInterceptor.java | 21 ++++++------------ ...lEvaluatingMethodInterceptorUnitTests.java | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptor.java index fb2dd2407..4feddee13 100644 --- a/src/main/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptor.java @@ -52,6 +52,7 @@ class SpelEvaluatingMethodInterceptor implements MethodInterceptor { private final EvaluationContext evaluationContext; private final MethodInterceptor delegate; private final Map expressions; + private final Object target; /** * Creates a new {@link SpelEvaluatingMethodInterceptor} delegating to the given {@link MethodInterceptor} as fallback @@ -72,7 +73,7 @@ class SpelEvaluatingMethodInterceptor implements MethodInterceptor { Assert.notNull(parser, "SpelExpressionParser must not be null!"); Assert.notNull(targetInterface, "Target interface must not be null!"); - StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new TargetWrapper(target)); + StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); if (target instanceof Map) { evaluationContext.addPropertyAccessor(new MapAccessor()); @@ -86,6 +87,7 @@ class SpelEvaluatingMethodInterceptor implements MethodInterceptor { this.evaluationContext = evaluationContext; this.delegate = delegate; + this.target = target; } /** @@ -134,7 +136,7 @@ class SpelEvaluatingMethodInterceptor implements MethodInterceptor { return delegate.invoke(invocation); } - return expression.getValue(evaluationContext); + return expression.getValue(evaluationContext, TargetWrapper.of(target, invocation.getArguments())); } /** @@ -142,19 +144,10 @@ class SpelEvaluatingMethodInterceptor implements MethodInterceptor { * * @author Oliver Gierke */ + @lombok.Value(staticConstructor = "of") static class TargetWrapper { - private final Object target; - - public TargetWrapper(Object target) { - this.target = target; - } - - /** - * @return the target - */ - public Object getTarget() { - return target; - } + Object target; + Object[] args; } } diff --git a/src/test/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptorUnitTests.java b/src/test/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptorUnitTests.java index 3c4e8bc47..ad7504233 100755 --- a/src/test/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptorUnitTests.java +++ b/src/test/java/org/springframework/data/projection/SpelEvaluatingMethodInterceptorUnitTests.java @@ -104,6 +104,21 @@ public class SpelEvaluatingMethodInterceptorUnitTests { assertThat(interceptor.invoke(invocation)).isEqualTo("Dave"); } + @Test // DATACMNS-1150 + public void forwardsParameterIntoSpElExpressionEvaluation() throws Throwable { + + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + factory.registerSingleton("someBean", new SomeBean()); + + when(invocation.getMethod()).thenReturn(Projection.class.getMethod("invokeBeanWithParameter", Integer.class)); + when(invocation.getArguments()).thenReturn(new Object[] { 1 }); + + MethodInterceptor interceptor = new SpelEvaluatingMethodInterceptor(delegate, new Target(), factory, parser, + Projection.class); + + assertThat(interceptor.invoke(invocation)).isEqualTo("property1"); + } + interface Projection { @Value("#{target.name}") @@ -115,6 +130,9 @@ public class SpelEvaluatingMethodInterceptorUnitTests { String getName(); String getAddress(); + + @Value("#{@someBean.someMethod(target, args[0])}") + String invokeBeanWithParameter(Integer parameter); } interface InvalidProjection { @@ -135,5 +153,9 @@ public class SpelEvaluatingMethodInterceptorUnitTests { public String getValue() { return "value"; } + + public String someMethod(Target target, Integer parameter) { + return target.getName() + parameter.toString(); + } } }