Closed
Description
Oliver Drotbohm opened SPR-15769 and commented
A PropertyOrFieldReference
caches the PropertyAccessor
used for the first evaluation of the node. However, if a new EvaluationContext
is provided and a completely different set of PropertyAccessor
instances is used, none of them actually ever get considered.
The test case below uses a custom PropertyAccessor
that holds a Map
of values. The second part of the test registers a new instance of it with different values and still the evaluation returns the old value.
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.Map;
import org.junit.Test;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
/**
* @author Oliver Gierke
*/
public class PropertyOrFieldReferenceCachingIssue {
@Test
public void shouldAlwaysUsePropertyAccessorFromEvaluationContext() {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("name");
StandardEvaluationContext context = new StandardEvaluationContext();
context.addPropertyAccessor(new ConfigurablePropertyAccessor(Collections.singletonMap("name", "Ollie")));
assertThat(expression.getValue(context), is("Ollie"));
context = new StandardEvaluationContext();
context.addPropertyAccessor(new ConfigurablePropertyAccessor(Collections.singletonMap("name", "Jens")));
assertThat(expression.getValue(context), is("Jens"));
}
static class ConfigurablePropertyAccessor implements PropertyAccessor {
private final Map<String, Object> values;
public ConfigurablePropertyAccessor(Map<String, Object> values) {
this.values = values;
}
@Override
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
return true;
}
@Override
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
return false;
}
@Override
public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {}
@Override
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
return new TypedValue(values.get(name));
}
@Override
public Class<?>[] getSpecificTargetClasses() {
return null;
}
}
}
Affects: 4.3.9, 5.0 RC2
Issue Links:
- ReflectivePropertyAccessor should cache sorted methods [SPR-16882] #21421 ReflectivePropertyAccessor should cache sorted methods