Skip to content

Commit f8926d6

Browse files
committed
Avoid cloning empty Annotation array in TypeDescriptor (backport)
Closes gh-32405
1 parent 19b21b1 commit f8926d6

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

@@ -512,12 +510,16 @@ public int hashCode() {
512510
public String toString() {
513511
StringBuilder builder = new StringBuilder();
514512
for (Annotation ann : getAnnotations()) {
515-
builder.append('@').append(ann.annotationType().getName()).append(' ');
513+
builder.append('@').append(getName(ann.annotationType())).append(' ');
516514
}
517515
builder.append(getResolvableType());
518516
return builder.toString();
519517
}
520518

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

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

738-
@Nullable
739742
private final Annotation[] annotations;
740743

741-
public AnnotatedElementAdapter(@Nullable Annotation[] annotations) {
744+
private AnnotatedElementAdapter(Annotation[] annotations) {
742745
this.annotations = annotations;
743746
}
744747

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

767777
@Override
768778
public Annotation[] getAnnotations() {
769-
return (this.annotations != null ? this.annotations.clone() : EMPTY_ANNOTATION_ARRAY);
779+
return (isEmpty() ? this.annotations : this.annotations.clone());
770780
}
771781

772782
@Override
@@ -775,7 +785,7 @@ public Annotation[] getDeclaredAnnotations() {
775785
}
776786

777787
public boolean isEmpty() {
778-
return ObjectUtils.isEmpty(this.annotations);
788+
return (this.annotations.length == 0);
779789
}
780790

781791
@Override
@@ -791,7 +801,7 @@ public int hashCode() {
791801

792802
@Override
793803
public String toString() {
794-
return TypeDescriptor.this.toString();
804+
return "AnnotatedElementAdapter annotations=" + Arrays.toString(this.annotations);
795805
}
796806
}
797807

0 commit comments

Comments
 (0)