Add IndexAccessor support to SpEL's SimpleEvaluationContext
Closes gh-32702
This commit is contained in:
parent
1e4275a0f9
commit
aaf33100d9
|
|
@ -27,6 +27,7 @@ import org.springframework.core.convert.ConversionService;
|
|||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.BeanResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.IndexAccessor;
|
||||
import org.springframework.expression.MethodResolver;
|
||||
import org.springframework.expression.OperatorOverloader;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
|
|
@ -107,6 +108,8 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
|||
|
||||
private final List<PropertyAccessor> propertyAccessors;
|
||||
|
||||
private final List<IndexAccessor> indexAccessors;
|
||||
|
||||
private final List<MethodResolver> methodResolvers;
|
||||
|
||||
private final TypeConverter typeConverter;
|
||||
|
|
@ -118,10 +121,11 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
|||
private final Map<String, Object> variables = new HashMap<>();
|
||||
|
||||
|
||||
private SimpleEvaluationContext(List<PropertyAccessor> accessors, List<MethodResolver> resolvers,
|
||||
@Nullable TypeConverter converter, @Nullable TypedValue rootObject) {
|
||||
private SimpleEvaluationContext(List<PropertyAccessor> propertyAccessors, List<IndexAccessor> indexAccessors,
|
||||
List<MethodResolver> resolvers, @Nullable TypeConverter converter, @Nullable TypedValue rootObject) {
|
||||
|
||||
this.propertyAccessors = accessors;
|
||||
this.propertyAccessors = propertyAccessors;
|
||||
this.indexAccessors = indexAccessors;
|
||||
this.methodResolvers = resolvers;
|
||||
this.typeConverter = (converter != null ? converter : new StandardTypeConverter());
|
||||
this.rootObject = (rootObject != null ? rootObject : TypedValue.NULL);
|
||||
|
|
@ -145,6 +149,16 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
|||
return this.propertyAccessors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specified {@link IndexAccessor} delegates, if any.
|
||||
* @since 6.2
|
||||
* @see Builder#withIndexAccessors(IndexAccessor...)
|
||||
*/
|
||||
@Override
|
||||
public List<IndexAccessor> getIndexAccessors() {
|
||||
return this.indexAccessors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specified {@link MethodResolver} delegates, if any.
|
||||
* @see Builder#withMethodResolvers
|
||||
|
|
@ -289,7 +303,9 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
|||
*/
|
||||
public static final class Builder {
|
||||
|
||||
private final List<PropertyAccessor> accessors;
|
||||
private final List<PropertyAccessor> propertyAccessors;
|
||||
|
||||
private List<IndexAccessor> indexAccessors = Collections.emptyList();
|
||||
|
||||
private List<MethodResolver> resolvers = Collections.emptyList();
|
||||
|
||||
|
|
@ -299,8 +315,20 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
|||
@Nullable
|
||||
private TypedValue rootObject;
|
||||
|
||||
|
||||
private Builder(PropertyAccessor... accessors) {
|
||||
this.accessors = Arrays.asList(accessors);
|
||||
this.propertyAccessors = Arrays.asList(accessors);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register the specified {@link IndexAccessor} delegates.
|
||||
* @param indexAccessors the index accessors to use
|
||||
* @since 6.2
|
||||
*/
|
||||
public Builder withIndexAccessors(IndexAccessor... indexAccessors) {
|
||||
this.indexAccessors = Arrays.asList(indexAccessors);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -381,7 +409,8 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
|||
}
|
||||
|
||||
public SimpleEvaluationContext build() {
|
||||
return new SimpleEvaluationContext(this.accessors, this.resolvers, this.typeConverter, this.rootObject);
|
||||
return new SimpleEvaluationContext(this.propertyAccessors, this.indexAccessors,
|
||||
this.resolvers, this.typeConverter, this.rootObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import org.springframework.expression.IndexAccessor;
|
|||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.SimpleEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.testresources.Person;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
|
@ -696,6 +697,31 @@ class IndexingTests {
|
|||
assertThat(expr.getValue(context, arrayNode)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void readAndWriteIndexWithSimpleEvaluationContext() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding()
|
||||
.withIndexAccessors(new JacksonArrayNodeIndexAccessor(objectMapper))
|
||||
.build();
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
TextNode node0 = new TextNode("node0");
|
||||
TextNode node1 = new TextNode("node1");
|
||||
ArrayNode arrayNode = objectMapper.createArrayNode();
|
||||
arrayNode.addAll(List.of(node0, node1));
|
||||
|
||||
Expression expr = parser.parseExpression("[0]");
|
||||
assertThat(expr.getValue(context, arrayNode)).isSameAs(node0);
|
||||
|
||||
TextNode nodeX = new TextNode("nodeX");
|
||||
expr.setValue(context, arrayNode, nodeX);
|
||||
// We use isEqualTo() instead of isSameAs(), since ObjectMapper.convertValue()
|
||||
// converts the supplied TextNode to an equivalent JsonNode.
|
||||
assertThat(expr.getValue(context, arrayNode)).isEqualTo(nodeX);
|
||||
|
||||
expr = parser.parseExpression("[1]");
|
||||
assertThat(expr.getValue(context, arrayNode)).isSameAs(node1);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IndexAccessor} that knows how to read and write indexes in a
|
||||
|
|
|
|||
Loading…
Reference in New Issue