Browse Source

Avoid cloning empty Annotation array in TypeDescriptor (backport)

Closes gh-32405
pull/32754/head
Juergen Hoeller 2 years ago
parent
commit
1cb0c7c036
  1. 38
      spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

38
spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -52,8 +52,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 +82,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 +94,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 +107,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 +123,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);
} }
@ -513,12 +511,16 @@ public class TypeDescriptor implements Serializable {
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (Annotation ann : getAnnotations()) { for (Annotation ann : getAnnotations()) {
builder.append('@').append(ann.annotationType().getName()).append(' '); builder.append('@').append(getName(ann.annotationType())).append(' ');
} }
builder.append(getResolvableType()); builder.append(getResolvableType());
return builder.toString(); 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. * Create a new type descriptor for an object.
@ -734,15 +736,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
private final Annotation[] annotations; private final Annotation[] annotations;
public AnnotatedElementAdapter(@Nullable Annotation[] annotations) { private AnnotatedElementAdapter(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()) {
@ -767,7 +777,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
@ -776,7 +786,7 @@ public class TypeDescriptor implements Serializable {
} }
public boolean isEmpty() { public boolean isEmpty() {
return ObjectUtils.isEmpty(this.annotations); return (this.annotations.length == 0);
} }
@Override @Override
@ -792,7 +802,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);
} }
} }

Loading…
Cancel
Save