mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-05-02 20:09:31 +01:00
Avoid cloning empty Annotation array in TypeDescriptor
Rework AnnotatedElementAdapter to avoid cloning the underlying Annotation array if it is empty when getAnnotations() is called. Additionally, make the class static and add a factory method that returns a singleton instance for null or empty Annotation arrays. Closes gh-32405
This commit is contained in:
committed by
Sam Brannen
parent
8172d7adfe
commit
7fa2a28970
@@ -30,6 +30,7 @@ import java.util.stream.Stream;
|
|||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
@@ -52,8 +53,6 @@ import org.springframework.util.ObjectUtils;
|
|||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class TypeDescriptor implements Serializable {
|
public class TypeDescriptor implements Serializable {
|
||||||
|
|
||||||
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
|
|
||||||
|
|
||||||
private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<>(32);
|
private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<>(32);
|
||||||
|
|
||||||
private static final Class<?>[] CACHED_COMMON_TYPES = {
|
private static final Class<?>[] CACHED_COMMON_TYPES = {
|
||||||
@@ -84,7 +83,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
public TypeDescriptor(MethodParameter methodParameter) {
|
public TypeDescriptor(MethodParameter methodParameter) {
|
||||||
this.resolvableType = ResolvableType.forMethodParameter(methodParameter);
|
this.resolvableType = ResolvableType.forMethodParameter(methodParameter);
|
||||||
this.type = this.resolvableType.resolve(methodParameter.getNestedParameterType());
|
this.type = this.resolvableType.resolve(methodParameter.getNestedParameterType());
|
||||||
this.annotatedElement = new AnnotatedElementAdapter(methodParameter.getParameterIndex() == -1 ?
|
this.annotatedElement = AnnotatedElementAdapter.from(methodParameter.getParameterIndex() == -1 ?
|
||||||
methodParameter.getMethodAnnotations() : methodParameter.getParameterAnnotations());
|
methodParameter.getMethodAnnotations() : methodParameter.getParameterAnnotations());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +95,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
public TypeDescriptor(Field field) {
|
public TypeDescriptor(Field field) {
|
||||||
this.resolvableType = ResolvableType.forField(field);
|
this.resolvableType = ResolvableType.forField(field);
|
||||||
this.type = this.resolvableType.resolve(field.getType());
|
this.type = this.resolvableType.resolve(field.getType());
|
||||||
this.annotatedElement = new AnnotatedElementAdapter(field.getAnnotations());
|
this.annotatedElement = AnnotatedElementAdapter.from(field.getAnnotations());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +108,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
Assert.notNull(property, "Property must not be null");
|
Assert.notNull(property, "Property must not be null");
|
||||||
this.resolvableType = ResolvableType.forMethodParameter(property.getMethodParameter());
|
this.resolvableType = ResolvableType.forMethodParameter(property.getMethodParameter());
|
||||||
this.type = this.resolvableType.resolve(property.getType());
|
this.type = this.resolvableType.resolve(property.getType());
|
||||||
this.annotatedElement = new AnnotatedElementAdapter(property.getAnnotations());
|
this.annotatedElement = AnnotatedElementAdapter.from(property.getAnnotations());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,7 +124,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
public TypeDescriptor(ResolvableType resolvableType, @Nullable Class<?> type, @Nullable Annotation[] annotations) {
|
public TypeDescriptor(ResolvableType resolvableType, @Nullable Class<?> type, @Nullable Annotation[] annotations) {
|
||||||
this.resolvableType = resolvableType;
|
this.resolvableType = resolvableType;
|
||||||
this.type = (type != null ? type : resolvableType.toClass());
|
this.type = (type != null ? type : resolvableType.toClass());
|
||||||
this.annotatedElement = new AnnotatedElementAdapter(annotations);
|
this.annotatedElement = AnnotatedElementAdapter.from(annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -742,15 +741,23 @@ public class TypeDescriptor implements Serializable {
|
|||||||
* @see AnnotatedElementUtils#isAnnotated(AnnotatedElement, Class)
|
* @see AnnotatedElementUtils#isAnnotated(AnnotatedElement, Class)
|
||||||
* @see AnnotatedElementUtils#getMergedAnnotation(AnnotatedElement, Class)
|
* @see AnnotatedElementUtils#getMergedAnnotation(AnnotatedElement, Class)
|
||||||
*/
|
*/
|
||||||
private class AnnotatedElementAdapter implements AnnotatedElement, Serializable {
|
private static final class AnnotatedElementAdapter implements AnnotatedElement, Serializable {
|
||||||
|
private static final AnnotatedElementAdapter EMPTY = new AnnotatedElementAdapter(new Annotation[0]);
|
||||||
|
|
||||||
@Nullable
|
@NonNull
|
||||||
private final Annotation[] annotations;
|
private final Annotation[] annotations;
|
||||||
|
|
||||||
public AnnotatedElementAdapter(@Nullable Annotation[] annotations) {
|
private AnnotatedElementAdapter(@NonNull Annotation[] annotations) {
|
||||||
this.annotations = annotations;
|
this.annotations = annotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static AnnotatedElementAdapter from(@Nullable Annotation[] annotations) {
|
||||||
|
if (annotations == null || annotations.length == 0) {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
return new AnnotatedElementAdapter(annotations);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
|
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
|
||||||
for (Annotation annotation : getAnnotations()) {
|
for (Annotation annotation : getAnnotations()) {
|
||||||
@@ -775,7 +782,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Annotation[] getAnnotations() {
|
public Annotation[] getAnnotations() {
|
||||||
return (this.annotations != null ? this.annotations.clone() : EMPTY_ANNOTATION_ARRAY);
|
return isEmpty() ? this.annotations : this.annotations.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -784,7 +791,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return ObjectUtils.isEmpty(this.annotations);
|
return this.annotations.length == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -800,7 +807,7 @@ public class TypeDescriptor implements Serializable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return TypeDescriptor.this.toString();
|
return "{AnnotatedElementAdapter annotations=" + Arrays.toString(this.annotations) + "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user