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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.ClassFileVersion;
20 import net.bytebuddy.build.CachedReturnPlugin;
21 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
22 import net.bytebuddy.description.enumeration.EnumerationDescription;
23 import net.bytebuddy.description.method.MethodDescription;
24 import net.bytebuddy.description.method.MethodList;
25 import net.bytebuddy.description.type.TypeDescription;
26 import net.bytebuddy.description.type.TypeList;
27 import net.bytebuddy.utility.privilege.SetAccessibleAction;
28
29 import java.lang.annotation.*;
30 import java.lang.reflect.InvocationHandler;
31 import java.lang.reflect.InvocationTargetException;
32 import java.lang.reflect.Method;
33 import java.lang.reflect.Proxy;
34 import java.security.AccessController;
35 import java.util.*;
36
37 import static net.bytebuddy.matcher.ElementMatchers.named;
38
39 /**
40  * An annotation description describes {@link java.lang.annotation.Annotation} meta data of a class without this class
41  * being required to be loaded. All values of an annotation are therefore represented in unloaded state:
42  * <ul>
43  * <li>{@link java.lang.Class} instances are represented as {@link TypeDescription}s.</li>
44  * <li>{@link java.lang.Enum} instances are represented as
45  * {@link net.bytebuddy.description.enumeration.EnumerationDescription}s.</li>
46  * <li>{@link java.lang.annotation.Annotation}s are described as
47  * {@link AnnotationDescription}s.</li>
48  * <li>All primitive types are represented as their wrapper types.</li>
49  * </ul>
50  * An annotation can however be loaded in order to access unwrapped values. This will cause a loading of the classes
51  * of these values.
52  */

53 public interface AnnotationDescription {
54
55     /**
56      * Indicates a nonexistent annotation in a type-safe manner.
57      */

58     AnnotationDescription.Loadable<?> UNDEFINED = null;
59
60     /**
61      * Returns the value of this annotation.
62      *
63      * @param property The property being accessed.
64      * @return The value for the supplied property.
65      */

66     AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property);
67
68     /**
69      * Returns a description of the annotation type of this annotation.
70      *
71      * @return A description of the annotation type of this annotation.
72      */

73     TypeDescription getAnnotationType();
74
75     /**
76      * Links this annotation description to a given annotation type such that it can be loaded. This does not cause
77      * the values of this annotation to be loaded.
78      *
79      * @param annotationType The loaded annotation type of this annotation description.
80      * @param <T>            The type of the annotation.
81      * @return A loadable version of this annotation description.
82      */

83     <T extends Annotation> Loadable<T> prepare(Class<T> annotationType);
84
85     /**
86      * Returns this annotation's retention policy.
87      *
88      * @return This annotation's retention policy.
89      */

90     RetentionPolicy getRetention();
91
92     /**
93      * Returns a set of all {@link ElementType}s that can declare this annotation.
94      *
95      * @return A set of all element types that can declare this annotation.
96      */

97     Set<ElementType> getElementTypes();
98
99     /**
100      * Checks if this annotation is inherited.
101      *
102      * @return {@code trueif this annotation is inherited.
103      * @see Inherited
104      */

105     boolean isInherited();
106
107     /**
108      * Checks if this annotation is documented.
109      *
110      * @return {@code trueif this annotation is documented.
111      * @see Documented
112      */

113     boolean isDocumented();
114
115     /**
116      * An annotation description that is linked to a given loaded annotation type which allows its representation
117      * as a fully loaded instance.
118      *
119      * @param <S> The annotation type.
120      */

121     interface Loadable<S extends Annotation> extends AnnotationDescription {
122
123         /**
124          * Loads this annotation description. This causes all classes referenced by the annotation value to be loaded.
125          * Without specifying a class loader, the annotation's class loader which was used to prepare this instance
126          * is used.
127          *
128          * @return A loaded version of this annotation description.
129          */

130         S load();
131     }
132
133     /**
134      * A rendering dispatcher is responsible for resolving annotation descriptions to {@link String} representations.
135      */

136     enum RenderingDispatcher {
137
138         /**
139          * A rendering dispatcher for any VM previous to Java 14.
140          */

141         LEGACY_VM,
142
143         /**
144          * A rendering dispatcher for Java 14 onward.
145          */

146         JAVA_14_CAPABLE_VM {
147             @Override
148             public void appendPrefix(StringBuilder toString, String key, int count) {
149                 if (count > 1 || !key.equals("value")) {
150                     super.appendPrefix(toString, key, count);
151                 }
152             }
153         };
154
155         /**
156          * The rendering dispatcher for the current VM.
157          */

158         public static final RenderingDispatcher CURRENT;
159
160         /*
161          * Initializes the rendering dispatcher.
162          */

163         static {
164             ClassFileVersion classFileVersion = ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V6);
165             if (classFileVersion.isAtLeast(ClassFileVersion.JAVA_V14)) {
166                 CURRENT = RenderingDispatcher.JAVA_14_CAPABLE_VM;
167             } else {
168                 CURRENT = RenderingDispatcher.LEGACY_VM;
169             }
170         }
171
172         /**
173          * Appends the key property prefix to a string builder representing an annotation's string representation.
174          *
175          * @param toString The {@link Object#toString()} representation of the annotation being handled.
176          * @param key      The key's name.
177          * @param count    The property count.
178          */

179         public void appendPrefix(StringBuilder toString, String key, int count) {
180             toString.append(key).append('=');
181         }
182     }
183
184     /**
185      * An {@link java.lang.reflect.InvocationHandler} for implementing annotations.
186      *
187      * @param <T> The type of the handled annotation.
188      */

189     class AnnotationInvocationHandler<T extends Annotation> implements InvocationHandler {
190
191         /**
192          * The name of the {@link Object#hashCode()} method.
193          */

194         private static final String HASH_CODE = "hashCode";
195
196         /**
197          * The name of the {@link Object#equals(Object)} method.
198          */

199         private static final String EQUALS = "equals";
200
201         /**
202          * The name of the {@link Object#toString()} method.
203          */

204         private static final String TO_STRING = "toString";
205
206         /**
207          * An empty array that can be used to indicate no arguments to avoid an allocation on a reflective call.
208          */

209         private static final Object[] NO_ARGUMENTS = new Object[0];
210
211         /**
212          * The loaded annotation type.
213          */

214         private final Class<? extends Annotation> annotationType;
215
216         /**
217          * A sorted list of values of this annotation.
218          */

219         private final LinkedHashMap<Method, AnnotationValue.Loaded<?>> values;
220
221         /**
222          * Creates a new invocation handler.
223          *
224          * @param annotationType The loaded annotation type.
225          * @param values         A sorted list of values of this annotation.
226          */

227         protected AnnotationInvocationHandler(Class<T> annotationType, LinkedHashMap<Method, AnnotationValue.Loaded<?>> values) {
228             this.annotationType = annotationType;
229             this.values = values;
230         }
231
232         /**
233          * Creates a proxy instance for the supplied annotation type and values.
234          *
235          * @param classLoader    The class loader that should be used for loading the annotation's values.
236          * @param annotationType The annotation's type.
237          * @param values         The values that the annotation contains.
238          * @param <S>            The type of the handled annotation.
239          * @return A proxy for the annotation type and values.
240          */

241         @SuppressWarnings("unchecked")
242         public static <S extends Annotation> S of(ClassLoader classLoader,
243                                                   Class<S> annotationType,
244                                                   Map<String, ? extends AnnotationValue<?, ?>> values) {
245             LinkedHashMap<Method, AnnotationValue.Loaded<?>> loadedValues = new LinkedHashMap<Method, AnnotationValue.Loaded<?>>();
246             for (Method method : annotationType.getDeclaredMethods()) {
247                 AnnotationValue<?, ?> annotationValue = values.get(method.getName());
248                 if (annotationValue == null) {
249                     Object defaultValue = method.getDefaultValue();
250                     loadedValues.put(method, (defaultValue == null
251                             ? new AnnotationValue.ForMissingValue<Void, Void>(new TypeDescription.ForLoadedType(method.getDeclaringClass()), method.getName())
252                             : AnnotationDescription.ForLoadedAnnotation.asValue(defaultValue, method.getReturnType())).load(classLoader));
253                 } else {
254                     loadedValues.put(method, annotationValue.filter(new MethodDescription.ForLoadedMethod(method)).load(classLoader));
255                 }
256             }
257             return (S) Proxy.newProxyInstance(classLoader, new Class<?>[]{annotationType}, new AnnotationInvocationHandler<S>(annotationType, loadedValues));
258         }
259
260         /**
261          * {@inheritDoc}
262          */

263         public Object invoke(Object proxy, Method method, Object[] argument) {
264             if (method.getDeclaringClass() != annotationType) {
265                 if (method.getName().equals(HASH_CODE)) {
266                     return hashCodeRepresentation();
267                 } else if (method.getName().equals(EQUALS) && method.getParameterTypes().length == 1) {
268                     return equalsRepresentation(proxy, argument[0]);
269                 } else if (method.getName().equals(TO_STRING)) {
270                     return toStringRepresentation();
271                 } else /* if (method.getName().equals("annotationType")) */ {
272                     return annotationType;
273                 }
274             }
275             return values.get(method).resolve();
276         }
277
278         /**
279          * Returns the string representation of the represented annotation.
280          *
281          * @return The string representation of the represented annotation.
282          */

283         protected String toStringRepresentation() {
284             StringBuilder toString = new StringBuilder();
285             toString.append('@');
286             toString.append(annotationType.getName());
287             toString.append('(');
288             boolean firstMember = true;
289             for (Map.Entry<Method, AnnotationValue.Loaded<?>> entry : values.entrySet()) {
290                 if (!entry.getValue().getState().isDefined()) {
291                     continue;
292                 }
293                 if (firstMember) {
294                     firstMember = false;
295                 } else {
296                     toString.append(", ");
297                 }
298                 RenderingDispatcher.CURRENT.appendPrefix(toString, entry.getKey().getName(), values.entrySet().size());
299                 toString.append(entry.getValue().toString());
300             }
301             toString.append(')');
302             return toString.toString();
303         }
304
305         /**
306          * Returns the hash code of the represented annotation.
307          *
308          * @return The hash code of the represented annotation.
309          */

310         private int hashCodeRepresentation() {
311             int hashCode = 0;
312             for (Map.Entry<Method, AnnotationValue.Loaded<?>> entry : values.entrySet()) {
313                 if (!entry.getValue().getState().isDefined()) {
314                     continue;
315                 }
316                 hashCode += (127 * entry.getKey().getName().hashCode()) ^ entry.getValue().hashCode();
317             }
318             return hashCode;
319         }
320
321         /**
322          * Checks if another instance is equal to this instance.
323          *
324          * @param self  The annotation proxy instance.
325          * @param other The instance to be examined for equality to the represented instance.
326          * @return {@code trueif the given instance is equal to the represented instance.
327          */

328         private boolean equalsRepresentation(Object self, Object other) {
329             if (self == other) {
330                 return true;
331             } else if (!annotationType.isInstance(other)) {
332                 return false;
333             } else if (Proxy.isProxyClass(other.getClass())) {
334                 InvocationHandler invocationHandler = Proxy.getInvocationHandler(other);
335                 if (invocationHandler instanceof AnnotationInvocationHandler) {
336                     return invocationHandler.equals(this);
337                 }
338             }
339             try {
340                 for (Map.Entry<Method, AnnotationValue.Loaded<?>> entry : values.entrySet()) {
341                     try {
342                         if (!entry.getValue().represents(entry.getKey().invoke(other, NO_ARGUMENTS))) {
343                             return false;
344                         }
345                     } catch (RuntimeException exception) {
346                         return false// Incomplete annotations are not equal to one another.
347                     }
348                 }
349                 return true;
350             } catch (InvocationTargetException ignored) {
351                 return false;
352             } catch (IllegalAccessException exception) {
353                 throw new IllegalStateException("Could not access annotation property", exception);
354             }
355         }
356
357         @Override
358         @CachedReturnPlugin.Enhance
359         public int hashCode() {
360             int result = annotationType.hashCode();
361             result = 31 * result + values.hashCode();
362             for (Map.Entry<Method, ?> entry : values.entrySet()) {
363                 result = 31 * result + entry.getValue().hashCode();
364             }
365             return result;
366         }
367
368         @Override
369         public boolean equals(Object other) {
370             if (this == other) {
371                 return true;
372             } else if (!(other instanceof AnnotationInvocationHandler)) {
373                 return false;
374             }
375             AnnotationInvocationHandler that = (AnnotationInvocationHandler) other;
376             if (!annotationType.equals(that.annotationType)) {
377                 return false;
378             }
379             for (Map.Entry<Method, AnnotationValue.Loaded<?>> entry : values.entrySet()) {
380                 if (!entry.getValue().equals(that.values.get(entry.getKey()))) {
381                     return false;
382                 }
383             }
384             return true;
385         }
386     }
387
388     /**
389      * An adapter implementation of an annotation.
390      */

391     abstract class AbstractBase implements AnnotationDescription {
392
393         /**
394          * An array containing all element types that are a legal annotation target when such a target
395          * is not specified explicitly.
396          */

397         private static final ElementType[] DEFAULT_TARGET = new ElementType[]{ElementType.ANNOTATION_TYPE,
398                 ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD,
399                 ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE};
400
401         /**
402          * {@inheritDoc}
403          */

404         public RetentionPolicy getRetention() {
405             AnnotationDescription.Loadable<Retention> retention = getAnnotationType().getDeclaredAnnotations().ofType(Retention.class);
406             return retention == null
407                     ? RetentionPolicy.CLASS
408                     : retention.load().value();
409         }
410
411         /**
412          * {@inheritDoc}
413          */

414         public Set<ElementType> getElementTypes() {
415             AnnotationDescription.Loadable<Target> target = getAnnotationType().getDeclaredAnnotations().ofType(Target.class);
416             return new HashSet<ElementType>(Arrays.asList(target == null
417                     ? DEFAULT_TARGET
418                     : target.load().value()));
419         }
420
421         /**
422          * {@inheritDoc}
423          */

424         public boolean isInherited() {
425             return getAnnotationType().getDeclaredAnnotations().isAnnotationPresent(Inherited.class);
426         }
427
428         /**
429          * {@inheritDoc}
430          */

431         public boolean isDocumented() {
432             return getAnnotationType().getDeclaredAnnotations().isAnnotationPresent(Documented.class);
433         }
434
435         @Override
436         @CachedReturnPlugin.Enhance
437         public int hashCode() {
438             int hashCode = 0;
439             for (MethodDescription.InDefinedShape methodDescription : getAnnotationType().getDeclaredMethods()) {
440                 hashCode += 31 * getValue(methodDescription).hashCode();
441             }
442             return hashCode;
443         }
444
445         @Override
446         public boolean equals(Object other) {
447             if (this == other) {
448                 return true;
449             } else if (!(other instanceof AnnotationDescription)) {
450                 return false;
451             }
452             AnnotationDescription annotationDescription = ((AnnotationDescription) other);
453             TypeDescription annotationType = getAnnotationType();
454             if (!annotationDescription.getAnnotationType().equals(annotationType)) {
455                 return false;
456             }
457             for (MethodDescription.InDefinedShape methodDescription : annotationType.getDeclaredMethods()) {
458                 if (!getValue(methodDescription).equals(annotationDescription.getValue(methodDescription))) {
459                     return false;
460                 }
461             }
462             return true;
463         }
464
465         @Override
466         public String toString() {
467             TypeDescription annotationType = getAnnotationType();
468             StringBuilder toString = new StringBuilder().append('@').append(annotationType.getName()).append('(');
469             boolean firstMember = true;
470             for (MethodDescription.InDefinedShape methodDescription : annotationType.getDeclaredMethods()) {
471                 AnnotationValue<?, ?> value = getValue(methodDescription);
472                 if (value.getState() == AnnotationValue.State.UNDEFINED) {
473                     continue;
474                 } else if (firstMember) {
475                     firstMember = false;
476                 } else {
477                     toString.append(", ");
478                 }
479                 RenderingDispatcher.CURRENT.appendPrefix(toString, methodDescription.getName(), annotationType.getDeclaredMethods().size());
480                 toString.append(value);
481             }
482             return toString.append(')').toString();
483         }
484     }
485
486     /**
487      * A description of an already loaded annotation.
488      *
489      * @param <S> The type of the annotation.
490      */

491     class ForLoadedAnnotation<S extends Annotation> extends AbstractBase implements Loadable<S> {
492
493         /**
494          * The represented annotation value.
495          */

496         private final S annotation;
497
498         /**
499          * The annotation's loaded type which might be loaded by a different class loader than the value's
500          * annotation type but must be structurally equal to it.
501          */

502         private final Class<S> annotationType;
503
504         /**
505          * Creates a new annotation description for a loaded annotation.
506          *
507          * @param annotation The annotation to represent.
508          */

509         @SuppressWarnings("unchecked")
510         protected ForLoadedAnnotation(S annotation) {
511             this(annotation, (Class<S>) annotation.annotationType());
512         }
513
514         /**
515          * Creates a new annotation description for a loaded annotation.
516          *
517          * @param annotation     The annotation to represent.
518          * @param annotationType The annotation's loaded type which might be loaded by a different class loader than the value's
519          *                       annotation type but must be structurally equal to it.
520          */

521         private ForLoadedAnnotation(S annotation, Class<S> annotationType) {
522             this.annotation = annotation;
523             this.annotationType = annotationType;
524         }
525
526         /**
527          * Creates a description of the given annotation.
528          *
529          * @param annotation The annotation to be described.
530          * @param <U>        The type of the annotation.
531          * @return A description of the given annotation.
532          */

533         public static <U extends Annotation> Loadable<U> of(U annotation) {
534             return new ForLoadedAnnotation<U>(annotation);
535         }
536
537         /**
538          * {@inheritDoc}
539          */

540         public S load() {
541             return annotationType == annotation.annotationType()
542                     ? annotation
543                     : AnnotationInvocationHandler.of(annotationType.getClassLoader(), annotationType, asValue(annotation));
544         }
545
546         /**
547          * Extracts the annotation values of an annotation into a property map.
548          *
549          * @param annotation The annotation to convert.
550          * @return A mapping of property names to their annotation value.
551          */

552         @SuppressWarnings("unchecked")
553         private static Map<String, AnnotationValue<?, ?>> asValue(Annotation annotation) {
554             Map<String, AnnotationValue<?, ?>> annotationValues = new HashMap<String, AnnotationValue<?, ?>>();
555             for (Method property : annotation.annotationType().getDeclaredMethods()) {
556                 try {
557                     annotationValues.put(property.getName(), asValue(property.invoke(annotation), property.getReturnType()));
558                 } catch (InvocationTargetException exception) {
559                     Throwable cause = exception.getCause();
560                     if (cause instanceof TypeNotPresentException) {
561                         annotationValues.put(property.getName(), new AnnotationValue.ForMissingType<Void, Void>(((TypeNotPresentException) cause).typeName()));
562                     } else if (cause instanceof EnumConstantNotPresentException) {
563                         annotationValues.put(property.getName(), new AnnotationValue.ForEnumerationDescription.WithUnknownConstant(
564                                 new TypeDescription.ForLoadedType(((EnumConstantNotPresentException) cause).enumType()),
565                                 ((EnumConstantNotPresentException) cause).constantName()));
566                     } else if (cause instanceof AnnotationTypeMismatchException) {
567                         annotationValues.put(property.getName(), new AnnotationValue.ForMismatchedType<Void, Void>(
568                                 new MethodDescription.ForLoadedMethod(((AnnotationTypeMismatchException) cause).element()),
569                                 ((AnnotationTypeMismatchException) cause).foundType()));
570                     } else if (!(cause instanceof IncompleteAnnotationException)) {
571                         throw new IllegalStateException("Cannot read " + property, exception.getCause());
572                     }
573                 } catch (IllegalAccessException exception) {
574                     throw new IllegalStateException("Cannot access " + property, exception);
575                 }
576             }
577             return annotationValues;
578         }
579
580         /**
581          * Transforms an annotation property to an annotation value.
582          *
583          * @param type  The annotation's type.
584          * @param value The annotations value.
585          * @return An annotation value representation.
586          */

587         @SuppressWarnings("unchecked")
588         public static AnnotationValue<?, ?> asValue(Object value, Class<?> type) {
589             // Because enums can implement annotation interfaces, the enum property needs to be checked first.
590             if (Enum.class.isAssignableFrom(type)) {
591                 return AnnotationValue.ForEnumerationDescription.<Enum>of(new EnumerationDescription.ForLoadedEnumeration((Enum) value));
592             } else if (Enum[].class.isAssignableFrom(type)) {
593                 Enum<?>[] element = (Enum<?>[]) value;
594                 EnumerationDescription[] enumerationDescription = new EnumerationDescription[element.length];
595                 int index = 0;
596                 for (Enum<?> anElement : element) {
597                     enumerationDescription[index++] = new EnumerationDescription.ForLoadedEnumeration(anElement);
598                 }
599                 return AnnotationValue.ForDescriptionArray.<Enum>of(TypeDescription.ForLoadedType.of(type.getComponentType()), enumerationDescription);
600             } else if (Annotation.class.isAssignableFrom(type)) {
601                 return AnnotationValue.ForAnnotationDescription.<Annotation>of(TypeDescription.ForLoadedType.of(type), asValue((Annotation) value));
602             } else if (Annotation[].class.isAssignableFrom(type)) {
603                 Annotation[] element = (Annotation[]) value;
604                 AnnotationDescription[] annotationDescription = new AnnotationDescription[element.length];
605                 int index = 0;
606                 for (Annotation anElement : element) {
607                     annotationDescription[index++] = new AnnotationDescription.Latent(TypeDescription.ForLoadedType.of(type.getComponentType()), asValue(anElement));
608                 }
609                 return AnnotationValue.ForDescriptionArray.of(TypeDescription.ForLoadedType.of(type.getComponentType()), annotationDescription);
610             } else if (Class.class.isAssignableFrom(type)) {
611                 return AnnotationValue.ForTypeDescription.<Class>of(TypeDescription.ForLoadedType.of((Class<?>) value));
612             } else if (Class[].class.isAssignableFrom(type)) {
613                 Class<?>[] element = (Class<?>[]) value;
614                 TypeDescription[] typeDescription = new TypeDescription[element.length];
615                 int index = 0;
616                 for (Class<?> anElement : element) {
617                     typeDescription[index++] = TypeDescription.ForLoadedType.of(anElement);
618                 }
619                 return AnnotationValue.ForDescriptionArray.of(typeDescription);
620             } else {
621                 return AnnotationValue.ForConstant.of(value);
622             }
623         }
624
625         /**
626          * {@inheritDoc}
627          */

628         @SuppressWarnings("deprecation")
629         @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should always be wrapped for clarity")
630         public AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property) {
631             if (!property.getDeclaringType().represents(annotation.annotationType())) {
632                 throw new IllegalArgumentException(property + " does not represent " + annotation.annotationType());
633             }
634             try {
635                 boolean accessible = property.getDeclaringType().isPublic(); // method is required to be public
636                 Method method = property instanceof MethodDescription.ForLoadedMethod
637                         ? ((MethodDescription.ForLoadedMethod) property).getLoadedMethod()
638                         : null;
639                 if (method == null || method.getDeclaringClass() != annotation.annotationType() || (!accessible && !method.isAccessible())) {
640                     method = annotation.annotationType().getMethod(property.getName());
641                     if (!accessible) {
642                         AccessController.doPrivileged(new SetAccessibleAction<Method>(method));
643                     }
644                 }
645                 return asValue(method.invoke(annotation), method.getReturnType()).filter(property);
646             } catch (InvocationTargetException exception) {
647                 Throwable cause = exception.getCause();
648                 if (cause instanceof TypeNotPresentException) {
649                     return new AnnotationValue.ForMissingType<Void, Void>(((TypeNotPresentException) cause).typeName());
650                 } else if (cause instanceof EnumConstantNotPresentException) {
651                     return new AnnotationValue.ForEnumerationDescription.WithUnknownConstant(
652                             new TypeDescription.ForLoadedType(((EnumConstantNotPresentException) cause).enumType()),
653                             ((EnumConstantNotPresentException) cause).constantName());
654                 } else if (cause instanceof AnnotationTypeMismatchException) {
655                     return new AnnotationValue.ForMismatchedType<Void, Void>(
656                             new MethodDescription.ForLoadedMethod(((AnnotationTypeMismatchException) cause).element()),
657                             ((AnnotationTypeMismatchException) cause).foundType());
658                 } else if (cause instanceof IncompleteAnnotationException) {
659                     return new AnnotationValue.ForMissingValue<Void, Void>(
660                             new TypeDescription.ForLoadedType(((IncompleteAnnotationException) cause).annotationType()),
661                             ((IncompleteAnnotationException) cause).elementName());
662                 } else {
663                     throw new IllegalStateException("Error reading annotation property " + property, cause);
664                 }
665             } catch (Exception exception) {
666                 throw new IllegalStateException("Cannot access annotation property " + property, exception);
667             }
668         }
669
670         /**
671          * {@inheritDoc}
672          */

673         @SuppressWarnings("unchecked")
674         public <T extends Annotation> Loadable<T> prepare(Class<T> annotationType) {
675             if (!annotation.annotationType().getName().equals(annotationType.getName())) {
676                 throw new IllegalArgumentException(annotationType + " does not represent " + annotation.annotationType());
677             }
678             return annotationType == annotation.annotationType()
679                     ? (Loadable<T>) this
680                     : new ForLoadedAnnotation<T>((T) annotation, annotationType);
681         }
682
683         /**
684          * {@inheritDoc}
685          */

686         public TypeDescription getAnnotationType() {
687             return TypeDescription.ForLoadedType.of(annotation.annotationType());
688         }
689     }
690
691     /**
692      * A latent description of an annotation value that is defined explicitly.
693      */

694     class Latent extends AbstractBase {
695
696         /**
697          * The type of the annotation.
698          */

699         private final TypeDescription annotationType;
700
701         /**
702          * The values of the annotation mapped by their property name.
703          */

704         private final Map<String, ? extends AnnotationValue<?, ?>> annotationValues;
705
706         /**
707          * Creates a new latent annotation description.
708          *
709          * @param annotationType   The type of the annotation.
710          * @param annotationValues The values of the annotation mapped by their property name.
711          */

712         protected Latent(TypeDescription annotationType, Map<String, ? extends AnnotationValue<?, ?>> annotationValues) {
713             this.annotationType = annotationType;
714             this.annotationValues = annotationValues;
715         }
716
717         /**
718          * {@inheritDoc}
719          */

720         public AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property) {
721             if (!property.getDeclaringType().equals(annotationType)) {
722                 throw new IllegalArgumentException("Not a property of " + annotationType + ": " + property);
723             }
724             AnnotationValue<?, ?> value = annotationValues.get(property.getName());
725             if (value != null) {
726                 return value.filter(property);
727             }
728             AnnotationValue<?, ?> defaultValue = property.getDefaultValue();
729             return defaultValue == null
730                     ? new AnnotationValue.ForMissingValue<Void, Void>(annotationType, property.getName())
731                     : defaultValue;
732         }
733
734         /**
735          * {@inheritDoc}
736          */

737         public TypeDescription getAnnotationType() {
738             return annotationType;
739         }
740
741         /**
742          * {@inheritDoc}
743          */

744         public <T extends Annotation> Loadable<T> prepare(Class<T> annotationType) {
745             if (!this.annotationType.represents(annotationType)) {
746                 throw new IllegalArgumentException(annotationType + " does not represent " + this.annotationType);
747             }
748             return new Loadable<T>(annotationType);
749         }
750
751         /**
752          * A loadable annotation description of a latent annotation description.
753          *
754          * @param <S> The annotation type.
755          */

756         protected class Loadable<S extends Annotation> extends AbstractBase implements AnnotationDescription.Loadable<S> {
757
758             /**
759              * The annotation type.
760              */

761             private final Class<S> annotationType;
762
763             /**
764              * Creates a loadable version of a latent annotation description.
765              *
766              * @param annotationType The annotation type.
767              */

768             protected Loadable(Class<S> annotationType) {
769                 this.annotationType = annotationType;
770             }
771
772             /**
773              * {@inheritDoc}
774              */

775             public S load() {
776                 return AnnotationDescription.AnnotationInvocationHandler.of(annotationType.getClassLoader(), annotationType, annotationValues);
777             }
778
779             /**
780              * {@inheritDoc}
781              */

782             public AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property) {
783                 return Latent.this.getValue(property);
784             }
785
786             /**
787              * {@inheritDoc}
788              */

789             public TypeDescription getAnnotationType() {
790                 return TypeDescription.ForLoadedType.of(annotationType);
791             }
792
793             /**
794              * {@inheritDoc}
795              */

796             public <T extends Annotation> Loadable<T> prepare(Class<T> annotationType) {
797                 return Latent.this.prepare(annotationType);
798             }
799         }
800     }
801
802     /**
803      * A builder for pragmatically creating {@link net.bytebuddy.description.annotation.AnnotationDescription}.
804      */

805     @HashCodeAndEqualsPlugin.Enhance
806     class Builder {
807
808         /**
809          * The annotation type.
810          */

811         private final TypeDescription annotationType;
812
813         /**
814          * A mapping of annotation properties to their annotation values.
815          */

816         private final Map<String, AnnotationValue<?, ?>> annotationValues;
817
818         /**
819          * Creates a builder for an annotation description.
820          *
821          * @param annotationType   The annotation type.
822          * @param annotationValues A mapping of annotation properties to their annotation values.
823          */

824         protected Builder(TypeDescription annotationType, Map<String, AnnotationValue<?, ?>> annotationValues) {
825             this.annotationType = annotationType;
826             this.annotationValues = annotationValues;
827         }
828
829         /**
830          * Creates a builder for creating an annotation of the given type.
831          *
832          * @param annotationType The annotation type.
833          * @return A builder for creating an annotation of the given type.
834          */

835         public static Builder ofType(Class<? extends Annotation> annotationType) {
836             return ofType(TypeDescription.ForLoadedType.of(annotationType));
837         }
838
839         /**
840          * Creates a builder for creating an annotation of the given type.
841          *
842          * @param annotationType A description of the annotation type.
843          * @return A builder for creating an annotation of the given type.
844          */

845         public static Builder ofType(TypeDescription annotationType) {
846             if (!annotationType.isAnnotation()) {
847                 throw new IllegalArgumentException("Not an annotation type: " + annotationType);
848             }
849             return new Builder(annotationType, Collections.<String, AnnotationValue<?, ?>>emptyMap());
850         }
851
852         /**
853          * Returns a builder with the additional, given property.
854          *
855          * @param property The name of the property to define.
856          * @param value    An explicit description of the annotation value.
857          * @return A builder with the additional, given property.
858          */

859         public Builder define(String property, AnnotationValue<?, ?> value) {
860             MethodList<MethodDescription.InDefinedShape> methodDescriptions = annotationType.getDeclaredMethods().filter(named(property));
861             if (methodDescriptions.isEmpty()) {
862                 throw new IllegalArgumentException(annotationType + " does not define a property named " + property);
863             }
864             Map<String, AnnotationValue<?, ?>> annotationValues = new HashMap<String, AnnotationValue<?, ?>>(this.annotationValues);
865             if (annotationValues.put(methodDescriptions.getOnly().getName(), value) != null) {
866                 throw new IllegalArgumentException("Property already defined: " + property);
867             }
868             return new Builder(annotationType, annotationValues);
869         }
870
871         /**
872          * Returns a builder with the additional enumeration property.
873          *
874          * @param property The name of the property to define.
875          * @param value    The enumeration value to define.
876          * @return A builder with the additional enumeration property.
877          */

878         public Builder define(String property, Enum<?> value) {
879             return define(property, new EnumerationDescription.ForLoadedEnumeration(value));
880         }
881
882         /**
883          * Returns a builder with the additional enumeration property.
884          *
885          * @param property        The name of the property to define.
886          * @param enumerationType The type of the enumeration.
887          * @param value           The enumeration value to define.
888          * @return A builder with the additional enumeration property.
889          */

890         public Builder define(String property, TypeDescription enumerationType, String value) {
891             return define(property, new EnumerationDescription.Latent(enumerationType, value));
892         }
893
894         /**
895          * Returns a builder with the additional enumeration property.
896          *
897          * @param property The name of the property to define.
898          * @param value    A description of the enumeration value to define.
899          * @return A builder with the additional enumeration property.
900          */

901         @SuppressWarnings("unchecked")
902         public Builder define(String property, EnumerationDescription value) {
903             return define(property, AnnotationValue.ForEnumerationDescription.<Enum>of(value));
904         }
905
906         /**
907          * Returns a builder with the additional annotation property.
908          *
909          * @param property   The name of the property to define.
910          * @param annotation The annotation value to define.
911          * @return A builder with the additional annotation property.
912          */

913         public Builder define(String property, Annotation annotation) {
914             return define(property, new ForLoadedAnnotation<Annotation>(annotation));
915         }
916
917         /**
918          * Returns a builder with the additional annotation property.
919          *
920          * @param property              The name of the property to define.
921          * @param annotationDescription A description of the annotation value to define.
922          * @return A builder with the additional annotation property.
923          */

924         public Builder define(String property, AnnotationDescription annotationDescription) {
925             return define(property, new AnnotationValue.ForAnnotationDescription<Annotation>(annotationDescription));
926         }
927
928         /**
929          * Returns a builder with the additional class property.
930          *
931          * @param property The name of the property to define.
932          * @param type     The class value to define.
933          * @return A builder with the additional class property.
934          */

935         public Builder define(String property, Class<?> type) {
936             return define(property, TypeDescription.ForLoadedType.of(type));
937         }
938
939         /**
940          * Returns a builder with the additional class property.
941          *
942          * @param property        The name of the property to define.
943          * @param typeDescription A description of the type to define as a property value.
944          * @return A builder with the additional class property.
945          */

946         @SuppressWarnings("unchecked")
947         public Builder define(String property, TypeDescription typeDescription) {
948             return define(property, AnnotationValue.ForTypeDescription.<Class>of(typeDescription));
949         }
950
951         /**
952          * Returns a builder with the additional enumeration array property.
953          *
954          * @param property        The name of the property to define.
955          * @param enumerationType The type of the enumeration, i.e. the component type of the enumeration array.
956          * @param value           The enumeration values to be contained by the array.
957          * @param <T>             The enumeration type.
958          * @return A builder with the additional class property.
959          */

960         @SuppressWarnings("unchecked")
961         public <T extends Enum<?>> Builder defineEnumerationArray(String property, Class<T> enumerationType, T... value) {
962             EnumerationDescription[] enumerationDescription = new EnumerationDescription[value.length];
963             int index = 0;
964             for (T aValue : value) {
965                 enumerationDescription[index++] = new EnumerationDescription.ForLoadedEnumeration(aValue);
966             }
967             return defineEnumerationArray(property, TypeDescription.ForLoadedType.of(enumerationType), enumerationDescription);
968         }
969
970         /**
971          * Returns a builder with the additional enumeration array property.
972          *
973          * @param property        The name of the property to define.
974          * @param enumerationType The type of the enumerations, i.e. is the component type of the enumeration array.
975          * @param value           The enumeration values to be contained by the array.
976          * @return A builder with the additional enumeration property.
977          */

978         public Builder defineEnumerationArray(String property, TypeDescription enumerationType, String... value) {
979             if (!enumerationType.isEnum()) {
980                 throw new IllegalArgumentException("Not an enumeration type: " + enumerationType);
981             }
982             EnumerationDescription[] enumerationDescription = new EnumerationDescription[value.length];
983             for (int i = 0; i < value.length; i++) {
984                 enumerationDescription[i] = new EnumerationDescription.Latent(enumerationType, value[i]);
985             }
986             return defineEnumerationArray(property, enumerationType, enumerationDescription);
987         }
988
989         /**
990          * Returns a builder with the additional enumeration array property.
991          *
992          * @param property        The name of the property to define.
993          * @param enumerationType The type of the enumerations, i.e. the component type of the enumeration array.
994          * @param value           Descriptions of the enumerations to be contained by the array.
995          * @return A builder with the additional enumeration property.
996          */

997         @SuppressWarnings("unchecked")
998         public Builder defineEnumerationArray(String property, TypeDescription enumerationType, EnumerationDescription... value) {
999             return define(property, AnnotationValue.ForDescriptionArray.<Enum>of(enumerationType, value));
1000         }
1001
1002         /**
1003          * Returns a builder with the additional annotation array property.
1004          *
1005          * @param property       The name of the property to define.
1006          * @param annotationType The type of the annotations, i.e. the component type of the enumeration array.
1007          * @param annotation     The annotation values to be contained by the array.
1008          * @param <T>            The annotation type.
1009          * @return A builder with the additional annotation property.
1010          */

1011         @SuppressWarnings("unchecked")
1012         public <T extends Annotation> Builder defineAnnotationArray(String property, Class<T> annotationType, T... annotation) {
1013             return defineAnnotationArray(property,
1014                     TypeDescription.ForLoadedType.of(annotationType),
1015                     new AnnotationList.ForLoadedAnnotations(annotation).toArray(new AnnotationDescription[0]));
1016         }
1017
1018         /**
1019          * Returns a builder with the additional annotation array property.
1020          *
1021          * @param property              The name of the property to define.
1022          * @param annotationType        The type of the annotations, i.e. the component type of the enumeration array.
1023          * @param annotationDescription Descriptions of the annotation values to be contained by the array.
1024          * @return A builder with the additional annotation property.
1025          */

1026         public Builder defineAnnotationArray(String property, TypeDescription annotationType, AnnotationDescription... annotationDescription) {
1027             return define(property, AnnotationValue.ForDescriptionArray.of(annotationType, annotationDescription));
1028         }
1029
1030         /**
1031          * Returns a builder with the additional type array property.
1032          *
1033          * @param property The name of the property to define.
1034          * @param type     The types that should be contained by the array.
1035          * @return A builder with the additional type array property.
1036          */

1037         public Builder defineTypeArray(String property, Class<?>... type) {
1038             return defineTypeArray(property, new TypeList.ForLoadedTypes(type).toArray(new TypeDescription[0]));
1039         }
1040
1041         /**
1042          * Returns a builder with the additional type array property.
1043          *
1044          * @param property        The name of the property to define.
1045          * @param typeDescription Descriptions of the types that should be contained by the array.
1046          * @return A builder with the additional type array property.
1047          */

1048         public Builder defineTypeArray(String property, TypeDescription... typeDescription) {
1049             return define(property, AnnotationValue.ForDescriptionArray.of(typeDescription));
1050         }
1051
1052         /**
1053          * Returns a builder with the additional {@code boolean} property.
1054          *
1055          * @param property The name of the property to define.
1056          * @param value    The {@code boolean} value to define for the property.
1057          * @return A builder with the additional {@code boolean} property.
1058          */

1059         public Builder define(String property, boolean value) {
1060             return define(property, AnnotationValue.ForConstant.of(value));
1061         }
1062
1063         /**
1064          * Returns a builder with the additional {@code byte} property.
1065          *
1066          * @param property The name of the property to define.
1067          * @param value    The {@code byte} value to define for the property.
1068          * @return A builder with the additional {@code byte} property.
1069          */

1070         public Builder define(String property, byte value) {
1071             return define(property, AnnotationValue.ForConstant.of(value));
1072         }
1073
1074         /**
1075          * Returns a builder with the additional {@code char} property.
1076          *
1077          * @param property The name of the property to define.
1078          * @param value    The {@code char} value to define for the property.
1079          * @return A builder with the additional {@code char} property.
1080          */

1081         public Builder define(String property, char value) {
1082             return define(property, AnnotationValue.ForConstant.of(value));
1083         }
1084
1085         /**
1086          * Returns a builder with the additional {@code short} property.
1087          *
1088          * @param property The name of the property to define.
1089          * @param value    The {@code short} value to define for the property.
1090          * @return A builder with the additional {@code short} property.
1091          */

1092         public Builder define(String property, short value) {
1093             return define(property, AnnotationValue.ForConstant.of(value));
1094         }
1095
1096         /**
1097          * Returns a builder with the additional {@code int} property.
1098          *
1099          * @param property The name of the property to define.
1100          * @param value    The {@code int} value to define for the property.
1101          * @return A builder with the additional {@code int} property.
1102          */

1103         public Builder define(String property, int value) {
1104             return define(property, AnnotationValue.ForConstant.of(value));
1105         }
1106
1107         /**
1108          * Returns a builder with the additional {@code long} property.
1109          *
1110          * @param property The name of the property to define.
1111          * @param value    The {@code long} value to define for the property.
1112          * @return A builder with the additional {@code long} property.
1113          */

1114         public Builder define(String property, long value) {
1115             return define(property, AnnotationValue.ForConstant.of(value));
1116         }
1117
1118         /**
1119          * Returns a builder with the additional {@code float} property.
1120          *
1121          * @param property The name of the property to define.
1122          * @param value    The {@code float} value to define for the property.
1123          * @return A builder with the additional {@code float} property.
1124          */

1125         public Builder define(String property, float value) {
1126             return define(property, AnnotationValue.ForConstant.of(value));
1127         }
1128
1129         /**
1130          * Returns a builder with the additional {@code double} property.
1131          *
1132          * @param property The name of the property to define.
1133          * @param value    The {@code double} value to define for the property.
1134          * @return A builder with the additional {@code double} property.
1135          */

1136         public Builder define(String property, double value) {
1137             return define(property, AnnotationValue.ForConstant.of(value));
1138         }
1139
1140         /**
1141          * Returns a builder with the additional {@link java.lang.String} property.
1142          *
1143          * @param property The name of the property to define.
1144          * @param value    The {@link java.lang.String} value to define for the property.
1145          * @return A builder with the additional {@link java.lang.String} property.
1146          */

1147         public Builder define(String property, String value) {
1148             return define(property, AnnotationValue.ForConstant.of(value));
1149         }
1150
1151         /**
1152          * Returns a builder with the additional {@code boolean} array property.
1153          *
1154          * @param property The name of the property to define.
1155          * @param value    The {@code boolean} values to define for the property.
1156          * @return A builder with the additional {@code boolean} array property.
1157          */

1158         public Builder defineArray(String property, boolean... value) {
1159             return define(property, AnnotationValue.ForConstant.of(value));
1160         }
1161
1162         /**
1163          * Returns a builder with the additional {@code byte} array property.
1164          *
1165          * @param property The name of the property to define.
1166          * @param value    The {@code byte} values to define for the property.
1167          * @return A builder with the additional {@code byte} array property.
1168          */

1169         public Builder defineArray(String property, byte... value) {
1170             return define(property, AnnotationValue.ForConstant.of(value));
1171         }
1172
1173         /**
1174          * Returns a builder with the additional {@code char} array property.
1175          *
1176          * @param property The name of the property to define.
1177          * @param value    The {@code char} values to define for the property.
1178          * @return A builder with the additional {@code char} array property.
1179          */

1180         public Builder defineArray(String property, char... value) {
1181             return define(property, AnnotationValue.ForConstant.of(value));
1182         }
1183
1184         /**
1185          * Returns a builder with the additional {@code short} array property.
1186          *
1187          * @param property The name of the property to define.
1188          * @param value    The {@code short} values to define for the property.
1189          * @return A builder with the additional {@code short} array property.
1190          */

1191         public Builder defineArray(String property, short... value) {
1192             return define(property, AnnotationValue.ForConstant.of(value));
1193         }
1194
1195         /**
1196          * Returns a builder with the additional {@code int} array property.
1197          *
1198          * @param property The name of the property to define.
1199          * @param value    The {@code int} values to define for the property.
1200          * @return A builder with the additional {@code int} array property.
1201          */

1202         public Builder defineArray(String property, int... value) {
1203             return define(property, AnnotationValue.ForConstant.of(value));
1204         }
1205
1206         /**
1207          * Returns a builder with the additional {@code long} array property.
1208          *
1209          * @param property The name of the property to define.
1210          * @param value    The {@code long} values to define for the property.
1211          * @return A builder with the additional {@code long} array property.
1212          */

1213         public Builder defineArray(String property, long... value) {
1214             return define(property, AnnotationValue.ForConstant.of(value));
1215         }
1216
1217         /**
1218          * Returns a builder with the additional {@code float} array property.
1219          *
1220          * @param property The name of the property to define.
1221          * @param value    The {@code float} values to define for the property.
1222          * @return A builder with the additional {@code float} array property.
1223          */

1224         public Builder defineArray(String property, float... value) {
1225             return define(property, AnnotationValue.ForConstant.of(value));
1226         }
1227
1228         /**
1229          * Returns a builder with the additional {@code double} array property.
1230          *
1231          * @param property The name of the property to define.
1232          * @param value    The {@code double} values to define for the property.
1233          * @return A builder with the additional {@code double} array property.
1234          */

1235         public Builder defineArray(String property, double... value) {
1236             return define(property, AnnotationValue.ForConstant.of(value));
1237         }
1238
1239         /**
1240          * Returns a builder with the additional {@link java.lang.String} array property.
1241          *
1242          * @param property The name of the property to define.
1243          * @param value    The {@link java.lang.String} array value to define for the property.
1244          * @return A builder with the additional {@link java.lang.String} array property.
1245          */

1246         public Builder defineArray(String property, String... value) {
1247             return define(property, AnnotationValue.ForConstant.of(value));
1248         }
1249
1250         /**
1251          * Creates an annotation description for the values that were defined for this builder. It is validated that all
1252          * properties are defined if no default value is set for an annotation property.
1253          *
1254          * @return An appropriate annotation description.
1255          */

1256         public AnnotationDescription build() {
1257             for (MethodDescription.InDefinedShape methodDescription : annotationType.getDeclaredMethods()) {
1258                 AnnotationValue<?, ?> annotationValue = annotationValues.get(methodDescription.getName());
1259                 if (annotationValue == null && methodDescription.getDefaultValue() == null) {
1260                     throw new IllegalStateException("No value or default value defined for " + methodDescription.getName());
1261                 } else if (annotationValue != null && annotationValue.filter(methodDescription).getState() != AnnotationValue.State.RESOLVED) {
1262                     throw new IllegalStateException("Illegal annotation value for " + methodDescription + ": " + annotationValue);
1263                 }
1264             }
1265             return new Latent(annotationType, annotationValues);
1266         }
1267
1268         /**
1269          * Creates an annotation description for the values that were defined for this builder.
1270          *
1271          * @param validated {@code trueif the annotation description should be validated for having included all values.
1272          * @return An appropriate annotation description.
1273          */

1274         public AnnotationDescription build(boolean validated) {
1275             return validated
1276                     ? build()
1277                     : new Latent(annotationType, annotationValues);
1278         }
1279     }
1280 }
1281