From 4a803961bc5f80cb4f7126091f298e1e76b33020 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 b402d623a28..ca1c47d4004 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 @@ public abstract class ValueCodeGeneratorDelegates { 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 d6d7dc66d49..4e8d113602b 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 @@ class ValueCodeGeneratorTests { 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'");