17
17
package org .springframework .core .convert ;
18
18
19
19
import java .lang .annotation .Annotation ;
20
+ import java .lang .reflect .AnnotatedElement ;
20
21
import java .lang .reflect .Field ;
21
22
import java .lang .reflect .Method ;
22
23
import java .util .LinkedHashMap ;
23
24
import java .util .Map ;
24
25
25
26
import org .springframework .core .GenericTypeResolver ;
26
27
import org .springframework .core .MethodParameter ;
28
+ import org .springframework .util .ConcurrentReferenceHashMap ;
29
+ import org .springframework .util .ObjectUtils ;
27
30
import org .springframework .util .ReflectionUtils ;
28
31
import org .springframework .util .StringUtils ;
29
32
37
40
* The built TypeDescriptor can then be used to convert from/to the property type.
38
41
*
39
42
* @author Keith Donald
43
+ * @author Phillip Webb
40
44
* @since 3.1
41
45
* @see TypeDescriptor#TypeDescriptor(Property)
42
46
* @see TypeDescriptor#nested(Property, int)
43
47
*/
44
48
public final class Property {
45
49
50
+ private static Map <Property , Annotation []> annotationCache =
51
+ new ConcurrentReferenceHashMap <Property , Annotation []>();
52
+
46
53
private final Class <?> objectType ;
47
54
48
55
private final Method readMethod ;
@@ -53,8 +60,7 @@ public final class Property {
53
60
54
61
private final MethodParameter methodParameter ;
55
62
56
- private final Annotation [] annotations ;
57
-
63
+ private Annotation [] annotations ;
58
64
59
65
public Property (Class <?> objectType , Method readMethod , Method writeMethod ) {
60
66
this (objectType , readMethod , writeMethod , null );
@@ -65,13 +71,7 @@ public Property(Class<?> objectType, Method readMethod, Method writeMethod, Stri
65
71
this .readMethod = readMethod ;
66
72
this .writeMethod = writeMethod ;
67
73
this .methodParameter = resolveMethodParameter ();
68
- if (name != null ) {
69
- this .name = name ;
70
- }
71
- else {
72
- this .name = resolveName ();
73
- }
74
- this .annotations = resolveAnnotations ();
74
+ this .name = (name == null ? resolveName () : name );
75
75
}
76
76
77
77
@@ -118,6 +118,9 @@ MethodParameter getMethodParameter() {
118
118
}
119
119
120
120
Annotation [] getAnnotations () {
121
+ if (this .annotations == null ) {
122
+ this .annotations = resolveAnnotations ();
123
+ }
121
124
return this .annotations ;
122
125
}
123
126
@@ -188,26 +191,26 @@ private MethodParameter resolveParameterType(MethodParameter parameter) {
188
191
}
189
192
190
193
private Annotation [] resolveAnnotations () {
191
- Map <Class <?>, Annotation > annMap = new LinkedHashMap <Class <?>, Annotation >();
192
- Method readMethod = getReadMethod ();
193
- if (readMethod != null ) {
194
- for (Annotation ann : readMethod .getAnnotations ()) {
195
- annMap .put (ann .annotationType (), ann );
196
- }
197
- }
198
- Method writeMethod = getWriteMethod ();
199
- if (writeMethod != null ) {
200
- for (Annotation ann : writeMethod .getAnnotations ()) {
201
- annMap .put (ann .annotationType (), ann );
202
- }
194
+ Annotation [] annotations = annotationCache .get (this );
195
+ if (annotations == null ) {
196
+ Map <Class <? extends Annotation >, Annotation > annotationMap = new LinkedHashMap <Class <? extends Annotation >, Annotation >();
197
+ addAnnotationsToMap (annotationMap , getReadMethod ());
198
+ addAnnotationsToMap (annotationMap , getWriteMethod ());
199
+ addAnnotationsToMap (annotationMap , getField ());
200
+ annotations = annotationMap .values ().toArray (new Annotation [annotationMap .size ()]);
201
+ annotationCache .put (this , annotations );
203
202
}
204
- Field field = getField ();
205
- if (field != null ) {
206
- for (Annotation ann : field .getAnnotations ()) {
207
- annMap .put (ann .annotationType (), ann );
203
+ return annotations ;
204
+ }
205
+
206
+ private void addAnnotationsToMap (
207
+ Map <Class <? extends Annotation >, Annotation > annotationMap ,
208
+ AnnotatedElement object ) {
209
+ if (object != null ) {
210
+ for (Annotation annotation : object .getAnnotations ()) {
211
+ annotationMap .put (annotation .annotationType (), annotation );
208
212
}
209
213
}
210
- return annMap .values ().toArray (new Annotation [annMap .size ()]);
211
214
}
212
215
213
216
private Field getField () {
@@ -238,4 +241,34 @@ private Class<?> declaringClass() {
238
241
}
239
242
}
240
243
244
+ @ Override
245
+ public int hashCode () {
246
+ final int prime = 31 ;
247
+ int hashCode = 1 ;
248
+ hashCode = prime * hashCode + ObjectUtils .nullSafeHashCode (objectType );
249
+ hashCode = prime * hashCode + ObjectUtils .nullSafeHashCode (readMethod );
250
+ hashCode = prime * hashCode + ObjectUtils .nullSafeHashCode (writeMethod );
251
+ hashCode = prime * hashCode + ObjectUtils .nullSafeHashCode (name );
252
+ return hashCode ;
253
+ }
254
+
255
+ @ Override
256
+ public boolean equals (Object obj ) {
257
+ if (this == obj ) {
258
+ return true ;
259
+ }
260
+ if (obj == null ) {
261
+ return false ;
262
+ }
263
+ if (getClass () != obj .getClass ()) {
264
+ return false ;
265
+ }
266
+ Property other = (Property ) obj ;
267
+ boolean equals = true ;
268
+ equals &= ObjectUtils .nullSafeEquals (objectType , other .objectType );
269
+ equals &= ObjectUtils .nullSafeEquals (readMethod , other .readMethod );
270
+ equals &= ObjectUtils .nullSafeEquals (writeMethod , other .writeMethod );
271
+ equals &= ObjectUtils .nullSafeEquals (name , other .name );
272
+ return equals ;
273
+ }
241
274
}
0 commit comments