MethodBasedEvaluationContext reliably exposes varargs
Issue: SPR-14554
This commit is contained in:
@@ -17,8 +17,8 @@
|
||||
package org.springframework.cache.interceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.expression.MethodBasedEvaluationContext;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
@@ -38,25 +38,27 @@ import org.springframework.core.ParameterNameDiscoverer;
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author Stephane Nicoll
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
class CacheEvaluationContext extends MethodBasedEvaluationContext {
|
||||
|
||||
private final List<String> unavailableVariables;
|
||||
private final Set<String> unavailableVariables = new HashSet<>(1);
|
||||
|
||||
CacheEvaluationContext(Object rootObject, Method method, Object[] args,
|
||||
ParameterNameDiscoverer paramDiscoverer) {
|
||||
|
||||
super(rootObject, method, args, paramDiscoverer);
|
||||
this.unavailableVariables = new ArrayList<>();
|
||||
CacheEvaluationContext(Object rootObject, Method method, Object[] arguments,
|
||||
ParameterNameDiscoverer parameterNameDiscoverer) {
|
||||
|
||||
super(rootObject, method, arguments, parameterNameDiscoverer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the specified variable name as unavailable for that context. Any expression trying
|
||||
* to access this variable should lead to an exception.
|
||||
* <p>This permits the validation of expressions that could potentially a variable even
|
||||
* when such variable isn't available yet. Any expression trying to use that variable should
|
||||
* therefore fail to evaluate.
|
||||
* Add the specified variable name as unavailable for that context.
|
||||
* Any expression trying to access this variable should lead to an exception.
|
||||
* <p>This permits the validation of expressions that could potentially a
|
||||
* variable even when such variable isn't available yet. Any expression
|
||||
* trying to use that variable should therefore fail to evaluate.
|
||||
*/
|
||||
public void addUnavailableVariable(String name) {
|
||||
this.unavailableVariables.add(name);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.context.expression;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
@@ -34,27 +35,27 @@ import org.springframework.util.ObjectUtils;
|
||||
* </ol>
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Sergey Podgurskiy
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
*/
|
||||
public class MethodBasedEvaluationContext extends StandardEvaluationContext {
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object[] args;
|
||||
private final Object[] arguments;
|
||||
|
||||
private final ParameterNameDiscoverer paramDiscoverer;
|
||||
private final ParameterNameDiscoverer parameterNameDiscoverer;
|
||||
|
||||
private boolean paramLoaded = false;
|
||||
private boolean argumentsLoaded = false;
|
||||
|
||||
|
||||
public MethodBasedEvaluationContext(Object rootObject, Method method, Object[] args,
|
||||
ParameterNameDiscoverer paramDiscoverer) {
|
||||
public MethodBasedEvaluationContext(Object rootObject, Method method, Object[] arguments,
|
||||
ParameterNameDiscoverer parameterNameDiscoverer) {
|
||||
|
||||
super(rootObject);
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
this.paramDiscoverer = paramDiscoverer;
|
||||
this.arguments = arguments;
|
||||
this.parameterNameDiscoverer = parameterNameDiscoverer;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,9 +65,9 @@ public class MethodBasedEvaluationContext extends StandardEvaluationContext {
|
||||
if (variable != null) {
|
||||
return variable;
|
||||
}
|
||||
if (!this.paramLoaded) {
|
||||
if (!this.argumentsLoaded) {
|
||||
lazyLoadArguments();
|
||||
this.paramLoaded = true;
|
||||
this.argumentsLoaded = true;
|
||||
variable = super.lookupVariable(name);
|
||||
}
|
||||
return variable;
|
||||
@@ -76,22 +77,30 @@ public class MethodBasedEvaluationContext extends StandardEvaluationContext {
|
||||
* Load the param information only when needed.
|
||||
*/
|
||||
protected void lazyLoadArguments() {
|
||||
// shortcut if no args need to be loaded
|
||||
if (ObjectUtils.isEmpty(this.args)) {
|
||||
// Shortcut if no args need to be loaded
|
||||
if (ObjectUtils.isEmpty(this.arguments)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// save arguments as indexed variables
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
setVariable("a" + i, this.args[i]);
|
||||
setVariable("p" + i, this.args[i]);
|
||||
}
|
||||
// Expose indexed variables as well as parameter names (if discoverable)
|
||||
String[] paramNames = this.parameterNameDiscoverer.getParameterNames(this.method);
|
||||
int paramCount = (paramNames != null ? paramNames.length : this.method.getParameterCount());
|
||||
int argsCount = this.arguments.length;
|
||||
|
||||
String[] parameterNames = this.paramDiscoverer.getParameterNames(this.method);
|
||||
// save parameter names (if discovered)
|
||||
if (parameterNames != null) {
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
setVariable(parameterNames[i], this.args[i]);
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
Object value = null;
|
||||
if (argsCount > paramCount && i == paramCount - 1) {
|
||||
// Expose remaining arguments as vararg array for last parameter
|
||||
value = Arrays.copyOfRange(this.arguments, i, argsCount);
|
||||
}
|
||||
else if (argsCount > i) {
|
||||
// Actual argument found - otherwise left as null
|
||||
value = this.arguments[i];
|
||||
}
|
||||
setVariable("a" + i, value);
|
||||
setVariable("p" + i, value);
|
||||
if (paramNames != null) {
|
||||
setVariable(paramNames[i], value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user