Skip to content

Commit

Permalink
Support compilation of map indexing with primitive in SpEL
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
sbrannen committed May 28, 2024
1 parent 079d53c commit aed1d5f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,7 @@ else if (this.indexedType == IndexedType.MAP) {
mv.visitLdcInsn(mapKeyName);
}
else {
cf.enterCompilationScope();
index.generateCode(mv, cf);
cf.exitCompilationScope();
generateIndexCode(mv, cf, index, Object.class);
}
mv.visitMethodInsn(
INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,53 @@ void indexIntoListUsingIntegerWrapper() {
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
}

@Test // gh-32903
void indexIntoMapUsingPrimitiveLiteral() {
Map<Object, String> map = Map.of(
false, "0", // BooleanLiteral
1, "ABC", // IntLiteral
2L, "XYZ", // LongLiteral
9.99F, "~10", // FloatLiteral
3.14159, "PI" // RealLiteral
);
context.setVariable("map", map);

// BooleanLiteral
expression = parser.parseExpression("#map[false]");
assertThat(expression.getValue(context)).isEqualTo("0");
assertCanCompile(expression);
assertThat(expression.getValue(context)).isEqualTo("0");
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");

// IntLiteral
expression = parser.parseExpression("#map[1]");
assertThat(expression.getValue(context)).isEqualTo("ABC");
assertCanCompile(expression);
assertThat(expression.getValue(context)).isEqualTo("ABC");
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");

// LongLiteral
expression = parser.parseExpression("#map[2L]");
assertThat(expression.getValue(context)).isEqualTo("XYZ");
assertCanCompile(expression);
assertThat(expression.getValue(context)).isEqualTo("XYZ");
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");

// FloatLiteral
expression = parser.parseExpression("#map[9.99F]");
assertThat(expression.getValue(context)).isEqualTo("~10");
assertCanCompile(expression);
assertThat(expression.getValue(context)).isEqualTo("~10");
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");

// RealLiteral
expression = parser.parseExpression("#map[3.14159]");
assertThat(expression.getValue(context)).isEqualTo("PI");
assertCanCompile(expression);
assertThat(expression.getValue(context)).isEqualTo("PI");
assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object");
}

private String stringify(Object object) {
Stream<? extends Object> stream;
if (object instanceof Collection<?> collection) {
Expand Down

0 comments on commit aed1d5f

Please sign in to comment.