Skip to content

Commit

Permalink
Avoid cloning empty Annotation array in TypeDescriptor (backport)
Browse files Browse the repository at this point in the history
Closes gh-32405
  • Loading branch information
jhoeller committed Mar 16, 2024
1 parent 51d70dc commit 1cb0c7c
Showing 1 changed file with 24 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -52,8 +52,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 +82,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 +94,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 +107,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 +123,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 @@ -513,12 +511,16 @@ public int hashCode() {
public String toString() {
StringBuilder builder = new StringBuilder();
for (Annotation ann : getAnnotations()) {
builder.append('@').append(ann.annotationType().getName()).append(' ');
builder.append('@').append(getName(ann.annotationType())).append(' ');
}
builder.append(getResolvableType());
return builder.toString();
}

private static String getName(Class<?> clazz) {
String canonicalName = clazz.getCanonicalName();
return (canonicalName != null ? canonicalName : clazz.getName());
}

/**
* Create a new type descriptor for an object.
Expand Down Expand Up @@ -734,15 +736,23 @@ private static TypeDescriptor getRelatedIfResolvable(TypeDescriptor source, Reso
* @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
private final Annotation[] annotations;

public AnnotatedElementAdapter(@Nullable Annotation[] annotations) {
private AnnotatedElementAdapter(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 @@ -767,7 +777,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 @@ -776,7 +786,7 @@ public Annotation[] getDeclaredAnnotations() {
}

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

@Override
Expand All @@ -792,7 +802,7 @@ public int hashCode() {

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

Expand Down

0 comments on commit 1cb0c7c

Please sign in to comment.