1 /*
2 * Copyright 2014 - 2020 Rafael Winterhalter
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.bytebuddy.description.annotation;
17
18 import net.bytebuddy.description.type.TypeDescription;
19 import net.bytebuddy.description.type.TypeList;
20 import net.bytebuddy.matcher.ElementMatcher;
21 import net.bytebuddy.matcher.FilterableList;
22
23 import java.lang.annotation.Annotation;
24 import java.lang.annotation.RetentionPolicy;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.Set;
29
30 /**
31 * Defines a list of annotation instances.
32 */
33 public interface AnnotationList extends FilterableList<AnnotationDescription, AnnotationList> {
34
35 /**
36 * Checks if this list contains an annotation of the given type.
37 *
38 * @param annotationType The type to find in the list.
39 * @return {@code true} if the list contains the annotation type.
40 */
41 boolean isAnnotationPresent(Class<? extends Annotation> annotationType);
42
43 /**
44 * Checks if this list contains an annotation of the given type.
45 *
46 * @param annotationType The type to find in the list.
47 * @return {@code true} if the list contains the annotation type.
48 */
49 boolean isAnnotationPresent(TypeDescription annotationType);
50
51 /**
52 * Finds the first annotation of the given type and returns it.
53 *
54 * @param annotationType The type to be found in the list.
55 * @param <T> The annotation type.
56 * @return The annotation description or {@code null} if no such annotation was found.
57 */
58 <T extends Annotation> AnnotationDescription.Loadable<T> ofType(Class<T> annotationType);
59
60 /**
61 * Finds the first annotation of the given type and returns it.
62 *
63 * @param annotationType The type to be found in the list.
64 * @return The annotation description or {@code null} if no such annotation was found.
65 */
66 AnnotationDescription ofType(TypeDescription annotationType);
67
68 /**
69 * Returns only annotations that are marked as {@link java.lang.annotation.Inherited} as long as they are not
70 * contained by the set of ignored annotation types.
71 *
72 * @param ignoredTypes A list of annotation types to be ignored from the lookup.
73 * @return A list of all inherited annotations besides of the given ignored types.
74 */
75 AnnotationList inherited(Set<? extends TypeDescription> ignoredTypes);
76
77 /**
78 * Only retains annotations with the given retention policy.
79 *
80 * @param matcher A matcher for the required retention policy.
81 * @return A of annotations only with elements
82 */
83 AnnotationList visibility(ElementMatcher<? super RetentionPolicy> matcher);
84
85 /**
86 * Returns a list of the annotation types of this list.
87 *
88 * @return A list of the annotation types of this list.
89 */
90 TypeList asTypeList();
91
92 /**
93 * An abstract base implementation of an annotation list.
94 */
95 abstract class AbstractBase extends FilterableList.AbstractBase<AnnotationDescription, AnnotationList> implements AnnotationList {
96
97 /**
98 * {@inheritDoc}
99 */
100 public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
101 for (AnnotationDescription annotation : this) {
102 if (annotation.getAnnotationType().represents(annotationType)) {
103 return true;
104 }
105 }
106 return false;
107 }
108
109 /**
110 * {@inheritDoc}
111 */
112 public boolean isAnnotationPresent(TypeDescription annotationType) {
113 for (AnnotationDescription annotation : this) {
114 if (annotation.getAnnotationType().equals(annotationType)) {
115 return true;
116 }
117 }
118 return false;
119 }
120
121 /**
122 * {@inheritDoc}
123 */
124 @SuppressWarnings("unchecked")
125 public <T extends Annotation> AnnotationDescription.Loadable<T> ofType(Class<T> annotationType) {
126 for (AnnotationDescription annotation : this) {
127 if (annotation.getAnnotationType().represents(annotationType)) {
128 return annotation.prepare(annotationType);
129 }
130 }
131 return (AnnotationDescription.Loadable<T>) AnnotationDescription.UNDEFINED;
132 }
133
134 /**
135 * {@inheritDoc}
136 */
137 public AnnotationDescription ofType(TypeDescription annotationType) {
138 for (AnnotationDescription annotation : this) {
139 if (annotation.getAnnotationType().equals(annotationType)) {
140 return annotation;
141 }
142 }
143 return AnnotationDescription.UNDEFINED;
144 }
145
146 /**
147 * {@inheritDoc}
148 */
149 public AnnotationList inherited(Set<? extends TypeDescription> ignoredTypes) {
150 List<AnnotationDescription> inherited = new ArrayList<AnnotationDescription>(size());
151 for (AnnotationDescription annotation : this) {
152 if (!ignoredTypes.contains(annotation.getAnnotationType()) && annotation.isInherited()) {
153 inherited.add(annotation);
154 }
155 }
156 return wrap(inherited);
157 }
158
159 /**
160 * {@inheritDoc}
161 */
162 public AnnotationList visibility(ElementMatcher<? super RetentionPolicy> matcher) {
163 List<AnnotationDescription> annotationDescriptions = new ArrayList<AnnotationDescription>(size());
164 for (AnnotationDescription annotation : this) {
165 if (matcher.matches(annotation.getRetention())) {
166 annotationDescriptions.add(annotation);
167 }
168 }
169 return wrap(annotationDescriptions);
170 }
171
172 /**
173 * {@inheritDoc}
174 */
175 public TypeList asTypeList() {
176 List<TypeDescription> annotationTypes = new ArrayList<TypeDescription>(size());
177 for (AnnotationDescription annotation : this) {
178 annotationTypes.add(annotation.getAnnotationType());
179 }
180 return new TypeList.Explicit(annotationTypes);
181 }
182
183 @Override
184 protected AnnotationList wrap(List<AnnotationDescription> values) {
185 return new Explicit(values);
186 }
187 }
188
189 /**
190 * Describes an array of loaded {@link java.lang.annotation.Annotation}s as an annotation list.
191 */
192 class ForLoadedAnnotations extends AbstractBase {
193
194 /**
195 * The represented annotations.
196 */
197 private final List<? extends Annotation> annotations;
198
199 /**
200 * Creates a new list of loaded annotations.
201 *
202 * @param annotation The represented annotations.
203 */
204 public ForLoadedAnnotations(Annotation... annotation) {
205 this(Arrays.asList(annotation));
206 }
207
208 /**
209 * Creates a new list of loaded annotations.
210 *
211 * @param annotations The represented annotations.
212 */
213 public ForLoadedAnnotations(List<? extends Annotation> annotations) {
214 this.annotations = annotations;
215 }
216
217 /**
218 * Creates a list of annotation lists representing the given loaded annotations.
219 *
220 * @param annotations The annotations to represent where each dimension is converted into a list.
221 * @return A list of annotation lists representing the given annotations.
222 */
223 public static List<AnnotationList> asList(Annotation[][] annotations) {
224 List<AnnotationList> result = new ArrayList<AnnotationList>(annotations.length);
225 for (Annotation[] annotation : annotations) {
226 result.add(new ForLoadedAnnotations(annotation));
227 }
228 return result;
229 }
230
231 /**
232 * {@inheritDoc}
233 */
234 public AnnotationDescription get(int index) {
235 return AnnotationDescription.ForLoadedAnnotation.of(annotations.get(index));
236 }
237
238 /**
239 * {@inheritDoc}
240 */
241 public int size() {
242 return annotations.size();
243 }
244 }
245
246 /**
247 * Represents a list of explicitly provided annotation descriptions.
248 */
249 class Explicit extends AbstractBase {
250
251 /**
252 * The list of represented annotation descriptions.
253 */
254 private final List<? extends AnnotationDescription> annotationDescriptions;
255
256 /**
257 * Creates a new list of annotation descriptions.
258 *
259 * @param annotationDescription The list of represented annotation descriptions.
260 */
261 public Explicit(AnnotationDescription... annotationDescription) {
262 this(Arrays.asList(annotationDescription));
263 }
264
265 /**
266 * Creates a new list of annotation descriptions.
267 *
268 * @param annotationDescriptions The list of represented annotation descriptions.
269 */
270 public Explicit(List<? extends AnnotationDescription> annotationDescriptions) {
271 this.annotationDescriptions = annotationDescriptions;
272 }
273
274 /**
275 * Creates a list of annotation lists for a given multidimensional list of annotation descriptions.
276 *
277 * @param annotations The list of annotations to represent as a list of annotation lists.
278 * @return The list of annotation lists.
279 */
280 public static List<AnnotationList> asList(List<? extends List<? extends AnnotationDescription>> annotations) {
281 List<AnnotationList> result = new ArrayList<AnnotationList>(annotations.size());
282 for (List<? extends AnnotationDescription> annotation : annotations) {
283 result.add(new Explicit(annotation));
284 }
285 return result;
286 }
287
288 /**
289 * {@inheritDoc}
290 */
291 public AnnotationDescription get(int index) {
292 return annotationDescriptions.get(index);
293 }
294
295 /**
296 * {@inheritDoc}
297 */
298 public int size() {
299 return annotationDescriptions.size();
300 }
301 }
302
303 /**
304 * Represents an empty annotation list.
305 */
306 class Empty extends FilterableList.Empty<AnnotationDescription, AnnotationList> implements AnnotationList {
307
308 /**
309 * Creates a list of empty annotation lists of the given dimension.
310 *
311 * @param length The length of the list.
312 * @return A list of empty annotation lists of the given length.
313 */
314 public static List<AnnotationList> asList(int length) {
315 List<AnnotationList> result = new ArrayList<AnnotationList>(length);
316 for (int i = 0; i < length; i++) {
317 result.add(new AnnotationList.Empty());
318 }
319 return result;
320 }
321
322 /**
323 * {@inheritDoc}
324 */
325 public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
326 return false;
327 }
328
329 /**
330 * {@inheritDoc}
331 */
332 public boolean isAnnotationPresent(TypeDescription annotationType) {
333 return false;
334 }
335
336 /**
337 * {@inheritDoc}
338 */
339 @SuppressWarnings("unchecked")
340 public <T extends Annotation> AnnotationDescription.Loadable<T> ofType(Class<T> annotationType) {
341 return (AnnotationDescription.Loadable<T>) AnnotationDescription.UNDEFINED;
342 }
343
344 /**
345 * {@inheritDoc}
346 */
347 public AnnotationDescription ofType(TypeDescription annotationType) {
348 return AnnotationDescription.UNDEFINED;
349 }
350
351 /**
352 * {@inheritDoc}
353 */
354 public AnnotationList inherited(Set<? extends TypeDescription> ignoredTypes) {
355 return this;
356 }
357
358 /**
359 * {@inheritDoc}
360 */
361 public AnnotationList visibility(ElementMatcher<? super RetentionPolicy> matcher) {
362 return this;
363 }
364
365 /**
366 * {@inheritDoc}
367 */
368 public TypeList asTypeList() {
369 return new TypeList.Empty();
370 }
371 }
372 }
373