Skip to content

Commit 02ce826

Browse files
committed
Cache and late resolve annotations for performance
Annotations are no longer resolved in the constructor and are cached for improved performance. Issue: SPR-9166
1 parent 6e0400d commit 02ce826

File tree

1 file changed

+56
-17
lines changed
  • spring-core/src/main/java/org/springframework/core/convert

1 file changed

+56
-17
lines changed

spring-core/src/main/java/org/springframework/core/convert/Property.java

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
package org.springframework.core.convert;
1818

1919
import java.lang.annotation.Annotation;
20+
import java.lang.reflect.AnnotatedElement;
2021
import java.lang.reflect.Field;
2122
import java.lang.reflect.Method;
2223
import java.util.LinkedHashMap;
2324
import java.util.Map;
2425

2526
import org.springframework.core.GenericTypeResolver;
2627
import org.springframework.core.MethodParameter;
28+
import org.springframework.util.ConcurrentReferenceHashMap;
29+
import org.springframework.util.ObjectUtils;
2730
import org.springframework.util.ReflectionUtils;
2831
import org.springframework.util.StringUtils;
2932

@@ -44,6 +47,9 @@
4447
*/
4548
public final class Property {
4649

50+
private static Map<Property, Annotation[]> annotationCache =
51+
new ConcurrentReferenceHashMap<Property, Annotation[]>();
52+
4753
private final Class<?> objectType;
4854

4955
private final Method readMethod;
@@ -112,6 +118,9 @@ MethodParameter getMethodParameter() {
112118
}
113119

114120
Annotation[] getAnnotations() {
121+
if(this.annotations == null) {
122+
this.annotations = resolveAnnotations();
123+
}
115124
return this.annotations;
116125
}
117126

@@ -182,26 +191,26 @@ private MethodParameter resolveParameterType(MethodParameter parameter) {
182191
}
183192

184193
private Annotation[] resolveAnnotations() {
185-
Map<Class<?>, Annotation> annMap = new LinkedHashMap<Class<?>, Annotation>();
186-
Method readMethod = getReadMethod();
187-
if (readMethod != null) {
188-
for (Annotation ann : readMethod.getAnnotations()) {
189-
annMap.put(ann.annotationType(), ann);
190-
}
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);
191202
}
192-
Method writeMethod = getWriteMethod();
193-
if (writeMethod != null) {
194-
for (Annotation ann : writeMethod.getAnnotations()) {
195-
annMap.put(ann.annotationType(), ann);
196-
}
197-
}
198-
Field field = getField();
199-
if (field != null) {
200-
for (Annotation ann : field.getAnnotations()) {
201-
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);
202212
}
203213
}
204-
return annMap.values().toArray(new Annotation[annMap.size()]);
205214
}
206215

207216
private Field getField() {
@@ -232,4 +241,34 @@ private Class<?> declaringClass() {
232241
}
233242
}
234243

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+
}
235274
}

0 commit comments

Comments
 (0)