21
21
import java .lang .reflect .InvocationHandler ;
22
22
import java .lang .reflect .Method ;
23
23
import java .util .Iterator ;
24
- import java .util .List ;
25
24
import java .util .Map ;
26
25
27
26
import org .springframework .util .ObjectUtils ;
28
27
import org .springframework .util .ReflectionUtils ;
29
28
import org .springframework .util .StringUtils ;
30
29
30
+ import static org .springframework .core .annotation .AnnotationUtils .*;
31
+
31
32
/**
32
33
* {@link InvocationHandler} for an {@link Annotation} that Spring has
33
34
* <em>synthesized</em> (i.e., wrapped in a dynamic proxy) with additional
@@ -56,7 +57,7 @@ class SynthesizedAnnotationInvocationHandler implements InvocationHandler {
56
57
private final Map <String , String > aliasMap ;
57
58
58
59
59
- public SynthesizedAnnotationInvocationHandler (AnnotatedElement annotatedElement , Annotation annotation ,
60
+ SynthesizedAnnotationInvocationHandler (AnnotatedElement annotatedElement , Annotation annotation ,
60
61
Map <String , String > aliasMap ) {
61
62
this .annotatedElement = annotatedElement ;
62
63
this .annotation = annotation ;
@@ -70,7 +71,10 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
70
71
Class <?>[] parameterTypes = method .getParameterTypes ();
71
72
int parameterCount = parameterTypes .length ;
72
73
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 )) {
74
78
return toString (proxy );
75
79
}
76
80
@@ -82,7 +86,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
82
86
ReflectionUtils .makeAccessible (method );
83
87
Object value = ReflectionUtils .invokeMethod (method , this .annotation , args );
84
88
85
- // Nothing special to do ?
89
+ // No custom processing necessary ?
86
90
if (!aliasPresent && !nestedAnnotation ) {
87
91
return value ;
88
92
}
@@ -101,11 +105,12 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
101
105
102
106
ReflectionUtils .makeAccessible (aliasedMethod );
103
107
Object aliasedValue = ReflectionUtils .invokeMethod (aliasedMethod , this .annotation , args );
104
- Object defaultValue = AnnotationUtils . getDefaultValue (this .annotation , methodName );
108
+ Object defaultValue = getDefaultValue (this .annotation , methodName );
105
109
106
110
if (!ObjectUtils .nullSafeEquals (value , aliasedValue ) && !ObjectUtils .nullSafeEquals (value , defaultValue )
107
111
&& !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 ());
109
114
String msg = String .format (
110
115
"In annotation [%s] declared on [%s], attribute [%s] and its alias [%s] are "
111
116
+ "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
123
128
124
129
// Synthesize nested annotations before returning them.
125
130
if (value instanceof Annotation ) {
126
- value = AnnotationUtils . synthesizeAnnotation ((Annotation ) value , this .annotatedElement );
131
+ value = synthesizeAnnotation ((Annotation ) value , this .annotatedElement );
127
132
}
128
133
else if (value instanceof Annotation []) {
129
134
Annotation [] annotations = (Annotation []) value ;
130
135
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 );
132
137
}
133
138
}
134
139
135
140
return value ;
136
141
}
137
142
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
+
138
162
private String toString (Object proxy ) {
139
163
StringBuilder sb = new StringBuilder ("@" ).append (annotationType .getName ()).append ("(" );
140
164
141
- List <Method > attributeMethods = AnnotationUtils .getAttributeMethods (this .annotationType );
142
- Iterator <Method > iterator = attributeMethods .iterator ();
165
+ Iterator <Method > iterator = getAttributeMethods (this .annotationType ).iterator ();
143
166
while (iterator .hasNext ()) {
144
167
Method attributeMethod = iterator .next ();
145
168
sb .append (attributeMethod .getName ());
0 commit comments