Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SpEL compilation fails when indexing into a Map with a primitive #32903

Closed
rmonje opened this issue May 27, 2024 · 3 comments
Closed

SpEL compilation fails when indexing into a Map with a primitive #32903

rmonje opened this issue May 27, 2024 · 3 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Milestone

Comments

@rmonje
Copy link

rmonje commented May 27, 2024

Overview

We have found inconsistent behavior when using a Map in a SpEL expression.

Example: mapWithArrays[1] != null && mapWithArrays[1][1] != null

It works the first 100 times it is executed. Then compilation is launched, which throws an exception.

Workaround: use mapWithArrays[new Integer(1)] != null && mapWithArrays[new Integer(1)][1] != null or mapWithArrays.get(1) != null && mapWithArrays.get(1)[1] != null.

Reproducer

CompilerTests_.zip

Stacktrace

org.springframework.expression.spel.SpelEvaluationException: EL1074E: An exception occurred while compiling an expression

	at org.springframework.expression.spel.standard.SpelExpression.compileExpression(SpelExpression.java:552)
	at org.springframework.expression.spel.standard.SpelExpression.checkCompile(SpelExpression.java:492)
	at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:310)
	at com.baeldung.thymeleaf.CompilerTests.test(CompilerTests.java:25)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: java.lang.IllegalStateException: Failed to instantiate CompiledExpression for expression: ((mapWithArrays.[1] != null) and (mapWithArrays.[1].[1] != null))
	at org.springframework.expression.spel.standard.SpelCompiler.compile(SpelCompiler.java:114)
	at org.springframework.expression.spel.standard.SpelExpression.compileExpression(SpelExpression.java:528)
	... 30 more
Caused by: java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    spel/Ex2.getValue(Ljava/lang/Object;Lorg/springframework/expression/EvaluationContext;)Ljava/lang/Object; @12: invokeinterface
  Reason:
    Type integer (current frame, stack[2]) is not assignable to 'java/lang/Object'
  Current Frame:
    bci: @12
    flags: { }
    locals: { 'spel/Ex2', 'java/lang/Object', 'org/springframework/expression/EvaluationContext' }
    stack: { 'org/springframework/expression/EvaluationContext', 'java/util/Map', integer }
  Bytecode:
    0000000: 2c2b c000 0eb4 0012 c000 1404 b900 1802
    0000010: 0001 b800 1e9a 0007 04a7 0004 039a 0008
    0000020: 121f a700 252c 2bc0 000e b400 12c0 0014
    0000030: 04b9 0018 0200 c000 2104 3201 b800 1e9a
    0000040: 0007 04a7 0004 03b8 0027 b0            
  Stackmap Table:
    same_frame(@28)
    same_locals_1_stack_item_frame(@29,Integer)
    same_frame(@37)
    same_frame(@70)
    same_locals_1_stack_item_frame(@71,Integer)

	at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
	at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3373)
	at java.base/java.lang.Class.getConstructor0(Class.java:3578)
	at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2754)
	at org.springframework.util.ReflectionUtils.accessibleConstructor(ReflectionUtils.java:185)
	at org.springframework.expression.spel.standard.SpelCompiler.compile(SpelCompiler.java:110)
	... 31 more
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label May 27, 2024
@sbrannen
Copy link
Member

I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.

@sbrannen sbrannen added the in: core Issues in core modules (aop, beans, core, context, expression) label May 27, 2024
@sbrannen sbrannen changed the title VerifyErrors when using SpEL compilation with Thymeleaf when using int to access map instead of Integer SpEL compilation failure when using int to access map instead of Integer May 27, 2024
@sbrannen sbrannen self-assigned this May 27, 2024
@sbrannen
Copy link
Member

Hi @rmonje,

Congratulations on submitting your first issue for the Spring Framework! 👍

I have confirmed that your example fails to compile against main, and we'll look into it.

Cheers,

Sam

@sbrannen sbrannen added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels May 27, 2024
@sbrannen sbrannen changed the title SpEL compilation failure when using int to access map instead of Integer SpEL compilation fails when using int to access a Map May 27, 2024
@sbrannen sbrannen added this to the 6.1.9 milestone May 27, 2024
@sbrannen sbrannen changed the title SpEL compilation fails when using int to access a Map SpEL compilation fails when indexing into a Map with a primitive May 27, 2024
@sbrannen sbrannen modified the milestones: 6.1.9, 6.0.22 May 27, 2024
@github-actions github-actions bot added status: backported An issue that has been backported to maintenance branches and removed for: backport-to-6.0.x labels May 27, 2024
sbrannen added a commit that referenced this issue May 28, 2024
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)
sbrannen added a commit that referenced this issue May 28, 2024
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 aed1d5f)
@sbrannen
Copy link
Member

This has been fixed in 6.1.x and ported to main, 6.0.x, and 5.3.x.

Feel free to try out the fix in the snapshot builds for 5.3.37, 6.0.22, 6.1.9, and 6.2.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants