From a30836e112f4638ca0d563ba8930e69340cd4a86 Mon Sep 17 00:00:00 2001 From: junhyeong9812 Date: Wed, 24 Jun 2026 21:36:33 +0900 Subject: [PATCH] Generate compilable code for non-finite floating-point values PrimitiveDelegate generated code via "$LF" for Float and "(double) $L" for Double, which emit the value's toString() verbatim. For NaN and infinities this produced non-compilable source such as "NaNF" or "(double) Infinity", causing the generated AOT sources to fail to compile. Detect NaN (via isNaN, since NaN is never equal to itself) and the positive/negative infinities, emitting the corresponding constant field references (Float.NaN, Double.POSITIVE_INFINITY, etc.) through the "$T" placeholder. Finite values keep their existing handling. Signed-off-by: junhyeong9812 --- .../generate/ValueCodeGeneratorDelegates.java | 22 ++++++++++++-- .../aot/generate/ValueCodeGeneratorTests.java | 30 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/aot/generate/ValueCodeGeneratorDelegates.java b/spring-core/src/main/java/org/springframework/aot/generate/ValueCodeGeneratorDelegates.java index b402d623a280..ca1c47d40048 100644 --- a/spring-core/src/main/java/org/springframework/aot/generate/ValueCodeGeneratorDelegates.java +++ b/spring-core/src/main/java/org/springframework/aot/generate/ValueCodeGeneratorDelegates.java @@ -220,10 +220,28 @@ private static class PrimitiveDelegate implements Delegate { if (value instanceof Long) { return CodeBlock.of("$LL", value); } - if (value instanceof Float) { + if (value instanceof Float floatValue) { + if (Float.isNaN(floatValue)) { + return CodeBlock.of("$T.NaN", Float.class); + } + if (floatValue == Float.POSITIVE_INFINITY) { + return CodeBlock.of("$T.POSITIVE_INFINITY", Float.class); + } + if (floatValue == Float.NEGATIVE_INFINITY) { + return CodeBlock.of("$T.NEGATIVE_INFINITY", Float.class); + } return CodeBlock.of("$LF", value); } - if (value instanceof Double) { + if (value instanceof Double doubleValue) { + if (Double.isNaN(doubleValue)) { + return CodeBlock.of("$T.NaN", Double.class); + } + if (doubleValue == Double.POSITIVE_INFINITY) { + return CodeBlock.of("$T.POSITIVE_INFINITY", Double.class); + } + if (doubleValue == Double.NEGATIVE_INFINITY) { + return CodeBlock.of("$T.NEGATIVE_INFINITY", Double.class); + } return CodeBlock.of("(double) $L", value); } if (value instanceof Character character) { diff --git a/spring-core/src/test/java/org/springframework/aot/generate/ValueCodeGeneratorTests.java b/spring-core/src/test/java/org/springframework/aot/generate/ValueCodeGeneratorTests.java index d6d7dc66d492..4e8d113602b4 100644 --- a/spring-core/src/test/java/org/springframework/aot/generate/ValueCodeGeneratorTests.java +++ b/spring-core/src/test/java/org/springframework/aot/generate/ValueCodeGeneratorTests.java @@ -157,6 +157,36 @@ void generateWhenDouble() { assertThat(generateCode(0.2)).hasToString("(double) 0.2"); } + @Test + void generateWhenFloatNaN() { + assertThat(generateCode(Float.NaN)).hasToString("java.lang.Float.NaN"); + } + + @Test + void generateWhenFloatPositiveInfinity() { + assertThat(generateCode(Float.POSITIVE_INFINITY)).hasToString("java.lang.Float.POSITIVE_INFINITY"); + } + + @Test + void generateWhenFloatNegativeInfinity() { + assertThat(generateCode(Float.NEGATIVE_INFINITY)).hasToString("java.lang.Float.NEGATIVE_INFINITY"); + } + + @Test + void generateWhenDoubleNaN() { + assertThat(generateCode(Double.NaN)).hasToString("java.lang.Double.NaN"); + } + + @Test + void generateWhenDoublePositiveInfinity() { + assertThat(generateCode(Double.POSITIVE_INFINITY)).hasToString("java.lang.Double.POSITIVE_INFINITY"); + } + + @Test + void generateWhenDoubleNegativeInfinity() { + assertThat(generateCode(Double.NEGATIVE_INFINITY)).hasToString("java.lang.Double.NEGATIVE_INFINITY"); + } + @Test void generateWhenChar() { assertThat(generateCode('a')).hasToString("'a'");