Synthesized annotations that contain arrays and/or strings do not generate the same toString() value as the non-synthesized version.

The non-synthesized annotation's toString() method returns a string which is a code equivalent version of that annotation meaning that you can take the result of the toString(), copy and paste it into code, and have it compile. This is very convenient when writing a code generation library since it allows you to copy annotations.

This does not work with synthesized annotations though as the way the array gets serialized in toString() doesn't match.

Actual Annotation:

@Bean("testValue")

Non-Synthesized Annotation toString():

@org.springframework.context.annotation.Bean(value = {"testValue"})

Synthesized Annotation toString():

@org.springframework.context.annotation.Bean(value = [testValue])

https://github.com/spring-projects/spring-framework/blob/a0c97e4c36e5e07bc13bab4409ec740332a57871/spring-core/src/main/java/org/springframework/core/annotation/SynthesizedMergedAnnotationInvocationHandler.java#L202

Comment From: sbrannen

This is actually by design.

The result of invoking toString() on a synthesized annotation is identical to the result of invoking toString() on the same non-synthesized annotation on Java 8. In fact we used to have tests in place to verify that, but those broke once we started building the framework on Java 9, since Java 9 changed the output format for toString() in annotations.

See:

  • 19211

  • commit faf6e5d8fa05d25504a2f8dcd1ced4931aa82f11

In any case, it does not appear that the JDK format has changed since Java 9, so I'll go ahead and update to the newer format.

Comment From: jhoeller

Ah ok, I wasn't aware of the change between JDK 8 and 9 there. If 5.3.x is currently aligned with the JDK 8 toString format there, we could also simply upgrade to the JDK 9+ format for 6.0.

Comment From: sbrannen

Interestingly enough, it turns out there are actually 2 bugs (🐛) lurking behind the scenes here.

  1. Spring's toString() for synthesized annotations in fact did not match the JDK 8 behavior for class attributes. Spring used Class#getName; JDK 8 used Class#toString.
  2. JDK 9+ incorrectly invokes Enum#toString for enum attributes; whereas, the commit I am about to push will use Enum#name, since an enum can in fact override toString() (for example, with return name().toLowerCase()).

I'll see if the OpenJDK team is willing to update the toString() implementation for annotations to use Enum#name.

Comment From: sbrannen

I'll see if the OpenJDK team is willing to update the toString() implementation for annotations to use Enum#name.

See: https://bugs.openjdk.java.net/browse/JDK-8281462

Comment From: sbrannen

Reopening to address additional shortcomings in the toString() implementation for synthesized annotations.