Merge branch '7.0.x'

This commit is contained in:
Sam Brannen
2026-09-05 13:42:41 +02:00
3 changed files with 71 additions and 29 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();
@@ -2087,6 +2087,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");
@@ -79,7 +79,17 @@ class ExponentialBackOffTests {
}
@Test
void maxAttemptsReached() {
void maxIntervalReachedImmediately() {
ExponentialBackOff backOff = new ExponentialBackOff(1000L, 2.0);
backOff.setMaxInterval(50L);
BackOffExecution execution = backOff.start();
assertThat(execution.nextBackOff()).isEqualTo(50L);
assertThat(execution.nextBackOff()).isEqualTo(50L);
}
@Test
void maxElapsedTimeReached() {
ExponentialBackOff backOff = new ExponentialBackOff(2000L, 2.0);
backOff.setMaxElapsedTime(4000L);
@@ -90,6 +100,19 @@ class ExponentialBackOffTests {
assertThat(execution.nextBackOff()).isEqualTo(BackOffExecution.STOP);
}
@Test
void maxAttempts() {
ExponentialBackOff backOff = new ExponentialBackOff();
backOff.setInitialInterval(1000L);
backOff.setMultiplier(2.0);
backOff.setMaxInterval(10000L);
backOff.setMaxAttempts(6);
List<Long> delays = new ArrayList<>();
BackOffExecution execution = backOff.start();
IntStream.range(0, 7).forEach(i -> delays.add(execution.nextBackOff()));
assertThat(delays).containsExactly(1000L, 2000L, 4000L, 8000L, 10000L, 10000L, BackOffExecution.STOP);
}
@Test
void startReturnsDifferentInstances() {
ExponentialBackOff backOff = new ExponentialBackOff();
@@ -143,16 +166,6 @@ class ExponentialBackOffTests {
assertThat(execution.nextBackOff()).isBetween(4275L, 4724L);
}
@Test
void maxIntervalReachedImmediately() {
ExponentialBackOff backOff = new ExponentialBackOff(1000L, 2.0);
backOff.setMaxInterval(50L);
BackOffExecution execution = backOff.start();
assertThat(execution.nextBackOff()).isEqualTo(50L);
assertThat(execution.nextBackOff()).isEqualTo(50L);
}
@Test
void toStringContent() {
ExponentialBackOff backOff = new ExponentialBackOff(2000L, 2.0);
@@ -174,17 +187,4 @@ class ExponentialBackOffTests {
assertThat(execution).asString().isEqualTo("ExponentialBackOffExecution[currentInterval=4000ms, multiplier=2.0, attempts=2]");
}
@Test
void maxAttempts() {
ExponentialBackOff backOff = new ExponentialBackOff();
backOff.setInitialInterval(1000L);
backOff.setMultiplier(2.0);
backOff.setMaxInterval(10000L);
backOff.setMaxAttempts(6);
List<Long> delays = new ArrayList<>();
BackOffExecution execution = backOff.start();
IntStream.range(0, 7).forEach(i -> delays.add(execution.nextBackOff()));
assertThat(delays).containsExactly(1000L, 2000L, 4000L, 8000L, 10000L, 10000L, BackOffExecution.STOP);
}
}