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 aed1d5f762)
			
			
This commit is contained in:
		
							parent
							
								
									0f04052ba1
								
							
						
					
					
						commit
						2384474615
					
				|  | @ -285,9 +285,7 @@ public class Indexer extends SpelNodeImpl { | ||||||
| 				mv.visitLdcInsn(mapKeyName); | 				mv.visitLdcInsn(mapKeyName); | ||||||
| 			} | 			} | ||||||
| 			else { | 			else { | ||||||
| 				cf.enterCompilationScope(); | 				generateIndexCode(mv, cf, index, Object.class); | ||||||
| 				index.generateCode(mv, cf); |  | ||||||
| 				cf.exitCompilationScope(); |  | ||||||
| 			} | 			} | ||||||
| 			mv.visitMethodInsn( | 			mv.visitMethodInsn( | ||||||
| 					INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true); | 					INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true); | ||||||
|  |  | ||||||
|  | @ -552,6 +552,52 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { | ||||||
| 			assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object"); | 			assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		@Test  // gh-32903 | ||||||
|  | 		void indexIntoMapUsingPrimitiveLiteral() { | ||||||
|  | 			Map<Object, String> map = new HashMap<>(); | ||||||
|  | 			map.put(false, "0");    // BooleanLiteral | ||||||
|  | 			map.put(1, "ABC");      // IntLiteral | ||||||
|  | 			map.put(2L, "XYZ");     // LongLiteral | ||||||
|  | 			map.put(9.99F, "~10");  // FloatLiteral | ||||||
|  | 			map.put(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) { | 		private String stringify(Object object) { | ||||||
| 			Stream<? extends Object> stream; | 			Stream<? extends Object> stream; | ||||||
| 			if (object instanceof Collection) { | 			if (object instanceof Collection) { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue