Support compilation of array and list indexing with Integer in SpEL

Prior to this commit, the Spring Expression Language (SpEL) failed to
compile an expression that indexed into any array or list using an
Integer.

This commit adds support for compilation of such expressions by
ensuring that an Integer is unboxed into an int in the compiled
bytecode.

Closes gh-32694
This commit is contained in:
Sam Brannen 2024-04-23 11:34:18 +03:00
parent 8124491249
commit ca6d987c56
2 changed files with 33 additions and 2 deletions

View File

@ -416,13 +416,13 @@ public class Indexer extends SpelNodeImpl {
default -> AALOAD;
};
generateIndexCode(index, mv, cf);
generateIndexCode(index, int.class, mv, cf);
mv.visitInsn(insn);
}
else if (this.indexedType == IndexedType.LIST) {
mv.visitTypeInsn(CHECKCAST, "java/util/List");
generateIndexCode(index, mv, cf);
generateIndexCode(index, int.class, mv, cf);
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;", true);
}
@ -473,6 +473,11 @@ public class Indexer extends SpelNodeImpl {
cf.exitCompilationScope();
}
private void generateIndexCode(SpelNodeImpl indexNode, Class<?> indexType, MethodVisitor mv, CodeFlow cf) {
String indexDesc = CodeFlow.toDescriptor(indexType);
generateCodeForArgument(mv, cf, indexNode, indexDesc);
}
@Override
public String toStringAST() {
return "[" + getChild(0).toStringAST() + "]";

View File

@ -706,6 +706,32 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String");
}
@Test // gh-32694
void indexIntoArrayUsingIntegerWrapper() {
context.setVariable("array", new int[] {1, 2, 3, 4});
context.setVariable("index", 2);
expression = parser.parseExpression("#array[#index]");
assertThat(expression.getValue(context)).isEqualTo(3);
assertCanCompile(expression);
assertThat(expression.getValue(context)).isEqualTo(3);
assertThat(getAst().getExitDescriptor()).isEqualTo("I");
}
@Test // gh-32694
void indexIntoListUsingIntegerWrapper() {
context.setVariable("list", List.of(1, 2, 3, 4));
context.setVariable("index", 2);
expression = parser.parseExpression("#list[#index]");
assertThat(expression.getValue(context)).isEqualTo(3);
assertCanCompile(expression);
assertThat(expression.getValue(context)).isEqualTo(3);
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
}
private String stringify(Object object) {
Stream<? extends Object> stream;
if (object instanceof Collection<?> collection) {