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.
2525import java .util .Collection ;
2626import java .util .HashMap ;
2727import java .util .Map ;
28+ import java .util .function .Supplier ;
2829import java .util .stream .Stream ;
2930
3031import 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