Skip to content

Commit

Permalink
Cache and late resolve annotations for performance
Browse files Browse the repository at this point in the history
Annotations are no longer resolved in the constructor and are cached
for improved performance.

Issue: SPR-9166
  • Loading branch information
philwebb committed Nov 3, 2012
1 parent 6e0400d commit 02ce826
Showing 1 changed file with 56 additions and 17 deletions.
Expand Up @@ -17,13 +17,16 @@
package org.springframework.core.convert;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

Expand All @@ -44,6 +47,9 @@
*/
public final class Property {

private static Map<Property, Annotation[]> annotationCache =
new ConcurrentReferenceHashMap<Property, Annotation[]>();

private final Class<?> objectType;

private final Method readMethod;
Expand Down Expand Up @@ -112,6 +118,9 @@ MethodParameter getMethodParameter() {
}

Annotation[] getAnnotations() {
if(this.annotations == null) {
this.annotations = resolveAnnotations();
}
return this.annotations;
}

Expand Down Expand Up @@ -182,26 +191,26 @@ private MethodParameter resolveParameterType(MethodParameter parameter) {
}

private Annotation[] resolveAnnotations() {
Map<Class<?>, Annotation> annMap = new LinkedHashMap<Class<?>, Annotation>();
Method readMethod = getReadMethod();
if (readMethod != null) {
for (Annotation ann : readMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
Annotation[] annotations = annotationCache.get(this);
if(annotations == null) {
Map<Class<? extends Annotation>, Annotation> annotationMap = new LinkedHashMap<Class<? extends Annotation>, Annotation>();
addAnnotationsToMap(annotationMap, getReadMethod());
addAnnotationsToMap(annotationMap, getWriteMethod());
addAnnotationsToMap(annotationMap, getField());
annotations = annotationMap.values().toArray(new Annotation[annotationMap.size()]);
annotationCache.put(this, annotations);
}
Method writeMethod = getWriteMethod();
if (writeMethod != null) {
for (Annotation ann : writeMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
Field field = getField();
if (field != null) {
for (Annotation ann : field.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
return annotations;
}

private void addAnnotationsToMap(
Map<Class<? extends Annotation>, Annotation> annotationMap,
AnnotatedElement object) {
if (object != null) {
for (Annotation annotation : object.getAnnotations()) {
annotationMap.put(annotation.annotationType(), annotation);
}
}
return annMap.values().toArray(new Annotation[annMap.size()]);
}

private Field getField() {
Expand Down Expand Up @@ -232,4 +241,34 @@ private Class<?> declaringClass() {
}
}

@Override
public int hashCode() {
final int prime = 31;
int hashCode = 1;
hashCode = prime * hashCode + ObjectUtils.nullSafeHashCode(objectType);
hashCode = prime * hashCode + ObjectUtils.nullSafeHashCode(readMethod);
hashCode = prime * hashCode + ObjectUtils.nullSafeHashCode(writeMethod);
hashCode = prime * hashCode + ObjectUtils.nullSafeHashCode(name);
return hashCode;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Property other = (Property) obj;
boolean equals = true;
equals &= ObjectUtils.nullSafeEquals(objectType, other.objectType);
equals &= ObjectUtils.nullSafeEquals(readMethod, other.readMethod);
equals &= ObjectUtils.nullSafeEquals(writeMethod, other.writeMethod);
equals &= ObjectUtils.nullSafeEquals(name, other.name);
return equals;
}
}

0 comments on commit 02ce826

Please sign in to comment.