10
10
import java .lang .annotation .ElementType ;
11
11
import java .lang .annotation .Repeatable ;
12
12
import java .lang .annotation .Target ;
13
- import java .util .ArrayList ;
14
13
import java .util .Collection ;
15
14
import java .util .EnumSet ;
16
15
import java .util .List ;
19
18
import org .hibernate .models .AnnotationAccessException ;
20
19
21
20
/**
22
- * Abstraction of {@linkplain java.lang.reflect.AnnotatedElement}
21
+ * Abstract for something where an annotation can be {@linkplain AnnotationUsage used}.
22
+ *
23
+ * @see java.lang.reflect.AnnotatedElement
23
24
*
24
25
* @author Steve Ebersole
25
26
*/
@@ -36,24 +37,50 @@ public interface AnnotationTarget {
36
37
37
38
/**
38
39
* Access to all the annotations used on this target.
40
+ *
41
+ * @apiNote This returns the usages directly available on the target; it does not
42
+ * expand repeatable containers (e.g. NamedQueries -> *NamedQuery).
39
43
*/
40
44
Collection <AnnotationUsage <?>> getAllAnnotationUsages ();
41
45
46
+ /**
47
+ * Allows to visit every annotation on the target.
48
+ *
49
+ * @apiNote Only visits the usages directly available on the target; it does not
50
+ * visit across repeatable containers (e.g. NamedQueries -> *NamedQuery).
51
+ */
42
52
default void forAllAnnotationUsages (Consumer <AnnotationUsage <?>> consumer ) {
43
53
getAllAnnotationUsages ().forEach ( consumer );
44
54
}
45
55
46
56
/**
47
- * Whether the given annotation is used on this target
57
+ * Whether the given annotation is used on this target.
58
+ *
59
+ * @see #hasRepeatableAnnotationUsage
60
+ *
61
+ * @apiNote This form does not check across repeatable containers. E.g., calling this
62
+ * method with {@code NamedQuery} will return {@code false} when the target directly
63
+ * has a NamedQueries.
48
64
*/
49
65
<A extends Annotation > boolean hasAnnotationUsage (Class <A > type );
50
66
67
+ /**
68
+ * Whether the given annotation is used on this target.
69
+ *
70
+ * @see #hasAnnotationUsage
71
+ *
72
+ * @apiNote This forms does check across repeatable containers. E.g., calling this
73
+ * method with {@code NamedQuery} will return {@code true} when the target directly
74
+ * has a NamedQueries.
75
+ */
76
+ <A extends Annotation > boolean hasRepeatableAnnotationUsage (Class <A > type );
77
+
51
78
/**
52
79
* Get the usage of the given annotation on this target.
53
80
* <p/>
54
81
* For {@linkplain Repeatable repeatable} annotation types (e.g. {@code @NamedQuery}), this method will either-<ul>
55
82
* <li>
56
- * if the repeatable annotation itself is present, it is returned.
83
+ * if a single repeatable annotation itself is present, it is returned.
57
84
* </li>
58
85
* <li>
59
86
* if the {@linkplain Repeatable#value() "containing annotation"} is present (e.g. {@code @NamedQueries}), <ul>
@@ -67,15 +94,14 @@ default void forAllAnnotationUsages(Consumer<AnnotationUsage<?>> consumer) {
67
94
* </li>
68
95
* </ul>
69
96
* <p/>
70
- * For annotations which can {@linkplain ElementType#ANNOTATION_TYPE target annotations},
71
- * all annotations on this target will be checked as well.
97
+ * For also checking across meta-annotations, see {@linkplain #locateAnnotationUsage(Class)}.
72
98
*
73
99
* @return The usage or {@code null}
74
100
*/
75
101
<A extends Annotation > AnnotationUsage <A > getAnnotationUsage (AnnotationDescriptor <A > descriptor );
76
102
77
103
/**
78
- * Helper form of {@link #getAnnotationUsage(AnnotationDescriptor)}
104
+ * Form of {@link #getAnnotationUsage(AnnotationDescriptor)} accepting the annotation {@linkplain Class }
79
105
*/
80
106
<A extends Annotation > AnnotationUsage <A > getAnnotationUsage (Class <A > type );
81
107
@@ -87,26 +113,17 @@ default void forAllAnnotationUsages(Consumer<AnnotationUsage<?>> consumer) {
87
113
88
114
/**
89
115
* Get all usages of the specified {@code annotationType} in this scope.
90
- * <p/>
91
- * For {@linkplain Repeatable repeatable} annotation types (e.g. {@code @NamedQuery}) -<ul>
92
- * <li>
93
- * if the repeatable annotation itself is present, a singleton list containing that single usage is returned
94
- * </li>
95
- * <li>
96
- * if the {@linkplain Repeatable#value() "containing annotation"} (e.g. {@code @NamedQueries}) is present,
97
- * the contained repeatable usages are extracted from the container and returned as a list
98
- * </li>
99
- * <li>
100
- * Otherwise, an empty list is returned.
101
- * </li>
102
- * </ul>
103
116
*
104
- * @apiNote If the passed annotation type is not repeatable, an empty list is returned.
117
+ * @apiNote For {@linkplain Repeatable repeatable} annotation types (e.g. {@code @NamedQuery}),
118
+ * the returned list will contain the union of <ol>
119
+ * <li>the singular {@code @NamedQuery} usage</li>
120
+ * <li>the nested {@code @NamedQuery} usages from the {@code @NamedQueries} usage</li>
121
+ * </ol>
105
122
*/
106
123
<A extends Annotation > List <AnnotationUsage <A >> getRepeatedAnnotationUsages (AnnotationDescriptor <A > type );
107
124
108
125
/**
109
- * Helper form of {@linkplain #getRepeatedAnnotationUsages(AnnotationDescriptor)}
126
+ * Form of {@linkplain #getRepeatedAnnotationUsages(AnnotationDescriptor)} accepting the annotation {@linkplain Class }
110
127
*/
111
128
<A extends Annotation > List <AnnotationUsage <A >> getRepeatedAnnotationUsages (Class <A > type );
112
129
@@ -128,7 +145,7 @@ default <X extends Annotation> void forEachAnnotationUsage(
128
145
}
129
146
130
147
/**
131
- * Helper form of {@link #forEachAnnotationUsage(AnnotationDescriptor, Consumer)}
148
+ * Form of {@link #forEachAnnotationUsage(AnnotationDescriptor, Consumer)} accepting the annotation {@linkplain Class }
132
149
*/
133
150
<X extends Annotation > void forEachAnnotationUsage (Class <X > type , Consumer <AnnotationUsage <X >> consumer );
134
151
@@ -155,17 +172,11 @@ default <X extends Annotation> void forEachAnnotationUsage(
155
172
* </pre>
156
173
* a call to this method passing {@code TheMeta} on {@code ClassDetails(TheClass)} will return
157
174
* the usage of {@code @TheAnnotation} on {@code TheClass}.
175
+ *
176
+ * @apiNote This method does not check across repeatable containers. Although the return is a List, we
177
+ * are functionally wanting just the unique ones.
158
178
*/
159
- default <A extends Annotation > List <AnnotationUsage <? extends Annotation >> getMetaAnnotated (Class <A > metaAnnotationType ) {
160
- final List <AnnotationUsage <?>> usages = new ArrayList <>();
161
- forAllAnnotationUsages ( (usage ) -> {
162
- final AnnotationUsage <? extends Annotation > metaUsage = usage .getAnnotationDescriptor ().getAnnotationUsage ( metaAnnotationType );
163
- if ( metaUsage != null ) {
164
- usages .add ( usage );
165
- }
166
- } );
167
- return usages ;
168
- }
179
+ <A extends Annotation > List <AnnotationUsage <? extends Annotation >> getMetaAnnotated (Class <A > metaAnnotationType );
169
180
170
181
/**
171
182
* Get a usage of the given annotation {@code type} whose {@code attributeToMatch} attribute value
@@ -208,6 +219,43 @@ <X extends Annotation> AnnotationUsage<X> getNamedAnnotationUsage(
208
219
String matchName ,
209
220
String attributeToMatch );
210
221
222
+ /**
223
+ * Functional contract to process an annotation and return a value.
224
+ *
225
+ * @param <T> The type of the value being returned.
226
+ */
227
+ @ FunctionalInterface
228
+ interface AnnotationUsageProcessor <T > {
229
+ /**
230
+ * The processed value. May be {@code null} to indicate a "no match"
231
+ */
232
+ T process (AnnotationUsage <? extends Annotation > annotationUsage );
233
+ }
234
+
235
+ /**
236
+ * Returns a "matching value" using the passed {@code processor} from the
237
+ * annotations, of the passed {@code annotationType}, used on the target.
238
+ *
239
+ * @apiNote In the case of repeatable annotations, the first usage for which
240
+ * the passed {@code processor} does not return {@code null} will be returned.
241
+ *
242
+ * @return The matching value or {@code null}
243
+ *
244
+ * @param <T> The type of the value being returned.
245
+ * @param <A> The type of annotations to check
246
+ */
247
+ default <T , A extends Annotation > T fromAnnotations (
248
+ Class <A > annotationType ,
249
+ AnnotationUsageProcessor <T > processor ) {
250
+ final List <AnnotationUsage <A >> annotationUsages = getRepeatedAnnotationUsages ( annotationType );
251
+ for ( AnnotationUsage <A > annotationUsage : annotationUsages ) {
252
+ final T result = processor .process ( annotationUsage );
253
+ if ( result != null ) {
254
+ return result ;
255
+ }
256
+ }
257
+ return null ;
258
+ }
211
259
212
260
/**
213
261
* Subset of {@linkplain ElementType annotation targets} supported for mapping annotations
0 commit comments