1
1
/*
2
- * Copyright 2002-2024 the original author or authors.
2
+ * Copyright 2002-2025 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
25
25
import java .util .Collection ;
26
26
import java .util .HashMap ;
27
27
import java .util .Map ;
28
+ import java .util .function .Supplier ;
28
29
import java .util .stream .Stream ;
29
30
30
31
import org .springframework .core .MethodParameter ;
@@ -70,7 +71,10 @@ public class TypeDescriptor implements Serializable {
70
71
71
72
private final ResolvableType resolvableType ;
72
73
73
- private final AnnotatedElementAdapter annotatedElement ;
74
+ private final AnnotatedElementSupplier annotatedElementSupplier ;
75
+
76
+ @ Nullable
77
+ private volatile AnnotatedElementAdapter annotatedElement ;
74
78
75
79
76
80
/**
@@ -82,7 +86,7 @@ public class TypeDescriptor implements Serializable {
82
86
public TypeDescriptor (MethodParameter methodParameter ) {
83
87
this .resolvableType = ResolvableType .forMethodParameter (methodParameter );
84
88
this .type = this .resolvableType .resolve (methodParameter .getNestedParameterType ());
85
- this .annotatedElement = AnnotatedElementAdapter .from (methodParameter .getParameterIndex () == -1 ?
89
+ this .annotatedElementSupplier = () -> AnnotatedElementAdapter .from (methodParameter .getParameterIndex () == -1 ?
86
90
methodParameter .getMethodAnnotations () : methodParameter .getParameterAnnotations ());
87
91
}
88
92
@@ -94,7 +98,7 @@ public TypeDescriptor(MethodParameter methodParameter) {
94
98
public TypeDescriptor (Field field ) {
95
99
this .resolvableType = ResolvableType .forField (field );
96
100
this .type = this .resolvableType .resolve (field .getType ());
97
- this .annotatedElement = AnnotatedElementAdapter .from (field .getAnnotations ());
101
+ this .annotatedElementSupplier = () -> AnnotatedElementAdapter .from (field .getAnnotations ());
98
102
}
99
103
100
104
/**
@@ -107,7 +111,7 @@ public TypeDescriptor(Property property) {
107
111
Assert .notNull (property , "Property must not be null" );
108
112
this .resolvableType = ResolvableType .forMethodParameter (property .getMethodParameter ());
109
113
this .type = this .resolvableType .resolve (property .getType ());
110
- this .annotatedElement = AnnotatedElementAdapter .from (property .getAnnotations ());
114
+ this .annotatedElementSupplier = () -> AnnotatedElementAdapter .from (property .getAnnotations ());
111
115
}
112
116
113
117
/**
@@ -123,7 +127,7 @@ public TypeDescriptor(Property property) {
123
127
public TypeDescriptor (ResolvableType resolvableType , @ Nullable Class <?> type , @ Nullable Annotation [] annotations ) {
124
128
this .resolvableType = resolvableType ;
125
129
this .type = (type != null ? type : resolvableType .toClass ());
126
- this .annotatedElement = AnnotatedElementAdapter .from (annotations );
130
+ this .annotatedElementSupplier = () -> AnnotatedElementAdapter .from (annotations );
127
131
}
128
132
129
133
@@ -250,12 +254,21 @@ public boolean isPrimitive() {
250
254
return getType ().isPrimitive ();
251
255
}
252
256
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
+
253
266
/**
254
267
* Return the annotations associated with this type descriptor, if any.
255
268
* @return the annotations, or an empty array if none
256
269
*/
257
270
public Annotation [] getAnnotations () {
258
- return this . annotatedElement .getAnnotations ();
271
+ return getAnnotatedElement () .getAnnotations ();
259
272
}
260
273
261
274
/**
@@ -266,12 +279,13 @@ public Annotation[] getAnnotations() {
266
279
* @return {@code true} if the annotation is present
267
280
*/
268
281
public boolean hasAnnotation (Class <? extends Annotation > annotationType ) {
269
- if (this .annotatedElement .isEmpty ()) {
282
+ AnnotatedElementAdapter annotatedElement = getAnnotatedElement ();
283
+ if (annotatedElement .isEmpty ()) {
270
284
// Shortcut: AnnotatedElementUtils would have to expect AnnotatedElement.getAnnotations()
271
285
// to return a copy of the array, whereas we can do it more efficiently here.
272
286
return false ;
273
287
}
274
- return AnnotatedElementUtils .isAnnotated (this . annotatedElement , annotationType );
288
+ return AnnotatedElementUtils .isAnnotated (annotatedElement , annotationType );
275
289
}
276
290
277
291
/**
@@ -282,12 +296,13 @@ public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
282
296
*/
283
297
@ Nullable
284
298
public <T extends Annotation > T getAnnotation (Class <T > annotationType ) {
285
- if (this .annotatedElement .isEmpty ()) {
299
+ AnnotatedElementAdapter annotatedElement = getAnnotatedElement ();
300
+ if (annotatedElement .isEmpty ()) {
286
301
// Shortcut: AnnotatedElementUtils would have to expect AnnotatedElement.getAnnotations()
287
302
// to return a copy of the array, whereas we can do it more efficiently here.
288
303
return null ;
289
304
}
290
- return AnnotatedElementUtils .getMergedAnnotation (this . annotatedElement , annotationType );
305
+ return AnnotatedElementUtils .getMergedAnnotation (annotatedElement , annotationType );
291
306
}
292
307
293
308
/**
@@ -808,4 +823,8 @@ public String toString() {
808
823
}
809
824
}
810
825
826
+
827
+ private interface AnnotatedElementSupplier extends Supplier <AnnotatedElementAdapter >, Serializable {
828
+ }
829
+
811
830
}
0 commit comments