13
13
*/
14
14
package ch .qos .logback .core .joran .spi ;
15
15
16
+
17
+ import java .lang .annotation .Annotation ;
18
+ import java .util .HashSet ;
19
+ import java .util .Set ;
16
20
import ch .qos .logback .core .spi .LifeCycle ;
17
21
18
22
public class NoAutoStartUtil {
@@ -24,13 +28,83 @@ public class NoAutoStartUtil {
24
28
* @param o
25
29
* @return true for classes not marked with the NoAutoStart annotation
26
30
*/
27
- static public boolean notMarkedWithNoAutoStart (Object o ) {
31
+ public static boolean notMarkedWithNoAutoStart (Object o ) {
32
+ if (o == null ) {
33
+ return false ;
34
+ }
28
35
Class <?> clazz = o .getClass ();
29
- NoAutoStart a = clazz . getAnnotation ( NoAutoStart .class );
36
+ NoAutoStart a = findAnnotation ( clazz , NoAutoStart .class );
30
37
return a == null ;
31
38
}
32
39
33
- /**
40
+ /**
41
+ * Find a single {@link Annotation} of {@code annotationType} on the
42
+ * supplied {@link Class}, traversing its interfaces, annotations, and
43
+ * superclasses if the annotation is not <em>directly present</em> on
44
+ * the given class itself.
45
+ * <p>This method explicitly handles class-level annotations which are not
46
+ * declared as {@link java.lang.annotation.Inherited inherited} <em>as well
47
+ * as meta-annotations and annotations on interfaces</em>.
48
+ * <p>The algorithm operates as follows:
49
+ * <ol>
50
+ * <li>Search for the annotation on the given class and return it if found.
51
+ * <li>Recursively search through all annotations that the given class declares.
52
+ * <li>Recursively search through all interfaces that the given class declares.
53
+ * <li>Recursively search through the superclass hierarchy of the given class.
54
+ * </ol>
55
+ * <p>Note: in this context, the term <em>recursively</em> means that the search
56
+ * process continues by returning to step #1 with the current interface,
57
+ * annotation, or superclass as the class to look for annotations on.
58
+ * @param clazz the class to look for annotations on
59
+ * @param annotationType the type of annotation to look for
60
+ * @return the first matching annotation, or {@code null} if not found
61
+ */
62
+ private static <A extends Annotation > A findAnnotation (Class <?> clazz , Class <A > annotationType ) {
63
+ return findAnnotation (clazz , annotationType , new HashSet <>());
64
+ }
65
+
66
+ /**
67
+ * Perform the search algorithm for {@link #findAnnotation(Class, Class)},
68
+ * avoiding endless recursion by tracking which annotations have already
69
+ * been <em>visited</em>.
70
+ * @param clazz the class to look for annotations on
71
+ * @param annotationType the type of annotation to look for
72
+ * @param visited the set of annotations that have already been visited
73
+ * @return the first matching annotation, or {@code null} if not found
74
+ */
75
+ @ SuppressWarnings ("unchecked" )
76
+ private static <A extends Annotation > A findAnnotation (Class <?> clazz , Class <A > annotationType , Set <Annotation > visited ) {
77
+
78
+ Annotation [] anns = clazz .getDeclaredAnnotations ();
79
+ for (Annotation ann : anns ) {
80
+ if (ann .annotationType () == annotationType ) {
81
+ return (A ) ann ;
82
+ }
83
+ }
84
+ for (Annotation ann : anns ) {
85
+ if (visited .add (ann )) {
86
+ A annotation = findAnnotation (ann .annotationType (), annotationType , visited );
87
+ if (annotation != null ) {
88
+ return annotation ;
89
+ }
90
+ }
91
+ }
92
+
93
+ for (Class <?> ifc : clazz .getInterfaces ()) {
94
+ A annotation = findAnnotation (ifc , annotationType , visited );
95
+ if (annotation != null ) {
96
+ return annotation ;
97
+ }
98
+ }
99
+
100
+ Class <?> superclass = clazz .getSuperclass ();
101
+ if (superclass == null || Object .class == superclass ) {
102
+ return null ;
103
+ }
104
+ return findAnnotation (superclass , annotationType , visited );
105
+ }
106
+
107
+ /**
34
108
* Is the object a {@link LifeCycle} and is it marked not marked with
35
109
* the NoAutoStart annotation.
36
110
* @param o
@@ -43,5 +117,4 @@ static public boolean shouldBeStarted(Object o) {
43
117
} else
44
118
return false ;
45
119
}
46
-
47
120
}
0 commit comments