Support String index type in custom IndexAccessor
Closes gh-32706
This commit is contained in:
parent
a3d3bc0a1f
commit
14689256c4
|
@ -244,14 +244,7 @@ public class Indexer extends SpelNodeImpl {
|
|||
}
|
||||
}
|
||||
|
||||
// Try to treat the index value as a property of the context object.
|
||||
TypeDescriptor valueType = indexValue.getTypeDescriptor();
|
||||
if (valueType != null && String.class == valueType.getType()) {
|
||||
this.indexedType = IndexedType.OBJECT;
|
||||
return new PropertyAccessorValueRef(
|
||||
target, (String) index, state.getEvaluationContext(), targetDescriptor);
|
||||
}
|
||||
|
||||
// Check for a custom IndexAccessor.
|
||||
EvaluationContext evalContext = state.getEvaluationContext();
|
||||
List<IndexAccessor> accessorsToTry = getIndexAccessorsToTry(target, evalContext.getIndexAccessors());
|
||||
if (accessMode.supportsReads) {
|
||||
|
@ -285,6 +278,14 @@ public class Indexer extends SpelNodeImpl {
|
|||
}
|
||||
}
|
||||
|
||||
// As a last resort, try to treat the index value as a property of the context object.
|
||||
TypeDescriptor valueType = indexValue.getTypeDescriptor();
|
||||
if (valueType != null && String.class == valueType.getType()) {
|
||||
this.indexedType = IndexedType.OBJECT;
|
||||
return new PropertyAccessorValueRef(
|
||||
target, (String) index, state.getEvaluationContext(), targetDescriptor);
|
||||
}
|
||||
|
||||
throw new SpelEvaluationException(
|
||||
getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetDescriptor);
|
||||
}
|
||||
|
|
|
@ -711,6 +711,72 @@ class IndexingTests {
|
|||
assertThat(expr.getValue(context, arrayNode)).isSameAs(node1);
|
||||
}
|
||||
|
||||
@Test // gh-32706
|
||||
void readIndexWithStringIndexType() {
|
||||
BirdNameToColorMappings birdNameMappings = new BirdNameToColorMappings();
|
||||
|
||||
// Without a registered BirdNameToColorMappingsIndexAccessor, we should
|
||||
// be able to index into an object via a property name.
|
||||
Expression propertyExpression = parser.parseExpression("['property']");
|
||||
assertThat(propertyExpression.getValue(context, birdNameMappings)).isEqualTo("enigma");
|
||||
|
||||
context.addIndexAccessor(new BirdNameToColorMappingsIndexAccessor());
|
||||
|
||||
Expression expression = parser.parseExpression("['cardinal']");
|
||||
assertThat(expression.getValue(context, birdNameMappings)).isEqualTo(Color.RED);
|
||||
|
||||
// With a registered BirdNameToColorMappingsIndexAccessor, an attempt
|
||||
// to index into an object via a property name should fail.
|
||||
assertThatExceptionOfType(SpelEvaluationException.class)
|
||||
.isThrownBy(() -> propertyExpression.getValue(context, birdNameMappings))
|
||||
.withMessageEndingWith("A problem occurred while attempting to read index '%s' in '%s'",
|
||||
"property", BirdNameToColorMappings.class.getName())
|
||||
.havingCause().withMessage("unknown bird color: property");
|
||||
}
|
||||
|
||||
static class BirdNameToColorMappings {
|
||||
|
||||
public final String property = "enigma";
|
||||
|
||||
public Color get(String name) {
|
||||
return switch (name) {
|
||||
case "cardinal" -> Color.RED;
|
||||
case "blue jay" -> Color.BLUE;
|
||||
default -> throw new RuntimeException("unknown bird color: " + name);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static class BirdNameToColorMappingsIndexAccessor implements IndexAccessor {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getSpecificTargetClasses() {
|
||||
return new Class[] { BirdNameToColorMappings.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(EvaluationContext context, Object target, Object index) {
|
||||
return (target instanceof BirdNameToColorMappings && index instanceof String);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue read(EvaluationContext context, Object target, Object index) {
|
||||
BirdNameToColorMappings mappings = (BirdNameToColorMappings) target;
|
||||
String name = (String) index;
|
||||
return new TypedValue(mappings.get(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(EvaluationContext context, Object target, Object index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(EvaluationContext context, Object target, Object index, @Nullable Object newValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IndexAccessor} that knows how to read and write indexes in a
|
||||
* Jackson {@link ArrayNode}.
|
||||
|
|
Loading…
Reference in New Issue