diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java
index b06e0833fc..ff00a7b101 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java
@@ -54,10 +54,11 @@ import org.springframework.util.ReflectionUtils;
*
*
* - Arrays: the nth element
- * - Collections (lists and sets): the nth element
+ * - Collections (lists, sets, etc.): the nth element
* - Strings: the nth character as a {@link String}
* - Maps: the value for the specified key
* - Objects: the property with the specified name
+ * - Custom Structures: via registered {@link IndexAccessor} implementations
*
*
* Null-safe Indexing
@@ -72,6 +73,9 @@ import org.springframework.util.ReflectionUtils;
* @author Stephane Nicoll
* @author Sam Brannen
* @since 3.0
+ * @see org.springframework.expression.IndexAccessor
+ * @see org.springframework.expression.spel.CompilableIndexAccessor
+ * @see org.springframework.expression.spel.support.ReflectiveIndexAccessor
*/
public class Indexer extends SpelNodeImpl {
@@ -385,7 +389,7 @@ public class Indexer extends SpelNodeImpl {
mv.visitTypeInsn(CHECKCAST, "java/util/Map");
// Special case when the key is an unquoted string literal that will be parsed as
// a property/field reference
- if ((index instanceof PropertyOrFieldReference reference)) {
+ if (index instanceof PropertyOrFieldReference reference) {
String mapKeyName = reference.getName();
mv.visitLdcInsn(mapKeyName);
}
@@ -849,6 +853,7 @@ public class Indexer extends SpelNodeImpl {
exitTypeDescriptor = CodeFlow.toDescriptor(Object.class);
return new TypedValue(o, this.collectionEntryDescriptor.elementTypeDescriptor(o));
}
+
int pos = 0;
for (Object o : this.collection) {
if (pos == this.index) {
@@ -856,23 +861,23 @@ public class Indexer extends SpelNodeImpl {
}
pos++;
}
- throw new IllegalStateException("Failed to find indexed element " + this.index + ": " + this.collection);
+ throw new SpelEvaluationException(getStartPosition(), SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS,
+ this.collection.size(), this.index);
}
@Override
public void setValue(@Nullable Object newValue) {
- growCollectionIfNecessary();
- if (this.collection instanceof List list) {
- if (this.collectionEntryDescriptor.getElementTypeDescriptor() != null) {
- newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue),
- this.collectionEntryDescriptor.getElementTypeDescriptor());
- }
- list.set(this.index, newValue);
- }
- else {
+ if (!(this.collection instanceof List list)) {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
this.collectionEntryDescriptor.toString());
}
+
+ growCollectionIfNecessary();
+ if (this.collectionEntryDescriptor.getElementTypeDescriptor() != null) {
+ newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue),
+ this.collectionEntryDescriptor.getElementTypeDescriptor());
+ }
+ list.set(this.index, newValue);
}
private void growCollectionIfNecessary() {
@@ -906,7 +911,7 @@ public class Indexer extends SpelNodeImpl {
@Override
public boolean isWritable() {
- return true;
+ return (this.collection instanceof List);
}
@Nullable