Change IndexAccessor#read()'s return type to TypedValue

Prior to this commit, the read() method in the IndexAccessor SPI
declared a return type of ValueRef which introduced a package cycle.

This commit addresses this by aligning with the PropertyAccess SPI and
returning TypedValue from IndexAccessor's read() method. This commit
also reworks the internals of Indexer based on a new, local
IndexAccessorValueRef implementation.

See gh-26409
See gh-26478
This commit is contained in:
Sam Brannen
2024-03-27 10:45:21 +01:00
parent b7c3833732
commit 5c6b82a947
3 changed files with 68 additions and 39 deletions

View File

@@ -41,10 +41,10 @@ import org.springframework.expression.Expression;
import org.springframework.expression.IndexAccessor;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ast.ValueRef;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.testresources.Person;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -543,45 +543,23 @@ class IndexingTests {
}
@Override
public ValueRef read(EvaluationContext context, Object target, Object index) {
return new ArrayNodeValueRef((ArrayNode) target, (Integer) index, this.objectMapper);
public TypedValue read(EvaluationContext context, Object target, Object index) {
ArrayNode arrayNode = (ArrayNode) target;
Integer intIndex = (Integer) index;
return new TypedValue(arrayNode.get(intIndex));
}
@Override
public boolean canWrite(EvaluationContext context, Object target, Object index) {
return (target instanceof ArrayNode && index instanceof Integer);
return canRead(context, target, index);
}
@Override
public void write(EvaluationContext context, Object target, Object index, Object newValue) {
if (!(target instanceof ArrayNode arrayNode)) {
throw new IllegalStateException("target must be an ArrayNode: " + target.getClass().getName());
}
if (!(index instanceof Integer intIndex)) {
throw new IllegalStateException("index must be an integer: " + target.getClass().getName());
}
public void write(EvaluationContext context, Object target, Object index, @Nullable Object newValue) {
ArrayNode arrayNode = (ArrayNode) target;
Integer intIndex = (Integer) index;
arrayNode.set(intIndex, this.objectMapper.convertValue(newValue, JsonNode.class));
}
private record ArrayNodeValueRef(ArrayNode arrayNode, int index, ObjectMapper objectMapper) implements ValueRef {
@Override
public TypedValue getValue() {
return new TypedValue(this.arrayNode.get(this.index));
}
@Override
public void setValue(Object newValue) {
// TODO throw new UnsupportedOperationException("setValue() is not supported");
this.arrayNode.set(index, this.objectMapper.convertValue(newValue, JsonNode.class));
}
@Override
public boolean isWritable() {
return true;
}
}
}
}