diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java index 0792cb1d50..8b0ad033ea 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java @@ -19,7 +19,6 @@ package org.springframework.expression.spel; import org.springframework.asm.MethodVisitor; import org.springframework.asm.Opcodes; import org.springframework.expression.PropertyAccessor; -import org.springframework.lang.Nullable; /** * A compilable {@link PropertyAccessor} is able to generate bytecode that represents @@ -45,14 +44,10 @@ public interface CompilablePropertyAccessor extends PropertyAccessor, Opcodes { * Generate the bytecode that performs the access operation into the specified * {@link MethodVisitor} using context information from the {@link CodeFlow} * where necessary. - *
Concrete implementations of {@code CompilablePropertyAccessor} typically - * have access to the property name via other means (for example, supplied as - * an argument when they were instantiated). Thus, the {@code propertyName} - * supplied to this method may be {@code null}. - * @param propertyName the name of the property, or {@code null} if not available + * @param propertyName the name of the property * @param methodVisitor the ASM method visitor into which code should be generated * @param codeFlow the current state of the expression compiler */ - void generateCode(@Nullable String propertyName, MethodVisitor methodVisitor, CodeFlow codeFlow); + void generateCode(String propertyName, MethodVisitor methodVisitor, CodeFlow codeFlow); } 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 85665adf50..b5829cd36b 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 @@ -213,16 +213,17 @@ public class Indexer extends SpelNodeImpl { if (this.indexedType == IndexedType.ARRAY) { return (this.exitTypeDescriptor != null); } - else if (this.indexedType == IndexedType.LIST) { - return this.children[0].isCompilable(); + SpelNodeImpl index = this.children[0]; + if (this.indexedType == IndexedType.LIST) { + return index.isCompilable(); } else if (this.indexedType == IndexedType.MAP) { - return (this.children[0] instanceof PropertyOrFieldReference || this.children[0].isCompilable()); + return (index instanceof PropertyOrFieldReference || index.isCompilable()); } else if (this.indexedType == IndexedType.OBJECT) { // If the string name is changing, the accessor is clearly going to change. // So compilation is only possible if the index expression is a StringLiteral. - return (getChild(0) instanceof StringLiteral && + return (index instanceof StringLiteral && this.cachedReadAccessor instanceof CompilablePropertyAccessor compilablePropertyAccessor && compilablePropertyAccessor.isCompilable()); } @@ -238,6 +239,7 @@ public class Indexer extends SpelNodeImpl { } SpelNodeImpl index = this.children[0]; + if (this.indexedType == IndexedType.ARRAY) { int insn = switch (this.exitTypeDescriptor) { case "D" -> { @@ -313,9 +315,14 @@ public class Indexer extends SpelNodeImpl { } else if (this.indexedType == IndexedType.OBJECT) { + if (!(index instanceof StringLiteral stringLiteral)) { + throw new IllegalStateException( + "Index expression must be a StringLiteral, but was: " + index.getClass().getName()); + } CompilablePropertyAccessor compilablePropertyAccessor = (CompilablePropertyAccessor) this.cachedReadAccessor; Assert.state(compilablePropertyAccessor != null, "No cached read accessor"); - compilablePropertyAccessor.generateCode(null, mv, cf); + String propertyName = (String) stringLiteral.getLiteralValue().getValue(); + compilablePropertyAccessor.generateCode(propertyName, mv, cf); } cf.pushDescriptor(this.exitTypeDescriptor); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 307984d7e7..322a275c62 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -712,7 +712,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } @Override - public void generateCode(@Nullable String propertyName, MethodVisitor mv, CodeFlow cf) { + public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) { Class> publicDeclaringClass = this.member.getDeclaringClass(); if (!Modifier.isPublic(publicDeclaringClass.getModifiers()) && this.originalMethod != null) { publicDeclaringClass = ReflectionHelper.findPublicDeclaringClass(this.originalMethod);