Align synthesized annotation toString() with JDK for NaN/Infinity

Closes gh-37244
This commit is contained in:
Sam Brannen
2026-09-05 13:37:06 +02:00
parent c1d241928c
commit 35d8c4d06f
2 changed files with 47 additions and 5 deletions
@@ -160,14 +160,12 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
}
/**
* This method currently does not address the following issues which we may
* This method currently does not address the following issue which we may
* choose to address at a later point in time.
*
* <ul>
* <li>non-ASCII, non-visible, and non-printable characters within a character
* or String literal are not escaped.</li>
* <li>formatting for float and double values does not take into account whether
* a value is not a number (NaN) or infinite.</li>
* </ul>
* @param value the attribute value to format
* @return the formatted string representation
@@ -199,10 +197,30 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
return Long.toString((Long) value) + 'L';
}
if (type == Float.class) {
return Float.toString((Float) value) + 'f';
float floatValue = (Float) value;
if (Float.isNaN(floatValue)) {
return "0.0f/0.0f";
}
if (floatValue == Float.POSITIVE_INFINITY) {
return "1.0f/0.0f";
}
if (floatValue == Float.NEGATIVE_INFINITY) {
return "-1.0f/0.0f";
}
return Float.toString(floatValue) + 'f';
}
if (type == Double.class) {
return Double.toString((Double) value);
double doubleValue = (Double) value;
if (Double.isNaN(doubleValue)) {
return "0.0/0.0";
}
if (doubleValue == Double.POSITIVE_INFINITY) {
return "1.0/0.0";
}
if (doubleValue == Double.NEGATIVE_INFINITY) {
return "-1.0/0.0";
}
return Double.toString(doubleValue);
}
if (value instanceof Enum<?> e) {
return e.name();
@@ -2060,6 +2060,30 @@ class MergedAnnotationsTests {
.isEqualTo("@%s({\"FromValueAttributeMeta\"})", ValueAttribute.class.getCanonicalName());
}
@Test // gh-37244
void toStringForSynthesizedAnnotationsWithNonFiniteFloatingPointValues() {
Map<String, Object> attributes = Map.of(
"name", "test",
"floatValue", Float.NaN,
"doubleValue", Double.NaN);
RequestMapping mapping = MergedAnnotation.of(RequestMapping.class, attributes).synthesize();
assertThat(mapping).asString().contains("floatValue=0.0f/0.0f", "doubleValue=0.0/0.0");
attributes = Map.of(
"name", "test",
"floatValue", Float.POSITIVE_INFINITY,
"doubleValue", Double.POSITIVE_INFINITY);
mapping = MergedAnnotation.of(RequestMapping.class, attributes).synthesize();
assertThat(mapping).asString().contains("floatValue=1.0f/0.0f", "doubleValue=1.0/0.0");
attributes = Map.of(
"name", "test",
"floatValue", Float.NEGATIVE_INFINITY,
"doubleValue", Double.NEGATIVE_INFINITY);
mapping = MergedAnnotation.of(RequestMapping.class, attributes).synthesize();
assertThat(mapping).asString().contains("floatValue=-1.0f/0.0f", "doubleValue=-1.0/0.0");
}
@Test
void equalsForSynthesizedAnnotations() throws Exception {
Method methodWithPath = WebController.class.getMethod("handleMappedWithPathAttribute");