Improve toString() for synthesized annotations
Although the initial report in gh-28015 only covered inconsistencies for arrays and strings in the toString() implementations for annotations between the JDK (after Java 9) and Spring, it has since come to our attention that there was further room for improvement. This commit therefore addresses the following in toString() output for synthesized annotations. - characters are now wrapped in single quotes. - bytes are now properly formatted as "(byte) 0x##". - long, float, and double values are now appended with "L", "f", and "d", respectively. The use of lowercase for "f" and "d" is solely to align with the choice made by the JDK team. However, this commit does not address the following issues which we may choose to address at a later point in time. - non-ASCII, non-visible, and non-printable characters within a character or String literal are not escaped. - formatting for float and double values does not take into account whether a value is not a number (NaN) or infinite. Closes gh-28015
This commit is contained in:
parent
ce87285be5
commit
2fd39839f8
|
@ -194,10 +194,38 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
|
|||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method currently does not address the following issues 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
|
||||
*/
|
||||
private String toString(Object value) {
|
||||
if (value instanceof String) {
|
||||
return '"' + value.toString() + '"';
|
||||
}
|
||||
if (value instanceof Character) {
|
||||
return '\'' + value.toString() + '\'';
|
||||
}
|
||||
if (value instanceof Byte) {
|
||||
return String.format("(byte) 0x%02X", value);
|
||||
}
|
||||
if (value instanceof Long) {
|
||||
return Long.toString(((Long) value)) + 'L';
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
return Float.toString(((Float) value)) + 'f';
|
||||
}
|
||||
if (value instanceof Double) {
|
||||
return Double.toString(((Double) value)) + 'd';
|
||||
}
|
||||
if (value instanceof Enum) {
|
||||
return ((Enum<?>) value).name();
|
||||
}
|
||||
|
|
|
@ -1887,7 +1887,7 @@ class MergedAnnotationsTests {
|
|||
|
||||
// Formatting common to Spring and JDK 9+
|
||||
assertThat(string)
|
||||
.contains("value={\"/test\"}", "path={\"/test\"}", "name=\"bar\"")
|
||||
.contains("value={\"/test\"}", "path={\"/test\"}", "name=\"bar\"", "ch='X'", "chars={'X'}")
|
||||
.endsWith(")");
|
||||
|
||||
if (webMapping instanceof SynthesizedAnnotation) {
|
||||
|
@ -1895,14 +1895,36 @@ class MergedAnnotationsTests {
|
|||
.startsWith("@org.springframework.core.annotation.MergedAnnotationsTests.RequestMapping(")
|
||||
.contains("method={GET, POST}",
|
||||
"clazz=org.springframework.core.annotation.MergedAnnotationsTests.RequestMethod.class",
|
||||
"classes={org.springframework.core.annotation.MergedAnnotationsTests.RequestMethod.class}");
|
||||
"classes={int[][].class, org.springframework.core.annotation.MergedAnnotationsTests.RequestMethod[].class}",
|
||||
"byteValue=(byte) 0xFF", "bytes={(byte) 0xFF}",
|
||||
"shortValue=9876", "shorts={9876}",
|
||||
"longValue=42L", "longs={42L}",
|
||||
"floatValue=3.14f", "floats={3.14f}",
|
||||
"doubleValue=99.999d", "doubles={99.999d}"
|
||||
);
|
||||
}
|
||||
else {
|
||||
assertThat(string).as("JDK 9-18 formatting")
|
||||
.startsWith("@org.springframework.core.annotation.MergedAnnotationsTests$RequestMapping(")
|
||||
.contains("method={method: get, method: post}",
|
||||
"clazz=org.springframework.core.annotation.MergedAnnotationsTests$RequestMethod.class",
|
||||
"classes={org.springframework.core.annotation.MergedAnnotationsTests$RequestMethod.class}");
|
||||
"classes={int[][].class, org.springframework.core.annotation.MergedAnnotationsTests$RequestMethod[].class}",
|
||||
"shortValue=9876", "shorts={9876}",
|
||||
"floatValue=3.14f", "floats={3.14f}",
|
||||
"doubleValue=99.999", "doubles={99.999}"
|
||||
);
|
||||
if (JRE.currentVersion().ordinal() < JRE.JAVA_14.ordinal()) {
|
||||
assertThat(string).as("JDK 9-13 formatting")
|
||||
.contains("longValue=42", "longs={42}",
|
||||
"byteValue=-1", "bytes={-1}"
|
||||
);
|
||||
}
|
||||
else {
|
||||
assertThat(string).as("JDK 14+ formatting")
|
||||
.contains("longValue=42L", "longs={42L}",
|
||||
"byteValue=(byte)0xff", "bytes={(byte)0xff}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2996,9 +3018,29 @@ class MergedAnnotationsTests {
|
|||
|
||||
RequestMethod[] method() default {};
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// All remaining attributes declare default values that are used solely
|
||||
// for the purpose of testing the toString() implementations for annotations.
|
||||
Class<?> clazz() default RequestMethod.class;
|
||||
Class<?>[] classes() default {int[][].class, RequestMethod[].class};
|
||||
|
||||
Class<?>[] classes() default {RequestMethod.class};
|
||||
char ch() default 'X';
|
||||
char[] chars() default {'X'};
|
||||
|
||||
byte byteValue() default (byte) 0xFF;
|
||||
byte[] bytes() default {(byte) 0xFF};
|
||||
|
||||
short shortValue() default 9876;
|
||||
short[] shorts() default {9876};
|
||||
|
||||
long longValue() default 42L;
|
||||
long[] longs() default {42L};
|
||||
|
||||
float floatValue() default 3.14F;
|
||||
float[] floats() default {3.14F};
|
||||
|
||||
double doubleValue() default 99.999D;
|
||||
double[] doubles() default {99.999D};
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
|
Loading…
Reference in New Issue