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 ff00a7b1018..969b50e46cc 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 @@ -810,6 +810,8 @@ public class Indexer extends SpelNodeImpl { throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE, this.name, ex.getMessage()); } + throw new SpelEvaluationException(getStartPosition(), + SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, this.targetObjectTypeDescriptor.toString()); } @Override diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java index 287644f8453..d0ef7f889f0 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import org.assertj.core.api.ThrowableTypeAssert; import org.junit.jupiter.api.Test; import org.springframework.core.convert.TypeDescriptor; @@ -83,11 +84,11 @@ class PropertyAccessTests extends AbstractExpressionTests { void accessingOnNullObject() { SpelExpression expr = (SpelExpression) parser.parseExpression("madeup"); EvaluationContext context = new StandardEvaluationContext(null); - assertThatExceptionOfType(SpelEvaluationException.class) + assertThatSpelEvaluationException() .isThrownBy(() -> expr.getValue(context)) .extracting(SpelEvaluationException::getMessageCode).isEqualTo(SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL); assertThat(expr.isWritable(context)).isFalse(); - assertThatExceptionOfType(SpelEvaluationException.class) + assertThatSpelEvaluationException() .isThrownBy(() -> expr.setValue(context, "abc")) .extracting(SpelEvaluationException::getMessageCode).isEqualTo(SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL); } @@ -117,8 +118,7 @@ class PropertyAccessTests extends AbstractExpressionTests { assertThat((int) i).isEqualTo(99); // Cannot set it to a string value - assertThatExceptionOfType(EvaluationException.class).isThrownBy(() -> - flibbleexpr.setValue(ctx, "not allowed")); + assertThatSpelEvaluationException().isThrownBy(() -> flibbleexpr.setValue(ctx, "not allowed")); // message will be: EL1063E:(pos 20): A problem occurred whilst attempting to set the property // 'flibbles': 'Cannot set flibbles to an object of type 'class java.lang.String'' // System.out.println(e.getMessage()); @@ -173,8 +173,7 @@ class PropertyAccessTests extends AbstractExpressionTests { @Test void noGetClassAccess() { EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); - assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() -> - parser.parseExpression("'a'.class.name").getValue(context)); + assertThatSpelEvaluationException().isThrownBy(() -> parser.parseExpression("'a'.class.name").getValue(context)); } @Test @@ -187,8 +186,13 @@ class PropertyAccessTests extends AbstractExpressionTests { target.setName("p2"); assertThat(expr.getValue(context, target)).isEqualTo("p2"); - assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() -> - parser.parseExpression("name='p3'").getValue(context, target)); + assertThatSpelEvaluationException() + .isThrownBy(() -> parser.parseExpression("name='p3'").getValue(context, target)) + .extracting(SpelEvaluationException::getMessageCode).isEqualTo(SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE); + + assertThatSpelEvaluationException() + .isThrownBy(() -> parser.parseExpression("['name']='p4'").getValue(context, target)) + .extracting(SpelEvaluationException::getMessageCode).isEqualTo(SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE); } @Test @@ -201,8 +205,9 @@ class PropertyAccessTests extends AbstractExpressionTests { RecordPerson target2 = new RecordPerson("p2"); assertThat(expr.getValue(context, target2)).isEqualTo("p2"); - assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() -> - parser.parseExpression("name='p3'").getValue(context, target2)); + assertThatSpelEvaluationException() + .isThrownBy(() -> parser.parseExpression("name='p3'").getValue(context, target2)) + .extracting(SpelEvaluationException::getMessageCode).isEqualTo(SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE); } @Test @@ -248,7 +253,7 @@ class PropertyAccessTests extends AbstractExpressionTests { void propertyAccessWithoutMethodResolver() { EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); Person target = new Person("p1"); - assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() -> + assertThatSpelEvaluationException().isThrownBy(() -> parser.parseExpression("name.substring(1)").getValue(context, target)); } @@ -274,12 +279,17 @@ class PropertyAccessTests extends AbstractExpressionTests { void propertyAccessWithArrayIndexOutOfBounds() { EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); Expression expression = parser.parseExpression("stringArrayOfThreeItems[3]"); - assertThatExceptionOfType(SpelEvaluationException.class) + assertThatSpelEvaluationException() .isThrownBy(() -> expression.getValue(context, new Inventor())) .extracting(SpelEvaluationException::getMessageCode).isEqualTo(SpelMessage.ARRAY_INDEX_OUT_OF_BOUNDS); } + private ThrowableTypeAssert assertThatSpelEvaluationException() { + return assertThatExceptionOfType(SpelEvaluationException.class); + } + + // This can resolve the property 'flibbles' on any String (very useful...) private static class StringyPropertyAccessor implements PropertyAccessor {