From 28f78f435e768e7ce7d974f82ba7ced700c5848b Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Sun, 12 Apr 2026 17:11:07 +0200 Subject: [PATCH] Introduce missing tests for immediate SpEL compilation for Elvis operator --- .../expression/spel/ast/Elvis.java | 6 +++++- .../spel/SpelCompilationCoverageTests.java | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java index f4933a70f3b..4098850c265 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java @@ -98,7 +98,11 @@ public class Elvis extends SpelNodeImpl { @Override public void generateCode(MethodVisitor mv, CodeFlow cf) { - // exit type descriptor can be null if both components are literal expressions + // If both elements are literals and the expression was not previously + // evaluated in interpreted mode -- or if getValueInternal() did not + // properly invoke computeExitTypeDescriptor() -- we may get here without + // the exit descriptor having been computed, so we must ensure the exit + // descriptor has been computed before proceeding. computeExitTypeDescriptor(); cf.enterCompilationScope(); diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java index 1d0727ec44d..0ecf23aca17 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java @@ -1470,6 +1470,23 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String"); } + @Test + void elvisWithImmediateCompilation() { + expression = parser.parseExpression("'a' ?: 'b'"); + // Both literals, so we can compile immediately without having previously + // evaluated the expression. + assertCanCompile(expression); + assertThat(expression.getValue(String.class)).isEqualTo("a"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String"); + + expression = parser.parseExpression("null ?: 'a'"); + // Both literals, so we can compile immediately without having previously + // evaluated the expression. + assertCanCompile(expression); + assertThat(expression.getValue(String.class)).isEqualTo("a"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object"); + } + @Test // gh-19758 void elvisMiscellaneous() { SpelParserConfiguration configuration = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null);