Only cache resolved method when coming from ReflectiveMethodResolver
Issue: SPR-9495
(cherry picked from commit b7ff26a
)
This commit is contained in:
parent
b9d726fb84
commit
6de67cc2df
|
@ -32,6 +32,7 @@ import org.springframework.expression.TypedValue;
|
||||||
import org.springframework.expression.spel.ExpressionState;
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
import org.springframework.expression.spel.SpelEvaluationException;
|
import org.springframework.expression.spel.SpelEvaluationException;
|
||||||
import org.springframework.expression.spel.SpelMessage;
|
import org.springframework.expression.spel.SpelMessage;
|
||||||
|
import org.springframework.expression.spel.support.ReflectiveMethodResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expression language AST node that represents a method reference.
|
* Expression language AST node that represents a method reference.
|
||||||
|
@ -88,7 +89,7 @@ public class MethodReference extends SpelNodeImpl {
|
||||||
return TypedValue.NULL;
|
return TypedValue.NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodExecutor executorToUse = getCachedExecutor(value, targetType, argumentTypes);
|
MethodExecutor executorToUse = getCachedExecutor(evaluationContext, value, targetType, argumentTypes);
|
||||||
if (executorToUse != null) {
|
if (executorToUse != null) {
|
||||||
try {
|
try {
|
||||||
return executorToUse.execute(evaluationContext, value, arguments);
|
return executorToUse.execute(evaluationContext, value, arguments);
|
||||||
|
@ -104,8 +105,7 @@ public class MethodReference extends SpelNodeImpl {
|
||||||
|
|
||||||
// To determine the situation, the AccessException will contain a cause.
|
// To determine the situation, the AccessException will contain a cause.
|
||||||
// If the cause is an InvocationTargetException, a user exception was
|
// If the cause is an InvocationTargetException, a user exception was
|
||||||
// thrown inside the method.
|
// thrown inside the method. Otherwise the method could not be invoked.
|
||||||
// Otherwise the method could not be invoked.
|
|
||||||
throwSimpleExceptionIfPossible(value, ae);
|
throwSimpleExceptionIfPossible(value, ae);
|
||||||
|
|
||||||
// At this point we know it wasn't a user problem so worth a retry if a
|
// At this point we know it wasn't a user problem so worth a retry if a
|
||||||
|
@ -161,7 +161,16 @@ public class MethodReference extends SpelNodeImpl {
|
||||||
return Collections.unmodifiableList(descriptors);
|
return Collections.unmodifiableList(descriptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodExecutor getCachedExecutor(Object value, TypeDescriptor target, List<TypeDescriptor> argumentTypes) {
|
private MethodExecutor getCachedExecutor(EvaluationContext evaluationContext, Object value,
|
||||||
|
TypeDescriptor target, List<TypeDescriptor> argumentTypes) {
|
||||||
|
|
||||||
|
List<MethodResolver> methodResolvers = evaluationContext.getMethodResolvers();
|
||||||
|
if (methodResolvers == null || methodResolvers.size() != 1 ||
|
||||||
|
!(methodResolvers.get(0) instanceof ReflectiveMethodResolver)) {
|
||||||
|
// Not a default ReflectiveMethodResolver - don't know whether caching is valid
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
CachedMethodExecutor executorToCheck = this.cachedExecutor;
|
CachedMethodExecutor executorToCheck = this.cachedExecutor;
|
||||||
if (executorToCheck != null && executorToCheck.isSuitable(value, target, argumentTypes)) {
|
if (executorToCheck != null && executorToCheck.isSuitable(value, target, argumentTypes)) {
|
||||||
return executorToCheck.get();
|
return executorToCheck.get();
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.convert.TypeDescriptor;
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
import org.springframework.expression.AccessException;
|
import org.springframework.expression.AccessException;
|
||||||
import org.springframework.expression.BeanResolver;
|
import org.springframework.expression.BeanResolver;
|
||||||
|
@ -1775,6 +1776,47 @@ public class SpelReproTests extends ExpressionTestCase {
|
||||||
assertEquals(XYZ.Z, Array.get(result, 2));
|
assertEquals(XYZ.Z, Array.get(result, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void SPR_9495() throws Exception {
|
||||||
|
SpelParserConfiguration configuration = new SpelParserConfiguration(false, false);
|
||||||
|
ExpressionParser parser = new SpelExpressionParser(configuration);
|
||||||
|
|
||||||
|
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||||
|
Expression spel = parser.parseExpression("#enumType.values()");
|
||||||
|
|
||||||
|
context.setVariable("enumType", ABC.class);
|
||||||
|
Object result = spel.getValue(context);
|
||||||
|
assertNotNull(result);
|
||||||
|
assertTrue(result.getClass().isArray());
|
||||||
|
assertEquals(ABC.A, Array.get(result, 0));
|
||||||
|
assertEquals(ABC.B, Array.get(result, 1));
|
||||||
|
assertEquals(ABC.C, Array.get(result, 2));
|
||||||
|
|
||||||
|
context.addMethodResolver(new MethodResolver() {
|
||||||
|
@Override
|
||||||
|
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, List<TypeDescriptor> argumentTypes) throws AccessException {
|
||||||
|
return new MethodExecutor() {
|
||||||
|
@Override
|
||||||
|
public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException {
|
||||||
|
try {
|
||||||
|
Method method = XYZ.class.getMethod("values");
|
||||||
|
Object value = method.invoke(target, arguments);
|
||||||
|
return new TypedValue(value, new TypeDescriptor(new MethodParameter(method, -1)).narrow(value));
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new AccessException(ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
result = spel.getValue(context);
|
||||||
|
assertNotNull(result);
|
||||||
|
assertTrue(result.getClass().isArray());
|
||||||
|
assertEquals(XYZ.X, Array.get(result, 0));
|
||||||
|
assertEquals(XYZ.Y, Array.get(result, 1));
|
||||||
|
assertEquals(XYZ.Z, Array.get(result, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static enum ABC {A, B, C}
|
private static enum ABC {A, B, C}
|
||||||
|
|
Loading…
Reference in New Issue