2121import java .lang .reflect .InvocationHandler ;
2222import java .lang .reflect .Method ;
2323import java .util .Iterator ;
24- import java .util .List ;
2524import java .util .Map ;
2625
2726import org .springframework .util .ObjectUtils ;
2827import org .springframework .util .ReflectionUtils ;
2928import org .springframework .util .StringUtils ;
3029
30+ import static org .springframework .core .annotation .AnnotationUtils .*;
31+
3132/**
3233 * {@link InvocationHandler} for an {@link Annotation} that Spring has
3334 * <em>synthesized</em> (i.e., wrapped in a dynamic proxy) with additional
@@ -56,7 +57,7 @@ class SynthesizedAnnotationInvocationHandler implements InvocationHandler {
5657 private final Map <String , String > aliasMap ;
5758
5859
59- public SynthesizedAnnotationInvocationHandler (AnnotatedElement annotatedElement , Annotation annotation ,
60+ SynthesizedAnnotationInvocationHandler (AnnotatedElement annotatedElement , Annotation annotation ,
6061 Map <String , String > aliasMap ) {
6162 this .annotatedElement = annotatedElement ;
6263 this .annotation = annotation ;
@@ -70,7 +71,10 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
7071 Class <?>[] parameterTypes = method .getParameterTypes ();
7172 int parameterCount = parameterTypes .length ;
7273
73- if ("toString" .equals (methodName ) && (parameterCount == 0 )) {
74+ if ("equals" .equals (methodName ) && (parameterCount == 1 ) && (parameterTypes [0 ] == Object .class )) {
75+ return equals (proxy , args [0 ]);
76+ }
77+ else if ("toString" .equals (methodName ) && (parameterCount == 0 )) {
7478 return toString (proxy );
7579 }
7680
@@ -82,7 +86,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
8286 ReflectionUtils .makeAccessible (method );
8387 Object value = ReflectionUtils .invokeMethod (method , this .annotation , args );
8488
85- // Nothing special to do ?
89+ // No custom processing necessary ?
8690 if (!aliasPresent && !nestedAnnotation ) {
8791 return value ;
8892 }
@@ -101,11 +105,12 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
101105
102106 ReflectionUtils .makeAccessible (aliasedMethod );
103107 Object aliasedValue = ReflectionUtils .invokeMethod (aliasedMethod , this .annotation , args );
104- Object defaultValue = AnnotationUtils . getDefaultValue (this .annotation , methodName );
108+ Object defaultValue = getDefaultValue (this .annotation , methodName );
105109
106110 if (!ObjectUtils .nullSafeEquals (value , aliasedValue ) && !ObjectUtils .nullSafeEquals (value , defaultValue )
107111 && !ObjectUtils .nullSafeEquals (aliasedValue , defaultValue )) {
108- String elementName = (this .annotatedElement == null ? "unknown element" : this .annotatedElement .toString ());
112+ String elementName = (this .annotatedElement == null ? "unknown element"
113+ : this .annotatedElement .toString ());
109114 String msg = String .format (
110115 "In annotation [%s] declared on [%s], attribute [%s] and its alias [%s] are "
111116 + "declared with values of [%s] and [%s], but only one declaration is permitted." ,
@@ -123,23 +128,41 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
123128
124129 // Synthesize nested annotations before returning them.
125130 if (value instanceof Annotation ) {
126- value = AnnotationUtils . synthesizeAnnotation ((Annotation ) value , this .annotatedElement );
131+ value = synthesizeAnnotation ((Annotation ) value , this .annotatedElement );
127132 }
128133 else if (value instanceof Annotation []) {
129134 Annotation [] annotations = (Annotation []) value ;
130135 for (int i = 0 ; i < annotations .length ; i ++) {
131- annotations [i ] = AnnotationUtils . synthesizeAnnotation (annotations [i ], this .annotatedElement );
136+ annotations [i ] = synthesizeAnnotation (annotations [i ], this .annotatedElement );
132137 }
133138 }
134139
135140 return value ;
136141 }
137142
143+ private boolean equals (Object proxy , Object other ) {
144+ if (this == other ) {
145+ return true ;
146+ }
147+ if (!this .annotationType .isInstance (other )) {
148+ return false ;
149+ }
150+
151+ for (Method attributeMethod : getAttributeMethods (this .annotationType )) {
152+ Object thisValue = ReflectionUtils .invokeMethod (attributeMethod , proxy );
153+ Object otherValue = ReflectionUtils .invokeMethod (attributeMethod , other );
154+ if (!ObjectUtils .nullSafeEquals (thisValue , otherValue )) {
155+ return false ;
156+ }
157+ }
158+
159+ return true ;
160+ }
161+
138162 private String toString (Object proxy ) {
139163 StringBuilder sb = new StringBuilder ("@" ).append (annotationType .getName ()).append ("(" );
140164
141- List <Method > attributeMethods = AnnotationUtils .getAttributeMethods (this .annotationType );
142- Iterator <Method > iterator = attributeMethods .iterator ();
165+ Iterator <Method > iterator = getAttributeMethods (this .annotationType ).iterator ();
143166 while (iterator .hasNext ()) {
144167 Method attributeMethod = iterator .next ();
145168 sb .append (attributeMethod .getName ());
0 commit comments