Skip to content

Commit 1a573d6

Browse files
committed
Lazily retrieve TypeDescriptor annotations on demand
Closes gh-33948
1 parent bb7a800 commit 1a573d6

File tree

1 file changed

+30
-11
lines changed

1 file changed

+30
-11
lines changed

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

+30-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 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.
@@ -25,6 +25,7 @@
2525
import java.util.Collection;
2626
import java.util.HashMap;
2727
import java.util.Map;
28+
import java.util.function.Supplier;
2829
import java.util.stream.Stream;
2930

3031
import org.springframework.core.MethodParameter;
@@ -70,7 +71,10 @@ public class TypeDescriptor implements Serializable {
7071

7172
private final ResolvableType resolvableType;
7273

73-
private final AnnotatedElementAdapter annotatedElement;
74+
private final AnnotatedElementSupplier annotatedElementSupplier;
75+
76+
@Nullable
77+
private volatile AnnotatedElementAdapter annotatedElement;
7478

7579

7680
/**
@@ -82,7 +86,7 @@ public class TypeDescriptor implements Serializable {
8286
public TypeDescriptor(MethodParameter methodParameter) {
8387
this.resolvableType = ResolvableType.forMethodParameter(methodParameter);
8488
this.type = this.resolvableType.resolve(methodParameter.getNestedParameterType());
85-
this.annotatedElement = AnnotatedElementAdapter.from(methodParameter.getParameterIndex() == -1 ?
89+
this.annotatedElementSupplier = () -> AnnotatedElementAdapter.from(methodParameter.getParameterIndex() == -1 ?
8690
methodParameter.getMethodAnnotations() : methodParameter.getParameterAnnotations());
8791
}
8892

@@ -94,7 +98,7 @@ public TypeDescriptor(MethodParameter methodParameter) {
9498
public TypeDescriptor(Field field) {
9599
this.resolvableType = ResolvableType.forField(field);
96100
this.type = this.resolvableType.resolve(field.getType());
97-
this.annotatedElement = AnnotatedElementAdapter.from(field.getAnnotations());
101+
this.annotatedElementSupplier = () -> AnnotatedElementAdapter.from(field.getAnnotations());
98102
}
99103

100104
/**
@@ -107,7 +111,7 @@ public TypeDescriptor(Property property) {
107111
Assert.notNull(property, "Property must not be null");
108112
this.resolvableType = ResolvableType.forMethodParameter(property.getMethodParameter());
109113
this.type = this.resolvableType.resolve(property.getType());
110-
this.annotatedElement = AnnotatedElementAdapter.from(property.getAnnotations());
114+
this.annotatedElementSupplier = () -> AnnotatedElementAdapter.from(property.getAnnotations());
111115
}
112116

113117
/**
@@ -123,7 +127,7 @@ public TypeDescriptor(Property property) {
123127
public TypeDescriptor(ResolvableType resolvableType, @Nullable Class<?> type, @Nullable Annotation[] annotations) {
124128
this.resolvableType = resolvableType;
125129
this.type = (type != null ? type : resolvableType.toClass());
126-
this.annotatedElement = AnnotatedElementAdapter.from(annotations);
130+
this.annotatedElementSupplier = () -> AnnotatedElementAdapter.from(annotations);
127131
}
128132

129133

@@ -250,12 +254,21 @@ public boolean isPrimitive() {
250254
return getType().isPrimitive();
251255
}
252256

257+
private AnnotatedElementAdapter getAnnotatedElement() {
258+
AnnotatedElementAdapter annotatedElement = this.annotatedElement;
259+
if (annotatedElement == null) {
260+
annotatedElement = this.annotatedElementSupplier.get();
261+
this.annotatedElement = annotatedElement;
262+
}
263+
return annotatedElement;
264+
}
265+
253266
/**
254267
* Return the annotations associated with this type descriptor, if any.
255268
* @return the annotations, or an empty array if none
256269
*/
257270
public Annotation[] getAnnotations() {
258-
return this.annotatedElement.getAnnotations();
271+
return getAnnotatedElement().getAnnotations();
259272
}
260273

261274
/**
@@ -266,12 +279,13 @@ public Annotation[] getAnnotations() {
266279
* @return {@code true} if the annotation is present
267280
*/
268281
public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
269-
if (this.annotatedElement.isEmpty()) {
282+
AnnotatedElementAdapter annotatedElement = getAnnotatedElement();
283+
if (annotatedElement.isEmpty()) {
270284
// Shortcut: AnnotatedElementUtils would have to expect AnnotatedElement.getAnnotations()
271285
// to return a copy of the array, whereas we can do it more efficiently here.
272286
return false;
273287
}
274-
return AnnotatedElementUtils.isAnnotated(this.annotatedElement, annotationType);
288+
return AnnotatedElementUtils.isAnnotated(annotatedElement, annotationType);
275289
}
276290

277291
/**
@@ -282,12 +296,13 @@ public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
282296
*/
283297
@Nullable
284298
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
285-
if (this.annotatedElement.isEmpty()) {
299+
AnnotatedElementAdapter annotatedElement = getAnnotatedElement();
300+
if (annotatedElement.isEmpty()) {
286301
// Shortcut: AnnotatedElementUtils would have to expect AnnotatedElement.getAnnotations()
287302
// to return a copy of the array, whereas we can do it more efficiently here.
288303
return null;
289304
}
290-
return AnnotatedElementUtils.getMergedAnnotation(this.annotatedElement, annotationType);
305+
return AnnotatedElementUtils.getMergedAnnotation(annotatedElement, annotationType);
291306
}
292307

293308
/**
@@ -808,4 +823,8 @@ public String toString() {
808823
}
809824
}
810825

826+
827+
private interface AnnotatedElementSupplier extends Supplier<AnnotatedElementAdapter>, Serializable {
828+
}
829+
811830
}

0 commit comments

Comments
 (0)