Skip to content

Commit aaf3310

Browse files
committed
Add IndexAccessor support to SpEL's SimpleEvaluationContext
Closes gh-32702
1 parent 1e4275a commit aaf3310

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/support/SimpleEvaluationContext.java

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.core.convert.TypeDescriptor;
2828
import org.springframework.expression.BeanResolver;
2929
import org.springframework.expression.EvaluationContext;
30+
import org.springframework.expression.IndexAccessor;
3031
import org.springframework.expression.MethodResolver;
3132
import org.springframework.expression.OperatorOverloader;
3233
import org.springframework.expression.PropertyAccessor;
@@ -107,6 +108,8 @@ public final class SimpleEvaluationContext implements EvaluationContext {
107108

108109
private final List<PropertyAccessor> propertyAccessors;
109110

111+
private final List<IndexAccessor> indexAccessors;
112+
110113
private final List<MethodResolver> methodResolvers;
111114

112115
private final TypeConverter typeConverter;
@@ -118,10 +121,11 @@ public final class SimpleEvaluationContext implements EvaluationContext {
118121
private final Map<String, Object> variables = new HashMap<>();
119122

120123

121-
private SimpleEvaluationContext(List<PropertyAccessor> accessors, List<MethodResolver> resolvers,
122-
@Nullable TypeConverter converter, @Nullable TypedValue rootObject) {
124+
private SimpleEvaluationContext(List<PropertyAccessor> propertyAccessors, List<IndexAccessor> indexAccessors,
125+
List<MethodResolver> resolvers, @Nullable TypeConverter converter, @Nullable TypedValue rootObject) {
123126

124-
this.propertyAccessors = accessors;
127+
this.propertyAccessors = propertyAccessors;
128+
this.indexAccessors = indexAccessors;
125129
this.methodResolvers = resolvers;
126130
this.typeConverter = (converter != null ? converter : new StandardTypeConverter());
127131
this.rootObject = (rootObject != null ? rootObject : TypedValue.NULL);
@@ -145,6 +149,16 @@ public List<PropertyAccessor> getPropertyAccessors() {
145149
return this.propertyAccessors;
146150
}
147151

152+
/**
153+
* Return the specified {@link IndexAccessor} delegates, if any.
154+
* @since 6.2
155+
* @see Builder#withIndexAccessors(IndexAccessor...)
156+
*/
157+
@Override
158+
public List<IndexAccessor> getIndexAccessors() {
159+
return this.indexAccessors;
160+
}
161+
148162
/**
149163
* Return the specified {@link MethodResolver} delegates, if any.
150164
* @see Builder#withMethodResolvers
@@ -289,7 +303,9 @@ public static Builder forReadWriteDataBinding() {
289303
*/
290304
public static final class Builder {
291305

292-
private final List<PropertyAccessor> accessors;
306+
private final List<PropertyAccessor> propertyAccessors;
307+
308+
private List<IndexAccessor> indexAccessors = Collections.emptyList();
293309

294310
private List<MethodResolver> resolvers = Collections.emptyList();
295311

@@ -299,8 +315,20 @@ public static final class Builder {
299315
@Nullable
300316
private TypedValue rootObject;
301317

318+
302319
private Builder(PropertyAccessor... accessors) {
303-
this.accessors = Arrays.asList(accessors);
320+
this.propertyAccessors = Arrays.asList(accessors);
321+
}
322+
323+
324+
/**
325+
* Register the specified {@link IndexAccessor} delegates.
326+
* @param indexAccessors the index accessors to use
327+
* @since 6.2
328+
*/
329+
public Builder withIndexAccessors(IndexAccessor... indexAccessors) {
330+
this.indexAccessors = Arrays.asList(indexAccessors);
331+
return this;
304332
}
305333

306334
/**
@@ -381,7 +409,8 @@ public Builder withTypedRootObject(Object rootObject, TypeDescriptor typeDescrip
381409
}
382410

383411
public SimpleEvaluationContext build() {
384-
return new SimpleEvaluationContext(this.accessors, this.resolvers, this.typeConverter, this.rootObject);
412+
return new SimpleEvaluationContext(this.propertyAccessors, this.indexAccessors,
413+
this.resolvers, this.typeConverter, this.rootObject);
385414
}
386415
}
387416

spring-expression/src/test/java/org/springframework/expression/spel/IndexingTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.springframework.expression.PropertyAccessor;
4444
import org.springframework.expression.TypedValue;
4545
import org.springframework.expression.spel.standard.SpelExpressionParser;
46+
import org.springframework.expression.spel.support.SimpleEvaluationContext;
4647
import org.springframework.expression.spel.support.StandardEvaluationContext;
4748
import org.springframework.expression.spel.testresources.Person;
4849
import org.springframework.lang.Nullable;
@@ -696,6 +697,31 @@ void readAndWriteIndex() {
696697
assertThat(expr.getValue(context, arrayNode)).isNull();
697698
}
698699

700+
@Test
701+
void readAndWriteIndexWithSimpleEvaluationContext() {
702+
ObjectMapper objectMapper = new ObjectMapper();
703+
SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding()
704+
.withIndexAccessors(new JacksonArrayNodeIndexAccessor(objectMapper))
705+
.build();
706+
SpelExpressionParser parser = new SpelExpressionParser();
707+
708+
TextNode node0 = new TextNode("node0");
709+
TextNode node1 = new TextNode("node1");
710+
ArrayNode arrayNode = objectMapper.createArrayNode();
711+
arrayNode.addAll(List.of(node0, node1));
712+
713+
Expression expr = parser.parseExpression("[0]");
714+
assertThat(expr.getValue(context, arrayNode)).isSameAs(node0);
715+
716+
TextNode nodeX = new TextNode("nodeX");
717+
expr.setValue(context, arrayNode, nodeX);
718+
// We use isEqualTo() instead of isSameAs(), since ObjectMapper.convertValue()
719+
// converts the supplied TextNode to an equivalent JsonNode.
720+
assertThat(expr.getValue(context, arrayNode)).isEqualTo(nodeX);
721+
722+
expr = parser.parseExpression("[1]");
723+
assertThat(expr.getValue(context, arrayNode)).isSameAs(node1);
724+
}
699725

700726
/**
701727
* {@link IndexAccessor} that knows how to read and write indexes in a

0 commit comments

Comments
 (0)