20
20
import java .lang .reflect .AnnotatedElement ;
21
21
import java .lang .reflect .InvocationHandler ;
22
22
import java .lang .reflect .Method ;
23
+ import java .util .Arrays ;
23
24
import java .util .Iterator ;
24
25
import java .util .Map ;
25
26
@@ -70,6 +71,9 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
70
71
if (isEqualsMethod (method )) {
71
72
return equals (proxy , args [0 ]);
72
73
}
74
+ if (isHashCodeMethod (method )) {
75
+ return hashCode (proxy );
76
+ }
73
77
if (isToStringMethod (method )) {
74
78
return toString (proxy );
75
79
}
@@ -137,6 +141,12 @@ else if (value instanceof Annotation[]) {
137
141
return value ;
138
142
}
139
143
144
+ /**
145
+ * See {@link Annotation#equals(Object)} for a definition of the required algorithm.
146
+ *
147
+ * @param proxy the synthesized annotation
148
+ * @param other the other object to compare against
149
+ */
140
150
private boolean equals (Object proxy , Object other ) {
141
151
if (this == other ) {
142
152
return true ;
@@ -156,6 +166,72 @@ private boolean equals(Object proxy, Object other) {
156
166
return true ;
157
167
}
158
168
169
+ /**
170
+ * See {@link Annotation#hashCode()} for a definition of the required algorithm.
171
+ *
172
+ * @param proxy the synthesized annotation
173
+ */
174
+ private int hashCode (Object proxy ) {
175
+ int result = 0 ;
176
+
177
+ for (Method attributeMethod : getAttributeMethods (this .annotationType )) {
178
+ Object value = invokeMethod (attributeMethod , proxy );
179
+ int hashCode ;
180
+ if (value .getClass ().isArray ()) {
181
+ hashCode = hashCodeForArray (value );
182
+ }
183
+ else {
184
+ hashCode = value .hashCode ();
185
+ }
186
+ result += (127 * attributeMethod .getName ().hashCode ()) ^ hashCode ;
187
+ }
188
+
189
+ return result ;
190
+ }
191
+
192
+ /**
193
+ * WARNING: we can NOT use any of the {@code nullSafeHashCode()} methods
194
+ * in Spring's {@link ObjectUtils} because those hash code generation
195
+ * algorithms do not comply with the requirements specified in
196
+ * {@link Annotation#hashCode()}.
197
+ *
198
+ * @param array the array to compute the hash code for
199
+ */
200
+ private int hashCodeForArray (Object array ) {
201
+ if (array instanceof boolean []) {
202
+ return Arrays .hashCode ((boolean []) array );
203
+ }
204
+ if (array instanceof byte []) {
205
+ return Arrays .hashCode ((byte []) array );
206
+ }
207
+ if (array instanceof char []) {
208
+ return Arrays .hashCode ((char []) array );
209
+ }
210
+ if (array instanceof double []) {
211
+ return Arrays .hashCode ((double []) array );
212
+ }
213
+ if (array instanceof float []) {
214
+ return Arrays .hashCode ((float []) array );
215
+ }
216
+ if (array instanceof int []) {
217
+ return Arrays .hashCode ((int []) array );
218
+ }
219
+ if (array instanceof long []) {
220
+ return Arrays .hashCode ((long []) array );
221
+ }
222
+ if (array instanceof short []) {
223
+ return Arrays .hashCode ((short []) array );
224
+ }
225
+
226
+ // else
227
+ return Arrays .hashCode ((Object []) array );
228
+ }
229
+
230
+ /**
231
+ * See {@link Annotation#toString()} for guidelines on the recommended format.
232
+ *
233
+ * @param proxy the synthesized annotation
234
+ */
159
235
private String toString (Object proxy ) {
160
236
StringBuilder sb = new StringBuilder ("@" ).append (annotationType .getName ()).append ("(" );
161
237
0 commit comments