diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java index 56dfe050b796..28c854db5df7 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java @@ -222,12 +222,15 @@ protected void generateComparisonCode(MethodVisitor mv, CodeFlow cf, int compIns } // assert: SpelCompiler.boxingCompatible(leftDesc, rightDesc) + // For OpGT and OpGE, use DCMPL/FCMPL (NaN yields -1) like javac, so that + // a comparison with NaN is false; DCMPG/FCMPG (NaN yields 1) otherwise. + boolean greaterThan = (compInstruction1 == IFLE || compInstruction1 == IFLT); if (targetType == 'D') { - mv.visitInsn(DCMPG); + mv.visitInsn(greaterThan ? DCMPL : DCMPG); mv.visitJumpInsn(compInstruction1, elseTarget); } else if (targetType == 'F') { - mv.visitInsn(FCMPG); + mv.visitInsn(greaterThan ? FCMPL : FCMPG); mv.visitJumpInsn(compInstruction1, elseTarget); } else if (targetType == 'J') { 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..7a59238dc6a0 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 @@ -962,6 +962,20 @@ void opGe() { assertThat((Boolean) expression.getValue()).isTrue(); } + @ParameterizedTest + @ValueSource(strings = { + "T(Double).NaN > 1.0d", "1.0d > T(Double).NaN", "T(Double).NaN >= 1.0d", "1.0d >= T(Double).NaN", + "T(Double).NaN < 1.0d", "1.0d < T(Double).NaN", "T(Double).NaN <= 1.0d", "1.0d <= T(Double).NaN", + "T(Float).NaN > 1.0f", "1.0f > T(Float).NaN", "T(Float).NaN >= 1.0f", "1.0f >= T(Float).NaN", + "T(Float).NaN < 1.0f", "1.0f < T(Float).NaN", "T(Float).NaN <= 1.0f", "1.0f <= T(Float).NaN" + }) + void relationalOperatorsWithNaN(String expressionString) { + expression = parse(expressionString); + assertThat((Boolean) expression.getValue()).isFalse(); + assertCanCompile(expression); + assertThat((Boolean) expression.getValue()).isFalse(); + } + @Test void opEq() { String tvar = "35";