4545 * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners},
4646 * and {@link org.springframework.test.context.ActiveProfiles @ActiveProfiles}
4747 * 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}).
5050 *
5151 * @author Sam Brannen
5252 * @since 4.0
5555 */
5656public abstract class MetaAnnotationUtils {
5757
58- private MetaAnnotationUtils () {
59- /* no-op */
60- }
61-
6258 /**
6359 * Find the {@link AnnotationDescriptor} for the supplied {@code annotationType}
6460 * on the supplied {@link Class}, traversing its annotations and superclasses
6561 * if no annotation can be found on the given class itself.
66- *
6762 * <p>This method explicitly handles class-level annotations which are not
6863 * declared as {@linkplain java.lang.annotation.Inherited inherited} <em>as
6964 * well as meta-annotations</em>.
70- *
7165 * <p>The algorithm operates as follows:
7266 * <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.
7771 * </ol>
78- *
7972 * <p>In this context, the term <em>recursively</em> means that the search
8073 * process continues by returning to step #1 with the current annotation or
8174 * superclass as the class to look for annotations on.
82- *
8375 * <p>If the supplied {@code clazz} is an interface, only the interface
8476 * itself will be checked; the inheritance hierarchy for interfaces will not
8577 * be traversed.
86- *
8778 * @param clazz the class to look for annotations on
8879 * @param annotationType the type of annotation to look for
8980 * @return the corresponding annotation descriptor if the annotation was found;
9081 * otherwise {@code null}
9182 * @see AnnotationUtils#findAnnotationDeclaringClass(Class, Class)
9283 * @see #findAnnotationDescriptorForTypes(Class, Class...)
9384 */
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+
9688 return findAnnotationDescriptor (clazz , new HashSet <Annotation >(), annotationType );
9789 }
9890
9991 /**
10092 * Perform the search algorithm for {@link #findAnnotationDescriptor(Class, Class)},
10193 * avoiding endless recursion by tracking which annotations have already been
10294 * <em>visited</em>.
103- *
10495 * @param clazz the class to look for annotations on
10596 * @param visited the set of annotations that have already been visited
10697 * @param annotationType the type of annotation to look for
@@ -142,31 +133,25 @@ private static <T extends Annotation> AnnotationDescriptor<T> findAnnotationDesc
142133 * in the inheritance hierarchy of the specified {@code clazz} (including
143134 * the specified {@code clazz} itself) which declares at least one of the
144135 * specified {@code annotationTypes}.
145- *
146136 * <p>This method traverses the annotations and superclasses of the specified
147137 * {@code clazz} if no annotation can be found on the given class itself.
148- *
149138 * <p>This method explicitly handles class-level annotations which are not
150139 * declared as {@linkplain java.lang.annotation.Inherited inherited} <em>as
151140 * well as meta-annotations</em>.
152- *
153141 * <p>The algorithm operates as follows:
154142 * <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.
160148 * </ol>
161- *
162149 * <p>In this context, the term <em>recursively</em> means that the search
163150 * process continues by returning to step #1 with the current annotation or
164151 * superclass as the class to look for annotations on.
165- *
166152 * <p>If the supplied {@code clazz} is an interface, only the interface
167153 * itself will be checked; the inheritance hierarchy for interfaces will not
168154 * be traversed.
169- *
170155 * @param clazz the class to look for annotations on
171156 * @param annotationTypes the types of annotations to look for
172157 * @return the corresponding annotation descriptor if one of the annotations
@@ -175,16 +160,16 @@ private static <T extends Annotation> AnnotationDescriptor<T> findAnnotationDesc
175160 * @see #findAnnotationDescriptor(Class, Class)
176161 */
177162 @ 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+
180166 return findAnnotationDescriptorForTypes (clazz , new HashSet <Annotation >(), annotationTypes );
181167 }
182168
183169 /**
184170 * Perform the search algorithm for {@link #findAnnotationDescriptorForTypes(Class, Class...)},
185171 * avoiding endless recursion by tracking which annotations have already been
186172 * <em>visited</em>.
187- *
188173 * @param clazz the class to look for annotations on
189174 * @param visited the set of annotations that have already been visited
190175 * @param annotationTypes the types of annotations to look for
@@ -196,7 +181,6 @@ private static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(Clas
196181 Set <Annotation > visited , Class <? extends Annotation >... annotationTypes ) {
197182
198183 assertNonEmptyAnnotationTypeArray (annotationTypes , "The list of annotation types must not be empty" );
199-
200184 if (clazz == null || clazz .equals (Object .class )) {
201185 return null ;
202186 }
@@ -224,49 +208,50 @@ private static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(Clas
224208 return findAnnotationDescriptorForTypes (clazz .getSuperclass (), visited , annotationTypes );
225209 }
226210
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+
227222
228223 /**
229224 * Descriptor for an {@link Annotation}, including the {@linkplain
230225 * #getDeclaringClass() class} on which the annotation is <em>declared</em>
231226 * 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
235228 * the {@linkplain #getComposedAnnotation() composed annotation} on which the
236229 * annotation is present. In such cases, the <em>root declaring class</em> is
237230 * not directly annotated with the annotation but rather indirectly via the
238231 * 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}
242233 * annotation <em>on</em> the {@code TransactionalTests} class, then the
243234 * properties of the {@code AnnotationDescriptor} would be as follows.
244- *
245235 * <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>
250240 * </ul>
251- *
252241 * <pre style="code">
253242 * @Transactional
254243 * @ContextConfiguration({"/test-datasource.xml", "/repository-config.xml"})
255244 * public class TransactionalTests { }
256245 * </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}
260247 * annotation <em>on</em> the {@code UserRepositoryTests} class, then the
261248 * properties of the {@code AnnotationDescriptor} would be as follows.
262- *
263249 * <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>
268254 * </ul>
269- *
270255 * <pre style="code">
271256 * @Transactional
272257 * @ContextConfiguration({"/test-datasource.xml", "/repository-config.xml"})
@@ -276,18 +261,18 @@ private static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(Clas
276261 * @RepositoryTests
277262 * public class UserRepositoryTests { }
278263 * </pre>
279- *
280- * @author Sam Brannen
281- * @since 4.0
282264 */
283265 public static class AnnotationDescriptor <T extends Annotation > {
284266
285267 private final Class <?> rootDeclaringClass ;
268+
286269 private final Class <?> declaringClass ;
270+
287271 private final Annotation composedAnnotation ;
272+
288273 private final T annotation ;
289- private final AnnotationAttributes annotationAttributes ;
290274
275+ private final AnnotationAttributes annotationAttributes ;
291276
292277 public AnnotationDescriptor (Class <?> rootDeclaringClass , T annotation ) {
293278 this (rootDeclaringClass , rootDeclaringClass , null , annotation );
@@ -297,13 +282,12 @@ public AnnotationDescriptor(Class<?> rootDeclaringClass, Class<?> declaringClass
297282 Annotation composedAnnotation , T annotation ) {
298283 Assert .notNull (rootDeclaringClass , "rootDeclaringClass must not be null" );
299284 Assert .notNull (annotation , "annotation must not be null" );
300-
301285 this .rootDeclaringClass = rootDeclaringClass ;
302286 this .declaringClass = declaringClass ;
303287 this .composedAnnotation = composedAnnotation ;
304288 this .annotation = annotation ;
305- this .annotationAttributes = AnnotatedElementUtils .getAnnotationAttributes (rootDeclaringClass ,
306- annotation .annotationType ().getName ());
289+ this .annotationAttributes = AnnotatedElementUtils .getAnnotationAttributes (
290+ rootDeclaringClass , annotation .annotationType ().getName ());
307291 }
308292
309293 public Class <?> getRootDeclaringClass () {
@@ -331,30 +315,28 @@ public Annotation getComposedAnnotation() {
331315 }
332316
333317 public Class <? extends Annotation > getComposedAnnotationType () {
334- return this .composedAnnotation == null ? null : this .composedAnnotation .annotationType ();
318+ return ( this .composedAnnotation != null ? this .composedAnnotation .annotationType () : null );
335319 }
336320
337321 /**
338322 * Provide a textual representation of this {@code AnnotationDescriptor}.
339323 */
340324 @ Override
341325 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 ();
348332 }
349333 }
350334
335+
351336 /**
352337 * <em>Untyped</em> extension of {@code AnnotationDescriptor} that is used
353338 * to describe the declaration of one of several candidate annotation types
354339 * where the actual annotation type cannot be predetermined.
355- *
356- * @author Sam Brannen
357- * @since 4.0
358340 */
359341 public static class UntypedAnnotationDescriptor extends AnnotationDescriptor <Annotation > {
360342
@@ -368,17 +350,4 @@ public UntypedAnnotationDescriptor(Class<?> rootDeclaringClass, Class<?> declari
368350 }
369351 }
370352
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-
384353}
0 commit comments