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. See gh-32694 Closes gh-32908
This commit is contained in:
parent
8feb842df5
commit
cda577d1aa
|
@ -221,6 +221,8 @@ public class Indexer extends SpelNodeImpl {
|
|||
cf.loadTarget(mv);
|
||||
}
|
||||
|
||||
SpelNodeImpl index = this.children[0];
|
||||
|
||||
if (this.indexedType == IndexedType.ARRAY) {
|
||||
String exitTypeDescriptor = this.exitTypeDescriptor;
|
||||
Assert.state(exitTypeDescriptor != null, "Array not compilable without descriptor");
|
||||
|
@ -266,18 +268,13 @@ public class Indexer extends SpelNodeImpl {
|
|||
}
|
||||
};
|
||||
|
||||
SpelNodeImpl index = this.children[0];
|
||||
cf.enterCompilationScope();
|
||||
index.generateCode(mv, cf);
|
||||
cf.exitCompilationScope();
|
||||
generateIndexCode(mv, cf, index, int.class);
|
||||
mv.visitInsn(insn);
|
||||
}
|
||||
|
||||
else if (this.indexedType == IndexedType.LIST) {
|
||||
mv.visitTypeInsn(CHECKCAST, "java/util/List");
|
||||
cf.enterCompilationScope();
|
||||
this.children[0].generateCode(mv, cf);
|
||||
cf.exitCompilationScope();
|
||||
generateIndexCode(mv, cf, index, int.class);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;", true);
|
||||
}
|
||||
|
||||
|
@ -285,13 +282,13 @@ 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 ((this.children[0] instanceof PropertyOrFieldReference reference)) {
|
||||
if ((index instanceof PropertyOrFieldReference reference)) {
|
||||
String mapKeyName = reference.getName();
|
||||
mv.visitLdcInsn(mapKeyName);
|
||||
}
|
||||
else {
|
||||
cf.enterCompilationScope();
|
||||
this.children[0].generateCode(mv, cf);
|
||||
index.generateCode(mv, cf);
|
||||
cf.exitCompilationScope();
|
||||
}
|
||||
mv.visitMethodInsn(
|
||||
|
@ -328,6 +325,11 @@ public class Indexer extends SpelNodeImpl {
|
|||
cf.pushDescriptor(this.exitTypeDescriptor);
|
||||
}
|
||||
|
||||
private void generateIndexCode(MethodVisitor mv, CodeFlow cf, SpelNodeImpl indexNode, Class<?> indexType) {
|
||||
String indexDesc = CodeFlow.toDescriptor(indexType);
|
||||
generateCodeForArgument(mv, cf, indexNode, indexDesc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
return "[" + getChild(0).toStringAST() + "]";
|
||||
|
|
|
@ -671,6 +671,32 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
|
|||
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String");
|
||||
}
|
||||
|
||||
@Test // gh-32694, gh-32908
|
||||
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, gh-32908
|
||||
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) {
|
||||
|
|
Loading…
Reference in New Issue