Skip to content

Commit aed1d5f

Browse files
committed
Support compilation of map indexing with primitive in SpEL
Prior to this commit, the Spring Expression Language (SpEL) failed to compile an expression that indexed into a Map using a primitive literal (boolean, int, long, float, or double). This commit adds support for compilation of such expressions by ensuring that primitive literals are boxed into their corresponding wrapper types in the compiled bytecode. Closes gh-32903 (cherry picked from commit e9de426)
1 parent 079d53c commit aed1d5f

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,7 @@ else if (this.indexedType == IndexedType.MAP) {
283283
mv.visitLdcInsn(mapKeyName);
284284
}
285285
else {
286-
cf.enterCompilationScope();
287-
index.generateCode(mv, cf);
288-
cf.exitCompilationScope();
286+
generateIndexCode(mv, cf, index, Object.class);
289287
}
290288
mv.visitMethodInsn(
291289
INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true);

spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java

+47
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,53 @@ void indexIntoListUsingIntegerWrapper() {
554554
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
555555
}
556556

557+
@Test // gh-32903
558+
void indexIntoMapUsingPrimitiveLiteral() {
559+
Map<Object, String> map = Map.of(
560+
false, "0", // BooleanLiteral
561+
1, "ABC", // IntLiteral
562+
2L, "XYZ", // LongLiteral
563+
9.99F, "~10", // FloatLiteral
564+
3.14159, "PI" // RealLiteral
565+
);
566+
context.setVariable("map", map);
567+
568+
// BooleanLiteral
569+
expression = parser.parseExpression("#map[false]");
570+
assertThat(expression.getValue(context)).isEqualTo("0");
571+
assertCanCompile(expression);
572+
assertThat(expression.getValue(context)).isEqualTo("0");
573+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
574+
575+
// IntLiteral
576+
expression = parser.parseExpression("#map[1]");
577+
assertThat(expression.getValue(context)).isEqualTo("ABC");
578+
assertCanCompile(expression);
579+
assertThat(expression.getValue(context)).isEqualTo("ABC");
580+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
581+
582+
// LongLiteral
583+
expression = parser.parseExpression("#map[2L]");
584+
assertThat(expression.getValue(context)).isEqualTo("XYZ");
585+
assertCanCompile(expression);
586+
assertThat(expression.getValue(context)).isEqualTo("XYZ");
587+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
588+
589+
// FloatLiteral
590+
expression = parser.parseExpression("#map[9.99F]");
591+
assertThat(expression.getValue(context)).isEqualTo("~10");
592+
assertCanCompile(expression);
593+
assertThat(expression.getValue(context)).isEqualTo("~10");
594+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
595+
596+
// RealLiteral
597+
expression = parser.parseExpression("#map[3.14159]");
598+
assertThat(expression.getValue(context)).isEqualTo("PI");
599+
assertCanCompile(expression);
600+
assertThat(expression.getValue(context)).isEqualTo("PI");
601+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
602+
}
603+
557604
private String stringify(Object object) {
558605
Stream<? extends Object> stream;
559606
if (object instanceof Collection<?> collection) {

0 commit comments

Comments
 (0)