45
45
* {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners},
46
46
* and {@link org.springframework.test.context.ActiveProfiles @ActiveProfiles}
47
47
* which offer support for merging and overriding various <em>inherited</em>
48
- * annotation attributes (e.g., {@link
49
- * org.springframework.test.context.ContextConfiguration#inheritLocations}).
48
+ * annotation attributes (e.g.
49
+ * {@link org.springframework.test.context.ContextConfiguration#inheritLocations}).
50
50
*
51
51
* @author Sam Brannen
52
52
* @since 4.0
55
55
*/
56
56
public abstract class MetaAnnotationUtils {
57
57
58
- private MetaAnnotationUtils () {
59
- /* no-op */
60
- }
61
-
62
58
/**
63
59
* Find the {@link AnnotationDescriptor} for the supplied {@code annotationType}
64
60
* on the supplied {@link Class}, traversing its annotations and superclasses
65
61
* if no annotation can be found on the given class itself.
66
- *
67
62
* <p>This method explicitly handles class-level annotations which are not
68
63
* declared as {@linkplain java.lang.annotation.Inherited inherited} <em>as
69
64
* well as meta-annotations</em>.
70
- *
71
65
* <p>The algorithm operates as follows:
72
66
* <ol>
73
- * <li>Search for the annotation on the given class and return a corresponding
74
- * {@code AnnotationDescriptor} if found.
75
- * <li>Recursively search through all annotations that the given class declares.
76
- * <li>Recursively search through the superclass hierarchy of the given class.
67
+ * <li>Search for the annotation on the given class and return a corresponding
68
+ * {@code AnnotationDescriptor} if found.
69
+ * <li>Recursively search through all annotations that the given class declares.
70
+ * <li>Recursively search through the superclass hierarchy of the given class.
77
71
* </ol>
78
- *
79
72
* <p>In this context, the term <em>recursively</em> means that the search
80
73
* process continues by returning to step #1 with the current annotation or
81
74
* superclass as the class to look for annotations on.
82
- *
83
75
* <p>If the supplied {@code clazz} is an interface, only the interface
84
76
* itself will be checked; the inheritance hierarchy for interfaces will not
85
77
* be traversed.
86
- *
87
78
* @param clazz the class to look for annotations on
88
79
* @param annotationType the type of annotation to look for
89
80
* @return the corresponding annotation descriptor if the annotation was found;
90
81
* otherwise {@code null}
91
82
* @see AnnotationUtils#findAnnotationDeclaringClass(Class, Class)
92
83
* @see #findAnnotationDescriptorForTypes(Class, Class...)
93
84
*/
94
- public static <T extends Annotation > AnnotationDescriptor <T > findAnnotationDescriptor (Class <?> clazz ,
95
- Class <T > annotationType ) {
85
+ public static <T extends Annotation > AnnotationDescriptor <T > findAnnotationDescriptor (
86
+ Class <?> clazz , Class <T > annotationType ) {
87
+
96
88
return findAnnotationDescriptor (clazz , new HashSet <Annotation >(), annotationType );
97
89
}
98
90
99
91
/**
100
92
* Perform the search algorithm for {@link #findAnnotationDescriptor(Class, Class)},
101
93
* avoiding endless recursion by tracking which annotations have already been
102
94
* <em>visited</em>.
103
- *
104
95
* @param clazz the class to look for annotations on
105
96
* @param visited the set of annotations that have already been visited
106
97
* @param annotationType the type of annotation to look for
@@ -142,31 +133,25 @@ private static <T extends Annotation> AnnotationDescriptor<T> findAnnotationDesc
142
133
* in the inheritance hierarchy of the specified {@code clazz} (including
143
134
* the specified {@code clazz} itself) which declares at least one of the
144
135
* specified {@code annotationTypes}.
145
- *
146
136
* <p>This method traverses the annotations and superclasses of the specified
147
137
* {@code clazz} if no annotation can be found on the given class itself.
148
- *
149
138
* <p>This method explicitly handles class-level annotations which are not
150
139
* declared as {@linkplain java.lang.annotation.Inherited inherited} <em>as
151
140
* well as meta-annotations</em>.
152
- *
153
141
* <p>The algorithm operates as follows:
154
142
* <ol>
155
- * <li>Search for a local declaration of one of the annotation types on
156
- * the given class and return a corresponding {@code UntypedAnnotationDescriptor}
157
- * if found.
158
- * <li>Recursively search through all annotations that the given class declares.
159
- * <li>Recursively search through the superclass hierarchy of the given class.
143
+ * <li>Search for a local declaration of one of the annotation types on
144
+ * the given class and return a corresponding {@code UntypedAnnotationDescriptor}
145
+ * if found.
146
+ * <li>Recursively search through all annotations that the given class declares.
147
+ * <li>Recursively search through the superclass hierarchy of the given class.
160
148
* </ol>
161
- *
162
149
* <p>In this context, the term <em>recursively</em> means that the search
163
150
* process continues by returning to step #1 with the current annotation or
164
151
* superclass as the class to look for annotations on.
165
- *
166
152
* <p>If the supplied {@code clazz} is an interface, only the interface
167
153
* itself will be checked; the inheritance hierarchy for interfaces will not
168
154
* be traversed.
169
- *
170
155
* @param clazz the class to look for annotations on
171
156
* @param annotationTypes the types of annotations to look for
172
157
* @return the corresponding annotation descriptor if one of the annotations
@@ -175,16 +160,16 @@ private static <T extends Annotation> AnnotationDescriptor<T> findAnnotationDesc
175
160
* @see #findAnnotationDescriptor(Class, Class)
176
161
*/
177
162
@ SuppressWarnings ("unchecked" )
178
- public static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes (Class <?> clazz ,
179
- Class <? extends Annotation >... annotationTypes ) {
163
+ public static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes (
164
+ Class <?> clazz , Class <? extends Annotation >... annotationTypes ) {
165
+
180
166
return findAnnotationDescriptorForTypes (clazz , new HashSet <Annotation >(), annotationTypes );
181
167
}
182
168
183
169
/**
184
170
* Perform the search algorithm for {@link #findAnnotationDescriptorForTypes(Class, Class...)},
185
171
* avoiding endless recursion by tracking which annotations have already been
186
172
* <em>visited</em>.
187
- *
188
173
* @param clazz the class to look for annotations on
189
174
* @param visited the set of annotations that have already been visited
190
175
* @param annotationTypes the types of annotations to look for
@@ -196,7 +181,6 @@ private static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(Clas
196
181
Set <Annotation > visited , Class <? extends Annotation >... annotationTypes ) {
197
182
198
183
assertNonEmptyAnnotationTypeArray (annotationTypes , "The list of annotation types must not be empty" );
199
-
200
184
if (clazz == null || clazz .equals (Object .class )) {
201
185
return null ;
202
186
}
@@ -224,49 +208,50 @@ private static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(Clas
224
208
return findAnnotationDescriptorForTypes (clazz .getSuperclass (), visited , annotationTypes );
225
209
}
226
210
211
+ private static void assertNonEmptyAnnotationTypeArray (Class <?>[] annotationTypes , String message ) {
212
+ if (ObjectUtils .isEmpty (annotationTypes )) {
213
+ throw new IllegalArgumentException (message );
214
+ }
215
+ for (Class <?> clazz : annotationTypes ) {
216
+ if (!Annotation .class .isAssignableFrom (clazz )) {
217
+ throw new IllegalArgumentException ("Array elements must be of type Annotation" );
218
+ }
219
+ }
220
+ }
221
+
227
222
228
223
/**
229
224
* Descriptor for an {@link Annotation}, including the {@linkplain
230
225
* #getDeclaringClass() class} on which the annotation is <em>declared</em>
231
226
* as well as the actual {@linkplain #getAnnotation() annotation} instance.
232
- *
233
- * <p>
234
- * If the annotation is used as a meta-annotation, the descriptor also includes
227
+ * <p>If the annotation is used as a meta-annotation, the descriptor also includes
235
228
* the {@linkplain #getComposedAnnotation() composed annotation} on which the
236
229
* annotation is present. In such cases, the <em>root declaring class</em> is
237
230
* not directly annotated with the annotation but rather indirectly via the
238
231
* composed annotation.
239
- *
240
- * <p>
241
- * Given the following example, if we are searching for the {@code @Transactional}
232
+ * <p>Given the following example, if we are searching for the {@code @Transactional}
242
233
* annotation <em>on</em> the {@code TransactionalTests} class, then the
243
234
* properties of the {@code AnnotationDescriptor} would be as follows.
244
- *
245
235
* <ul>
246
- * <li>rootDeclaringClass: {@code TransactionalTests} class object</li>
247
- * <li>declaringClass: {@code TransactionalTests} class object</li>
248
- * <li>composedAnnotation: {@code null}</li>
249
- * <li>annotation: instance of the {@code Transactional} annotation</li>
236
+ * <li>rootDeclaringClass: {@code TransactionalTests} class object</li>
237
+ * <li>declaringClass: {@code TransactionalTests} class object</li>
238
+ * <li>composedAnnotation: {@code null}</li>
239
+ * <li>annotation: instance of the {@code Transactional} annotation</li>
250
240
* </ul>
251
- *
252
241
* <pre style="code">
253
242
* @Transactional
254
243
* @ContextConfiguration({"/test-datasource.xml", "/repository-config.xml"})
255
244
* public class TransactionalTests { }
256
245
* </pre>
257
- *
258
- * <p>
259
- * Given the following example, if we are searching for the {@code @Transactional}
246
+ * <p>Given the following example, if we are searching for the {@code @Transactional}
260
247
* annotation <em>on</em> the {@code UserRepositoryTests} class, then the
261
248
* properties of the {@code AnnotationDescriptor} would be as follows.
262
- *
263
249
* <ul>
264
- * <li>rootDeclaringClass: {@code UserRepositoryTests} class object</li>
265
- * <li>declaringClass: {@code RepositoryTests} class object</li>
266
- * <li>composedAnnotation: instance of the {@code RepositoryTests} annotation</li>
267
- * <li>annotation: instance of the {@code Transactional} annotation</li>
250
+ * <li>rootDeclaringClass: {@code UserRepositoryTests} class object</li>
251
+ * <li>declaringClass: {@code RepositoryTests} class object</li>
252
+ * <li>composedAnnotation: instance of the {@code RepositoryTests} annotation</li>
253
+ * <li>annotation: instance of the {@code Transactional} annotation</li>
268
254
* </ul>
269
- *
270
255
* <pre style="code">
271
256
* @Transactional
272
257
* @ContextConfiguration({"/test-datasource.xml", "/repository-config.xml"})
@@ -276,18 +261,18 @@ private static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(Clas
276
261
* @RepositoryTests
277
262
* public class UserRepositoryTests { }
278
263
* </pre>
279
- *
280
- * @author Sam Brannen
281
- * @since 4.0
282
264
*/
283
265
public static class AnnotationDescriptor <T extends Annotation > {
284
266
285
267
private final Class <?> rootDeclaringClass ;
268
+
286
269
private final Class <?> declaringClass ;
270
+
287
271
private final Annotation composedAnnotation ;
272
+
288
273
private final T annotation ;
289
- private final AnnotationAttributes annotationAttributes ;
290
274
275
+ private final AnnotationAttributes annotationAttributes ;
291
276
292
277
public AnnotationDescriptor (Class <?> rootDeclaringClass , T annotation ) {
293
278
this (rootDeclaringClass , rootDeclaringClass , null , annotation );
@@ -297,13 +282,12 @@ public AnnotationDescriptor(Class<?> rootDeclaringClass, Class<?> declaringClass
297
282
Annotation composedAnnotation , T annotation ) {
298
283
Assert .notNull (rootDeclaringClass , "rootDeclaringClass must not be null" );
299
284
Assert .notNull (annotation , "annotation must not be null" );
300
-
301
285
this .rootDeclaringClass = rootDeclaringClass ;
302
286
this .declaringClass = declaringClass ;
303
287
this .composedAnnotation = composedAnnotation ;
304
288
this .annotation = annotation ;
305
- this .annotationAttributes = AnnotatedElementUtils .getAnnotationAttributes (rootDeclaringClass ,
306
- annotation .annotationType ().getName ());
289
+ this .annotationAttributes = AnnotatedElementUtils .getAnnotationAttributes (
290
+ rootDeclaringClass , annotation .annotationType ().getName ());
307
291
}
308
292
309
293
public Class <?> getRootDeclaringClass () {
@@ -331,30 +315,28 @@ public Annotation getComposedAnnotation() {
331
315
}
332
316
333
317
public Class <? extends Annotation > getComposedAnnotationType () {
334
- return this .composedAnnotation == null ? null : this .composedAnnotation .annotationType ();
318
+ return ( this .composedAnnotation != null ? this .composedAnnotation .annotationType () : null );
335
319
}
336
320
337
321
/**
338
322
* Provide a textual representation of this {@code AnnotationDescriptor}.
339
323
*/
340
324
@ Override
341
325
public String toString () {
342
- return new ToStringCreator (this )//
343
- .append ("rootDeclaringClass" , rootDeclaringClass )//
344
- .append ("declaringClass" , declaringClass )//
345
- .append ("composedAnnotation" , composedAnnotation )//
346
- .append ("annotation" , annotation )//
347
- .toString ();
326
+ return new ToStringCreator (this )
327
+ .append ("rootDeclaringClass" , this . rootDeclaringClass )
328
+ .append ("declaringClass" , this . declaringClass )
329
+ .append ("composedAnnotation" , this . composedAnnotation )
330
+ .append ("annotation" , this . annotation )
331
+ .toString ();
348
332
}
349
333
}
350
334
335
+
351
336
/**
352
337
* <em>Untyped</em> extension of {@code AnnotationDescriptor} that is used
353
338
* to describe the declaration of one of several candidate annotation types
354
339
* where the actual annotation type cannot be predetermined.
355
- *
356
- * @author Sam Brannen
357
- * @since 4.0
358
340
*/
359
341
public static class UntypedAnnotationDescriptor extends AnnotationDescriptor <Annotation > {
360
342
@@ -368,17 +350,4 @@ public UntypedAnnotationDescriptor(Class<?> rootDeclaringClass, Class<?> declari
368
350
}
369
351
}
370
352
371
-
372
- private static void assertNonEmptyAnnotationTypeArray (Class <?>[] annotationTypes , String message ) {
373
- if (ObjectUtils .isEmpty (annotationTypes )) {
374
- throw new IllegalArgumentException (message );
375
- }
376
-
377
- for (Class <?> clazz : annotationTypes ) {
378
- if (!Annotation .class .isAssignableFrom (clazz )) {
379
- throw new IllegalArgumentException ("Array elements must be of type Annotation" );
380
- }
381
- }
382
- }
383
-
384
353
}
0 commit comments