Skip to content

Commit

Permalink
Add IndexAccessor support to SpEL's SimpleEvaluationContext
Browse files Browse the repository at this point in the history
Closes gh-32702
  • Loading branch information
sbrannen committed Apr 24, 2024
1 parent 1e4275a commit aaf3310
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -145,6 +149,16 @@ public List<PropertyAccessor> getPropertyAccessors() {
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
Expand Down Expand Up @@ -289,7 +303,9 @@ public static Builder forReadWriteDataBinding() {
*/
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();

Expand All @@ -299,8 +315,20 @@ public static final class Builder {
@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;
}

/**
Expand Down Expand Up @@ -381,7 +409,8 @@ public Builder withTypedRootObject(Object rootObject, TypeDescriptor typeDescrip
}

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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
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;
Expand Down Expand Up @@ -696,6 +697,31 @@ void readAndWriteIndex() {
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
Expand Down

0 comments on commit aaf3310

Please sign in to comment.