27
27
import org .springframework .util .MultiValueMap ;
28
28
29
29
/**
30
- * Utility class used to collect all annotation values including those declared on
31
- * meta-annotations.
30
+ * Utility class used to collect all annotation attributes, including those
31
+ * declared on meta-annotations.
32
32
*
33
33
* @author Phillip Webb
34
34
* @author Juergen Hoeller
@@ -39,7 +39,7 @@ public class AnnotatedElementUtils {
39
39
40
40
public static Set <String > getMetaAnnotationTypes (AnnotatedElement element , String annotationType ) {
41
41
final Set <String > types = new LinkedHashSet <String >();
42
- process (element , annotationType , false , new Processor <Object >() {
42
+ process (element , annotationType , true , false , new Processor <Object >() {
43
43
@ Override
44
44
public Object process (Annotation annotation , int metaDepth ) {
45
45
if (metaDepth > 0 ) {
@@ -55,7 +55,7 @@ public void postProcess(Annotation annotation, Object result) {
55
55
}
56
56
57
57
public static boolean hasMetaAnnotationTypes (AnnotatedElement element , String annotationType ) {
58
- return Boolean .TRUE .equals (process (element , annotationType , false , new Processor <Boolean >() {
58
+ return Boolean .TRUE .equals (process (element , annotationType , true , false , new Processor <Boolean >() {
59
59
@ Override
60
60
public Boolean process (Annotation annotation , int metaDepth ) {
61
61
if (metaDepth > 0 ) {
@@ -70,7 +70,7 @@ public void postProcess(Annotation annotation, Boolean result) {
70
70
}
71
71
72
72
public static boolean isAnnotated (AnnotatedElement element , String annotationType ) {
73
- return Boolean .TRUE .equals (process (element , annotationType , false , new Processor <Boolean >() {
73
+ return Boolean .TRUE .equals (process (element , annotationType , true , false , new Processor <Boolean >() {
74
74
@ Override
75
75
public Boolean process (Annotation annotation , int metaDepth ) {
76
76
return Boolean .TRUE ;
@@ -81,14 +81,59 @@ public void postProcess(Annotation annotation, Boolean result) {
81
81
}));
82
82
}
83
83
84
+ /**
85
+ * Delegates to {@link #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)},
86
+ * supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap}.
87
+ *
88
+ * @param element the annotated element
89
+ * @param annotationType the annotation type to find
90
+ * @see #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
91
+ */
84
92
public static AnnotationAttributes getAnnotationAttributes (AnnotatedElement element , String annotationType ) {
85
93
return getAnnotationAttributes (element , annotationType , false , false );
86
94
}
87
95
96
+ /**
97
+ * Delegates to {@link #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean, boolean, boolean)},
98
+ * supplying {@code true} for {@code searchInterfaces} and {@code false} for {@code searchClassHierarchy}.
99
+ *
100
+ * @param element the annotated element
101
+ * @param annotationType the annotation type to find
102
+ * @param classValuesAsString whether to convert Class references into
103
+ * Strings or to preserve them as Class references
104
+ * @param nestedAnnotationsAsMap whether to turn nested Annotation instances
105
+ * into {@link AnnotationAttributes} maps or to preserve them as Annotation
106
+ * instances
107
+ * @see #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean, boolean, boolean)
108
+ */
88
109
public static AnnotationAttributes getAnnotationAttributes (AnnotatedElement element , String annotationType ,
89
- final boolean classValuesAsString , final boolean nestedAnnotationsAsMap ) {
110
+ boolean classValuesAsString , boolean nestedAnnotationsAsMap ) {
111
+ return getAnnotationAttributes (element , annotationType , true , false , classValuesAsString ,
112
+ nestedAnnotationsAsMap );
113
+ }
90
114
91
- return process (element , annotationType , false , new Processor <AnnotationAttributes >() {
115
+ /**
116
+ * Find annotation attributes of the specified {@code annotationType} in
117
+ * the annotation hierarchy of the supplied {@link AnnotatedElement},
118
+ * and merge the results into an {@link AnnotationAttributes} map.
119
+ *
120
+ * @param element the annotated element
121
+ * @param annotationType the annotation type to find
122
+ * @param searchInterfaces whether or not to search on interfaces, if the
123
+ * annotated element is a class
124
+ * @param searchClassHierarchy whether or not to search the class hierarchy
125
+ * recursively, if the annotated element is a class
126
+ * @param classValuesAsString whether to convert Class references into
127
+ * Strings or to preserve them as Class references
128
+ * @param nestedAnnotationsAsMap whether to turn nested Annotation instances
129
+ * into {@link AnnotationAttributes} maps or to preserve them as Annotation
130
+ * instances
131
+ */
132
+ public static AnnotationAttributes getAnnotationAttributes (AnnotatedElement element , String annotationType ,
133
+ boolean searchInterfaces , boolean searchClassHierarchy , final boolean classValuesAsString ,
134
+ final boolean nestedAnnotationsAsMap ) {
135
+
136
+ return process (element , annotationType , searchInterfaces , searchClassHierarchy , new Processor <AnnotationAttributes >() {
92
137
@ Override
93
138
public AnnotationAttributes process (Annotation annotation , int metaDepth ) {
94
139
return AnnotationUtils .getAnnotationAttributes (annotation , classValuesAsString , nestedAnnotationsAsMap );
@@ -115,7 +160,7 @@ public static MultiValueMap<String, Object> getAllAnnotationAttributes(Annotated
115
160
final String annotationType , final boolean classValuesAsString , final boolean nestedAnnotationsAsMap ) {
116
161
117
162
final MultiValueMap <String , Object > attributes = new LinkedMultiValueMap <String , Object >();
118
- process (element , annotationType , false , new Processor <Void >() {
163
+ process (element , annotationType , true , false , new Processor <Void >() {
119
164
@ Override
120
165
public Void process (Annotation annotation , int metaDepth ) {
121
166
if (annotation .annotationType ().getName ().equals (annotationType )) {
@@ -144,22 +189,26 @@ public void postProcess(Annotation annotation, Void result) {
144
189
/**
145
190
* Process all annotations of the specified {@code annotationType} and
146
191
* recursively all meta-annotations on the specified {@code element}.
147
- * <p>If the {@code traverseClassHierarchy} flag is {@code true} and the sought
192
+ *
193
+ * <p>If the {@code searchClassHierarchy} flag is {@code true} and the sought
148
194
* annotation is neither <em>directly present</em> on the given element nor
149
195
* present on the given element as a meta-annotation, then the algorithm will
150
196
* recursively search through the class hierarchy of the given element.
197
+ *
151
198
* @param element the annotated element
152
199
* @param annotationType the annotation type to find
153
- * @param traverseClassHierarchy whether or not to traverse up the class
154
- * hierarchy recursively
200
+ * @param searchInterfaces whether or not to search on interfaces, if the
201
+ * annotated element is a class
202
+ * @param searchClassHierarchy whether or not to search the class hierarchy
203
+ * recursively, if the annotated element is a class
155
204
* @param processor the processor to delegate to
156
205
* @return the result of the processor
157
206
*/
158
- private static <T > T process (AnnotatedElement element , String annotationType , boolean traverseClassHierarchy ,
159
- Processor <T > processor ) {
207
+ private static <T > T process (AnnotatedElement element , String annotationType , boolean searchInterfaces ,
208
+ boolean searchClassHierarchy , Processor <T > processor ) {
160
209
161
210
try {
162
- return doProcess (element , annotationType , traverseClassHierarchy , processor ,
211
+ return doProcess (element , annotationType , searchInterfaces , searchClassHierarchy , processor ,
163
212
new HashSet <AnnotatedElement >(), 0 );
164
213
}
165
214
catch (Throwable ex ) {
@@ -171,54 +220,79 @@ private static <T> T process(AnnotatedElement element, String annotationType, bo
171
220
* Perform the search algorithm for the {@link #process} method, avoiding
172
221
* endless recursion by tracking which annotated elements have already been
173
222
* <em>visited</em>.
223
+ *
174
224
* <p>The {@code metaDepth} parameter represents the depth of the annotation
175
225
* relative to the initial element. For example, an annotation that is
176
226
* <em>present</em> on the element will have a depth of 0; a meta-annotation
177
227
* will have a depth of 1; and a meta-meta-annotation will have a depth of 2.
228
+ *
178
229
* @param element the annotated element
179
230
* @param annotationType the annotation type to find
180
- * @param traverseClassHierarchy whether or not to traverse up the class
181
- * hierarchy recursively
231
+ * @param searchInterfaces whether or not to search on interfaces, if the
232
+ * annotated element is a class
233
+ * @param searchClassHierarchy whether or not to search the class hierarchy
234
+ * recursively, if the annotated element is a class
182
235
* @param processor the processor to delegate to
183
236
* @param visited the set of annotated elements that have already been visited
184
237
* @param metaDepth the depth of the annotation relative to the initial element
185
238
* @return the result of the processor
186
239
*/
187
- private static <T > T doProcess (AnnotatedElement element , String annotationType , boolean traverseClassHierarchy ,
188
- Processor <T > processor , Set <AnnotatedElement > visited , int metaDepth ) {
240
+ private static <T > T doProcess (AnnotatedElement element , String annotationType , boolean searchInterfaces ,
241
+ boolean searchClassHierarchy , Processor <T > processor , Set <AnnotatedElement > visited , int metaDepth ) {
189
242
190
243
if (visited .add (element )) {
191
244
try {
245
+
246
+ // Local annotations: either directly declared or inherited.
192
247
Annotation [] annotations =
193
- (traverseClassHierarchy ? element .getDeclaredAnnotations () : element .getAnnotations ());
248
+ (searchClassHierarchy ? element .getDeclaredAnnotations () : element .getAnnotations ());
249
+
250
+ // Search in local annotations
194
251
for (Annotation annotation : annotations ) {
195
252
if (annotation .annotationType ().getName ().equals (annotationType ) || metaDepth > 0 ) {
196
253
T result = processor .process (annotation , metaDepth );
197
254
if (result != null ) {
198
255
return result ;
199
256
}
200
- result = doProcess (annotation .annotationType (), annotationType , traverseClassHierarchy ,
201
- processor , visited , metaDepth + 1 );
257
+ result = doProcess (annotation .annotationType (), annotationType , searchInterfaces ,
258
+ searchClassHierarchy , processor , visited , metaDepth + 1 );
202
259
if (result != null ) {
203
260
processor .postProcess (annotation , result );
204
261
return result ;
205
262
}
206
263
}
207
264
}
265
+
266
+ // Search in meta annotations on location annotations
208
267
for (Annotation annotation : annotations ) {
209
268
if (!AnnotationUtils .isInJavaLangAnnotationPackage (annotation )) {
210
- T result = doProcess (annotation .annotationType (), annotationType , traverseClassHierarchy ,
211
- processor , visited , metaDepth );
269
+ T result = doProcess (annotation .annotationType (), annotationType , searchInterfaces ,
270
+ searchClassHierarchy , processor , visited , metaDepth );
212
271
if (result != null ) {
213
272
processor .postProcess (annotation , result );
214
273
return result ;
215
274
}
216
275
}
217
276
}
218
- if (traverseClassHierarchy && element instanceof Class ) {
277
+
278
+ // Search on interfaces
279
+ if (searchInterfaces && element instanceof Class ) {
280
+ Class <?> clazz = (Class <?>) element ;
281
+ for (Class <?> ifc : clazz .getInterfaces ()) {
282
+ T result = doProcess (ifc , annotationType , searchInterfaces , searchClassHierarchy , processor ,
283
+ visited , metaDepth );
284
+ if (result != null ) {
285
+ return result ;
286
+ }
287
+ }
288
+ }
289
+
290
+ // Search on superclass
291
+ if (searchClassHierarchy && element instanceof Class ) {
219
292
Class <?> superclass = ((Class <?>) element ).getSuperclass ();
220
293
if (superclass != null && !superclass .equals (Object .class )) {
221
- T result = doProcess (superclass , annotationType , true , processor , visited , metaDepth );
294
+ T result = doProcess (superclass , annotationType , searchInterfaces , searchClassHierarchy ,
295
+ processor , visited , metaDepth );
222
296
if (result != null ) {
223
297
return result ;
224
298
}
0 commit comments