Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid cloning empty Annotation array in TypeDescriptor #32405

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
Expand All @@ -52,8 +53,6 @@
@SuppressWarnings("serial")
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 Class<?>[] CACHED_COMMON_TYPES = {
Expand Down Expand Up @@ -84,7 +83,7 @@ public class TypeDescriptor implements Serializable {
public TypeDescriptor(MethodParameter methodParameter) {
this.resolvableType = ResolvableType.forMethodParameter(methodParameter);
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());
}

Expand All @@ -96,7 +95,7 @@ public TypeDescriptor(MethodParameter methodParameter) {
public TypeDescriptor(Field field) {
this.resolvableType = ResolvableType.forField(field);
this.type = this.resolvableType.resolve(field.getType());
this.annotatedElement = new AnnotatedElementAdapter(field.getAnnotations());
this.annotatedElement = AnnotatedElementAdapter.from(field.getAnnotations());
}

/**
Expand All @@ -109,7 +108,7 @@ public TypeDescriptor(Property property) {
Assert.notNull(property, "Property must not be null");
this.resolvableType = ResolvableType.forMethodParameter(property.getMethodParameter());
this.type = this.resolvableType.resolve(property.getType());
this.annotatedElement = new AnnotatedElementAdapter(property.getAnnotations());
this.annotatedElement = AnnotatedElementAdapter.from(property.getAnnotations());
}

/**
Expand All @@ -125,7 +124,7 @@ public TypeDescriptor(Property property) {
public TypeDescriptor(ResolvableType resolvableType, @Nullable Class<?> type, @Nullable Annotation[] annotations) {
this.resolvableType = resolvableType;
this.type = (type != null ? type : resolvableType.toClass());
this.annotatedElement = new AnnotatedElementAdapter(annotations);
this.annotatedElement = AnnotatedElementAdapter.from(annotations);
}


Expand Down Expand Up @@ -742,15 +741,23 @@ public static TypeDescriptor nested(Property property, int nestingLevel) {
* @see AnnotatedElementUtils#isAnnotated(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;

public AnnotatedElementAdapter(@Nullable Annotation[] annotations) {
private AnnotatedElementAdapter(@NonNull Annotation[] annotations) {
this.annotations = annotations;
}

private static AnnotatedElementAdapter from(@Nullable Annotation[] annotations) {
if (annotations == null || annotations.length == 0) {
return EMPTY;
}
return new AnnotatedElementAdapter(annotations);
}

@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
for (Annotation annotation : getAnnotations()) {
Expand All @@ -775,7 +782,7 @@ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {

@Override
public Annotation[] getAnnotations() {
return (this.annotations != null ? this.annotations.clone() : EMPTY_ANNOTATION_ARRAY);
return isEmpty() ? this.annotations : this.annotations.clone();
}

@Override
Expand All @@ -784,7 +791,7 @@ public Annotation[] getDeclaredAnnotations() {
}

public boolean isEmpty() {
return ObjectUtils.isEmpty(this.annotations);
return this.annotations.length == 0;
}

@Override
Expand All @@ -800,7 +807,7 @@ public int hashCode() {

@Override
public String toString() {
return TypeDescriptor.this.toString();
return "{AnnotatedElementAdapter annotations=" + Arrays.toString(this.annotations) + "}";
}
}

Expand Down