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

Comment From: sbrannen

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

Comment From: sbrannen

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

Comment From: sbrannen

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.