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 trueif 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 trueif 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 nullif 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 nullif 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