Skip to content

Commit e9de426

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
1 parent cda577d commit e9de426

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
@@ -287,9 +287,7 @@ else if (this.indexedType == IndexedType.MAP) {
287287
mv.visitLdcInsn(mapKeyName);
288288
}
289289
else {
290-
cf.enterCompilationScope();
291-
index.generateCode(mv, cf);
292-
cf.exitCompilationScope();
290+
generateIndexCode(mv, cf, index, Object.class);
293291
}
294292
mv.visitMethodInsn(
295293
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
@@ -697,6 +697,53 @@ void indexIntoListUsingIntegerWrapper() {
697697
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
698698
}
699699

700+
@Test // gh-32903
701+
void indexIntoMapUsingPrimitiveLiteral() {
702+
Map<Object, String> map = Map.of(
703+
false, "0", // BooleanLiteral
704+
1, "ABC", // IntLiteral
705+
2L, "XYZ", // LongLiteral
706+
9.99F, "~10", // FloatLiteral
707+
3.14159, "PI" // RealLiteral
708+
);
709+
context.setVariable("map", map);
710+
711+
// BooleanLiteral
712+
expression = parser.parseExpression("#map[false]");
713+
assertThat(expression.getValue(context)).isEqualTo("0");
714+
assertCanCompile(expression);
715+
assertThat(expression.getValue(context)).isEqualTo("0");
716+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
717+
718+
// IntLiteral
719+
expression = parser.parseExpression("#map[1]");
720+
assertThat(expression.getValue(context)).isEqualTo("ABC");
721+
assertCanCompile(expression);
722+
assertThat(expression.getValue(context)).isEqualTo("ABC");
723+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
724+
725+
// LongLiteral
726+
expression = parser.parseExpression("#map[2L]");
727+
assertThat(expression.getValue(context)).isEqualTo("XYZ");
728+
assertCanCompile(expression);
729+
assertThat(expression.getValue(context)).isEqualTo("XYZ");
730+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
731+
732+
// FloatLiteral
733+
expression = parser.parseExpression("#map[9.99F]");
734+
assertThat(expression.getValue(context)).isEqualTo("~10");
735+
assertCanCompile(expression);
736+
assertThat(expression.getValue(context)).isEqualTo("~10");
737+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
738+
739+
// RealLiteral
740+
expression = parser.parseExpression("#map[3.14159]");
741+
assertThat(expression.getValue(context)).isEqualTo("PI");
742+
assertCanCompile(expression);
743+
assertThat(expression.getValue(context)).isEqualTo("PI");
744+
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
745+
}
746+
700747
private String stringify(Object object) {
701748
Stream<? extends Object> stream;
702749
if (object instanceof Collection<?> collection) {

0 commit comments

Comments
 (0)