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 b2f65812d3df..d63dd5972662 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 @@ -128,12 +128,19 @@ public void generateCode(MethodVisitor mv, CodeFlow cf) { this.children[0].generateCode(mv, cf); String lastDesc = cf.lastDescriptor(); Assert.state(lastDesc != null, "No last descriptor"); + if (CodeFlow.isPrimitive(lastDesc) && !"V".equals(lastDesc)) { + // A primitive value is neither null nor an empty String, so the value + // of the expression is always the value of the left-hand operand. + if (!CodeFlow.isPrimitive(this.exitTypeDescriptor)) { + CodeFlow.insertBoxIfNecessary(mv, lastDesc.charAt(0)); + } + cf.exitCompilationScope(); + cf.pushDescriptor(this.exitTypeDescriptor); + return; + } if ("Ljava/util/Optional".equals(lastDesc)) { CodeFlow.insertOptionalUnwrapIfNecessary(mv, lastDesc); } - else { - CodeFlow.insertBoxIfNecessary(mv, lastDesc.charAt(0)); - } cf.exitCompilationScope(); mv.visitInsn(DUP); 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 2f41db9c0b94..1873c7661a49 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 @@ -6758,6 +6758,41 @@ void elvisMiscellaneous() { assertIsCompiled(exp); } + @Test + void elvisWithPrimitiveOperandsOfSameType() { + expression = parser.parseExpression("3 ?: 4"); + assertThat(expression.getValue()).isEqualTo(3); + assertCanCompile(expression); + assertThat(expression.getValue()).isEqualTo(3); + assertThat(getAst().getExitDescriptor()).isEqualTo("I"); + + // double slot primitive + expression = parser.parseExpression("3L ?: 4L"); + assertThat(expression.getValue()).isEqualTo(3L); + assertCanCompile(expression); + assertThat(expression.getValue()).isEqualTo(3L); + assertThat(getAst().getExitDescriptor()).isEqualTo("J"); + + expression = parser.parseExpression("3.5d ?: 4.5d"); + assertThat(expression.getValue()).isEqualTo(3.5d); + assertCanCompile(expression); + assertThat(expression.getValue()).isEqualTo(3.5d); + assertThat(getAst().getExitDescriptor()).isEqualTo("D"); + + expression = parser.parseExpression("true ?: false"); + assertThat(expression.getValue()).isEqualTo(true); + assertCanCompile(expression); + assertThat(expression.getValue()).isEqualTo(true); + assertThat(getAst().getExitDescriptor()).isEqualTo("Z"); + + // method returning primitive + expression = parser.parseExpression("length() ?: 0"); + assertThat(expression.getValue("abc")).isEqualTo(3); + assertCanCompile(expression); + assertThat(expression.getValue("abc")).isEqualTo(3); + assertThat(getAst().getExitDescriptor()).isEqualTo("I"); + } + @Test void elvis_SPR17214() { SpelParserConfiguration spc = SpelParserConfiguration.builder().compilerMode(SpelCompilerMode.IMMEDIATE).build();