Skip to content

Commit 1cb0c7c

Browse files
committed
Avoid cloning empty Annotation array in TypeDescriptor (backport)
Closes gh-32405
1 parent 51d70dc commit 1cb0c7c

File tree

1 file changed

+24
-14
lines changed

1 file changed

+24
-14
lines changed

Diff for: spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

+24-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,8 +52,6 @@
5252
@SuppressWarnings("serial")
5353
public class TypeDescriptor implements Serializable {
5454

55-
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
56-
5755
private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<>(32);
5856

5957
private static final Class<?>[] CACHED_COMMON_TYPES = {
@@ -84,7 +82,7 @@ public class TypeDescriptor implements Serializable {
8482
public TypeDescriptor(MethodParameter methodParameter) {
8583
this.resolvableType = ResolvableType.forMethodParameter(methodParameter);
8684
this.type = this.resolvableType.resolve(methodParameter.getNestedParameterType());
87-
this.annotatedElement = new AnnotatedElementAdapter(methodParameter.getParameterIndex() == -1 ?
85+
this.annotatedElement = AnnotatedElementAdapter.from(methodParameter.getParameterIndex() == -1 ?
8886
methodParameter.getMethodAnnotations() : methodParameter.getParameterAnnotations());
8987
}
9088

@@ -96,7 +94,7 @@ public TypeDescriptor(MethodParameter methodParameter) {
9694
public TypeDescriptor(Field field) {
9795
this.resolvableType = ResolvableType.forField(field);
9896
this.type = this.resolvableType.resolve(field.getType());
99-
this.annotatedElement = new AnnotatedElementAdapter(field.getAnnotations());
97+
this.annotatedElement = AnnotatedElementAdapter.from(field.getAnnotations());
10098
}
10199

102100
/**
@@ -109,7 +107,7 @@ public TypeDescriptor(Property property) {
109107
Assert.notNull(property, "Property must not be null");
110108
this.resolvableType = ResolvableType.forMethodParameter(property.getMethodParameter());
111109
this.type = this.resolvableType.resolve(property.getType());
112-
this.annotatedElement = new AnnotatedElementAdapter(property.getAnnotations());
110+
this.annotatedElement = AnnotatedElementAdapter.from(property.getAnnotations());
113111
}
114112

115113
/**
@@ -125,7 +123,7 @@ public TypeDescriptor(Property property) {
125123
public TypeDescriptor(ResolvableType resolvableType, @Nullable Class<?> type, @Nullable Annotation[] annotations) {
126124
this.resolvableType = resolvableType;
127125
this.type = (type != null ? type : resolvableType.toClass());
128-
this.annotatedElement = new AnnotatedElementAdapter(annotations);
126+
this.annotatedElement = AnnotatedElementAdapter.from(annotations);
129127
}
130128

131129

@@ -513,12 +511,16 @@ public int hashCode() {
513511
public String toString() {
514512
StringBuilder builder = new StringBuilder();
515513
for (Annotation ann : getAnnotations()) {
516-
builder.append('@').append(ann.annotationType().getName()).append(' ');
514+
builder.append('@').append(getName(ann.annotationType())).append(' ');
517515
}
518516
builder.append(getResolvableType());
519517
return builder.toString();
520518
}
521519

520+
private static String getName(Class<?> clazz) {
521+
String canonicalName = clazz.getCanonicalName();
522+
return (canonicalName != null ? canonicalName : clazz.getName());
523+
}
522524

523525
/**
524526
* Create a new type descriptor for an object.
@@ -734,15 +736,23 @@ private static TypeDescriptor getRelatedIfResolvable(TypeDescriptor source, Reso
734736
* @see AnnotatedElementUtils#isAnnotated(AnnotatedElement, Class)
735737
* @see AnnotatedElementUtils#getMergedAnnotation(AnnotatedElement, Class)
736738
*/
737-
private class AnnotatedElementAdapter implements AnnotatedElement, Serializable {
739+
private static final class AnnotatedElementAdapter implements AnnotatedElement, Serializable {
740+
741+
private static final AnnotatedElementAdapter EMPTY = new AnnotatedElementAdapter(new Annotation[0]);
738742

739-
@Nullable
740743
private final Annotation[] annotations;
741744

742-
public AnnotatedElementAdapter(@Nullable Annotation[] annotations) {
745+
private AnnotatedElementAdapter(Annotation[] annotations) {
743746
this.annotations = annotations;
744747
}
745748

749+
private static AnnotatedElementAdapter from(@Nullable Annotation[] annotations) {
750+
if (annotations == null || annotations.length == 0) {
751+
return EMPTY;
752+
}
753+
return new AnnotatedElementAdapter(annotations);
754+
}
755+
746756
@Override
747757
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
748758
for (Annotation annotation : getAnnotations()) {
@@ -767,7 +777,7 @@ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
767777

768778
@Override
769779
public Annotation[] getAnnotations() {
770-
return (this.annotations != null ? this.annotations.clone() : EMPTY_ANNOTATION_ARRAY);
780+
return (isEmpty() ? this.annotations : this.annotations.clone());
771781
}
772782

773783
@Override
@@ -776,7 +786,7 @@ public Annotation[] getDeclaredAnnotations() {
776786
}
777787

778788
public boolean isEmpty() {
779-
return ObjectUtils.isEmpty(this.annotations);
789+
return (this.annotations.length == 0);
780790
}
781791

782792
@Override
@@ -792,7 +802,7 @@ public int hashCode() {
792802

793803
@Override
794804
public String toString() {
795-
return TypeDescriptor.this.toString();
805+
return "AnnotatedElementAdapter annotations=" + Arrays.toString(this.annotations);
796806
}
797807
}
798808

0 commit comments

Comments
 (0)