/*
 * Copyright 2014 - 2019 Rafael Winterhalter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.bytebuddy.description.annotation;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
import net.bytebuddy.description.enumeration.EnumerationDescription;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.description.type.TypeList;
import net.bytebuddy.utility.privilege.SetAccessibleAction;

import java.lang.annotation.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.util.*;

import static net.bytebuddy.matcher.ElementMatchers.named;

An annotation description describes Annotation meta data of a class without this class being required to be loaded. All values of an annotation are therefore represented in unloaded state: An annotation can however be loaded in order to access unwrapped values. This will cause a loading of the classes of these values.
/** * An annotation description describes {@link java.lang.annotation.Annotation} meta data of a class without this class * being required to be loaded. All values of an annotation are therefore represented in unloaded state: * <ul> * <li>{@link java.lang.Class} instances are represented as {@link TypeDescription}s.</li> * <li>{@link java.lang.Enum} instances are represented as * {@link net.bytebuddy.description.enumeration.EnumerationDescription}s.</li> * <li>{@link java.lang.annotation.Annotation}s are described as * {@link AnnotationDescription}s.</li> * <li>All primitive types are represented as their wrapper types.</li> * </ul> * An annotation can however be loaded in order to access unwrapped values. This will cause a loading of the classes * of these values. */
public interface AnnotationDescription {
Indicates a nonexistent annotation in a type-safe manner.
/** * Indicates a nonexistent annotation in a type-safe manner. */
AnnotationDescription.Loadable<?> UNDEFINED = null;
Returns the value of this annotation.
Params:
  • property – The property being accessed.
Returns:The value for the supplied property.
/** * Returns the value of this annotation. * * @param property The property being accessed. * @return The value for the supplied property. */
AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property);
Returns a description of the annotation type of this annotation.
Returns:A description of the annotation type of this annotation.
/** * Returns a description of the annotation type of this annotation. * * @return A description of the annotation type of this annotation. */
TypeDescription getAnnotationType();
Links this annotation description to a given annotation type such that it can be loaded. This does not cause the values of this annotation to be loaded.
Params:
  • annotationType – The loaded annotation type of this annotation description.
Type parameters:
  • <T> – The type of the annotation.
Returns:A loadable version of this annotation description.
/** * Links this annotation description to a given annotation type such that it can be loaded. This does not cause * the values of this annotation to be loaded. * * @param annotationType The loaded annotation type of this annotation description. * @param <T> The type of the annotation. * @return A loadable version of this annotation description. */
<T extends Annotation> Loadable<T> prepare(Class<T> annotationType);
Returns this annotation's retention policy.
Returns:This annotation's retention policy.
/** * Returns this annotation's retention policy. * * @return This annotation's retention policy. */
RetentionPolicy getRetention();
Returns a set of all ElementTypes that can declare this annotation.
Returns:A set of all element types that can declare this annotation.
/** * Returns a set of all {@link ElementType}s that can declare this annotation. * * @return A set of all element types that can declare this annotation. */
Set<ElementType> getElementTypes();
Checks if this annotation is inherited.
See Also:
Returns:true if this annotation is inherited.
/** * Checks if this annotation is inherited. * * @return {@code true} if this annotation is inherited. * @see Inherited */
boolean isInherited();
Checks if this annotation is documented.
See Also:
Returns:true if this annotation is documented.
/** * Checks if this annotation is documented. * * @return {@code true} if this annotation is documented. * @see Documented */
boolean isDocumented();
An annotation description that is linked to a given loaded annotation type which allows its representation as a fully loaded instance.
Type parameters:
  • <S> – The annotation type.
/** * An annotation description that is linked to a given loaded annotation type which allows its representation * as a fully loaded instance. * * @param <S> The annotation type. */
interface Loadable<S extends Annotation> extends AnnotationDescription {
Loads this annotation description. This causes all classes referenced by the annotation value to be loaded. Without specifying a class loader, the annotation's class loader which was used to prepare this instance is used.
Throws:
Returns:A loaded version of this annotation description.
/** * Loads this annotation description. This causes all classes referenced by the annotation value to be loaded. * Without specifying a class loader, the annotation's class loader which was used to prepare this instance * is used. * * @return A loaded version of this annotation description. * @throws java.lang.ClassNotFoundException If any linked classes of the annotation cannot be loaded. */
S load() throws ClassNotFoundException;
Loads this annotation description. This causes all classes referenced by the annotation value to be loaded. Without specifying a class loader, the annotation's class loader which was used to prepare this instance is used. Any ClassNotFoundException is wrapped in an IllegalStateException.
Returns:A loaded version of this annotation description.
/** * Loads this annotation description. This causes all classes referenced by the annotation value to be loaded. * Without specifying a class loader, the annotation's class loader which was used to prepare this instance * is used. Any {@link java.lang.ClassNotFoundException} is wrapped in an {@link java.lang.IllegalStateException}. * * @return A loaded version of this annotation description. */
S loadSilent(); }
An InvocationHandler for implementing annotations.
Type parameters:
  • <T> – The type of the handled annotation.
/** * An {@link java.lang.reflect.InvocationHandler} for implementing annotations. * * @param <T> The type of the handled annotation. */
class AnnotationInvocationHandler<T extends Annotation> implements InvocationHandler {
The name of the Object.hashCode() method.
/** * The name of the {@link Object#hashCode()} method. */
private static final String HASH_CODE = "hashCode";
The name of the Object.equals(Object) method.
/** * The name of the {@link Object#equals(Object)} method. */
private static final String EQUALS = "equals";
The name of the Object.toString() method.
/** * The name of the {@link Object#toString()} method. */
private static final String TO_STRING = "toString";
An empty array that can be used to indicate no arguments to avoid an allocation on a reflective call.
/** * An empty array that can be used to indicate no arguments to avoid an allocation on a reflective call. */
private static final Object[] NO_ARGUMENTS = new Object[0];
The loaded annotation type.
/** * The loaded annotation type. */
private final Class<? extends Annotation> annotationType;
A sorted list of values of this annotation.
/** * A sorted list of values of this annotation. */
private final LinkedHashMap<Method, AnnotationValue.Loaded<?>> values;
Creates a new invocation handler.
Params:
  • annotationType – The loaded annotation type.
  • values – A sorted list of values of this annotation.
/** * Creates a new invocation handler. * * @param annotationType The loaded annotation type. * @param values A sorted list of values of this annotation. */
protected AnnotationInvocationHandler(Class<T> annotationType, LinkedHashMap<Method, AnnotationValue.Loaded<?>> values) { this.annotationType = annotationType; this.values = values; }
Creates a proxy instance for the supplied annotation type and values.
Params:
  • classLoader – The class loader that should be used for loading the annotation's values.
  • annotationType – The annotation's type.
  • values – The values that the annotation contains.
Type parameters:
  • <S> – The type of the handled annotation.
Throws:
  • ClassNotFoundException – If the class of an instance that is contained by this annotation could not be found.
Returns:A proxy for the annotation type and values.
/** * Creates a proxy instance for the supplied annotation type and values. * * @param classLoader The class loader that should be used for loading the annotation's values. * @param annotationType The annotation's type. * @param values The values that the annotation contains. * @param <S> The type of the handled annotation. * @return A proxy for the annotation type and values. * @throws ClassNotFoundException If the class of an instance that is contained by this annotation could not be found. */
@SuppressWarnings("unchecked") public static <S extends Annotation> S of(ClassLoader classLoader, Class<S> annotationType, Map<String, ? extends AnnotationValue<?, ?>> values) throws ClassNotFoundException { LinkedHashMap<Method, AnnotationValue.Loaded<?>> loadedValues = new LinkedHashMap<Method, AnnotationValue.Loaded<?>>(); for (Method method : annotationType.getDeclaredMethods()) { AnnotationValue<?, ?> annotationValue = values.get(method.getName()); loadedValues.put(method, (annotationValue == null ? defaultValueOf(method) : annotationValue).load(classLoader)); } return (S) Proxy.newProxyInstance(classLoader, new Class<?>[]{annotationType}, new AnnotationInvocationHandler<S>(annotationType, loadedValues)); }
Creates a default value for the given method.
Params:
  • method – The method from which to attempt the extraction of a default value.
Returns:A default value representation.
/** * Creates a default value for the given method. * * @param method The method from which to attempt the extraction of a default value. * @return A default value representation. */
private static AnnotationValue<?, ?> defaultValueOf(Method method) { Object defaultValue = method.getDefaultValue(); return defaultValue == null ? MissingValue.of(method) : AnnotationDescription.ForLoadedAnnotation.asValue(defaultValue, method.getReturnType()); }
Resolves any primitive type to its wrapper type.
Params:
  • type – The type to resolve.
Returns:The resolved type.
/** * Resolves any primitive type to its wrapper type. * * @param type The type to resolve. * @return The resolved type. */
private static Class<?> asWrapper(Class<?> type) { if (type.isPrimitive()) { if (type == boolean.class) { return Boolean.class; } else if (type == byte.class) { return Byte.class; } else if (type == short.class) { return Short.class; } else if (type == char.class) { return Character.class; } else if (type == int.class) { return Integer.class; } else if (type == long.class) { return Long.class; } else if (type == float.class) { return Float.class; } else if (type == double.class) { return Double.class; } } return type; }
{@inheritDoc}
/** * {@inheritDoc} */
public Object invoke(Object proxy, Method method, Object[] argument) { if (method.getDeclaringClass() != annotationType) { if (method.getName().equals(HASH_CODE)) { return hashCodeRepresentation(); } else if (method.getName().equals(EQUALS) && method.getParameterTypes().length == 1) { return equalsRepresentation(proxy, argument[0]); } else if (method.getName().equals(TO_STRING)) { return toStringRepresentation(); } else /* if (method.getName().equals("annotationType")) */ { return annotationType; } } Object value = values.get(method).resolve(); if (!asWrapper(method.getReturnType()).isAssignableFrom(value.getClass())) { throw new AnnotationTypeMismatchException(method, value.getClass().toString()); } return value; }
Returns the string representation of the represented annotation.
Returns:The string representation of the represented annotation.
/** * Returns the string representation of the represented annotation. * * @return The string representation of the represented annotation. */
protected String toStringRepresentation() { StringBuilder toString = new StringBuilder(); toString.append('@'); toString.append(annotationType.getName()); toString.append('('); boolean firstMember = true; for (Map.Entry<Method, AnnotationValue.Loaded<?>> entry : values.entrySet()) { if (!entry.getValue().getState().isDefined()) { continue; } if (firstMember) { firstMember = false; } else { toString.append(", "); } toString.append(entry.getKey().getName()) .append('=') .append(entry.getValue().toString()); } toString.append(')'); return toString.toString(); }
Returns the hash code of the represented annotation.
Returns:The hash code of the represented annotation.
/** * Returns the hash code of the represented annotation. * * @return The hash code of the represented annotation. */
private int hashCodeRepresentation() { int hashCode = 0; for (Map.Entry<Method, AnnotationValue.Loaded<?>> entry : values.entrySet()) { if (!entry.getValue().getState().isDefined()) { continue; } hashCode += (127 * entry.getKey().getName().hashCode()) ^ entry.getValue().hashCode(); } return hashCode; }
Checks if another instance is equal to this instance.
Params:
  • self – The annotation proxy instance.
  • other – The instance to be examined for equality to the represented instance.
Returns:true if the given instance is equal to the represented instance.
/** * Checks if another instance is equal to this instance. * * @param self The annotation proxy instance. * @param other The instance to be examined for equality to the represented instance. * @return {@code true} if the given instance is equal to the represented instance. */
private boolean equalsRepresentation(Object self, Object other) { if (self == other) { return true; } else if (!annotationType.isInstance(other)) { return false; } else if (Proxy.isProxyClass(other.getClass())) { InvocationHandler invocationHandler = Proxy.getInvocationHandler(other); if (invocationHandler instanceof AnnotationInvocationHandler) { return invocationHandler.equals(this); } } try { for (Map.Entry<Method, AnnotationValue.Loaded<?>> entry : values.entrySet()) { try { if (!entry.getValue().represents(entry.getKey().invoke(other, NO_ARGUMENTS))) { return false; } } catch (RuntimeException exception) { return false; // Incomplete annotations are not equal to one another. } } return true; } catch (InvocationTargetException ignored) { return false; } catch (IllegalAccessException exception) { throw new IllegalStateException("Could not access annotation property", exception); } } @Override public int hashCode() { int result = annotationType.hashCode(); result = 31 * result + values.hashCode(); for (Map.Entry<Method, ?> entry : values.entrySet()) { result = 31 * result + entry.getValue().hashCode(); } return result; } @Override public boolean equals(Object other) { if (this == other) { return true; } else if (!(other instanceof AnnotationInvocationHandler)) { return false; } AnnotationInvocationHandler that = (AnnotationInvocationHandler) other; if (!annotationType.equals(that.annotationType)) { return false; } for (Map.Entry<Method, AnnotationValue.Loaded<?>> entry : values.entrySet()) { if (!entry.getValue().equals(that.values.get(entry.getKey()))) { return false; } } return true; }
Represents a missing annotation property which is not represented by a default value.
/** * Represents a missing annotation property which is not represented by a default value. */
protected static class MissingValue extends AnnotationValue.Loaded.AbstractBase<Void> implements AnnotationValue<Void, Void> {
The annotation type.
/** * The annotation type. */
private final Class<? extends Annotation> annotationType;
The name of the property without an annotation value.
/** * The name of the property without an annotation value. */
private final String property;
Creates a new representation for a missing annotation property.
Params:
  • annotationType – The annotation type.
  • property – The name of the property without an annotation value.
/** * Creates a new representation for a missing annotation property. * * @param annotationType The annotation type. * @param property The name of the property without an annotation value. */
protected MissingValue(Class<? extends Annotation> annotationType, String property) { this.annotationType = annotationType; this.property = property; }
Creates a missing value for the supplied annotation property.
Params:
  • method – A method representing an annotation property.
Returns:An annotation value for a missing property.
/** * Creates a missing value for the supplied annotation property. * * @param method A method representing an annotation property. * @return An annotation value for a missing property. */
@SuppressWarnings("unchecked") protected static AnnotationValue<?, ?> of(Method method) { return new MissingValue((Class<? extends Annotation>) method.getDeclaringClass(), method.getName()); }
{@inheritDoc}
/** * {@inheritDoc} */
public State getState() { return State.UNDEFINED; }
{@inheritDoc}
/** * {@inheritDoc} */
public boolean represents(Object value) { return false; }
{@inheritDoc}
/** * {@inheritDoc} */
public Loaded<Void> load(ClassLoader classLoader) { return this; }
{@inheritDoc}
/** * {@inheritDoc} */
public Loaded<Void> loadSilent(ClassLoader classLoader) { return this; }
{@inheritDoc}
/** * {@inheritDoc} */
public Void resolve() { throw new IncompleteAnnotationException(annotationType, property); } /* does intentionally not implement hashCode, equals and toString */ } }
An adapter implementation of an annotation.
/** * An adapter implementation of an annotation. */
abstract class AbstractBase implements AnnotationDescription {
An array containing all element types that are a legal annotation target when such a target is not specified explicitly.
/** * An array containing all element types that are a legal annotation target when such a target * is not specified explicitly. */
private static final ElementType[] DEFAULT_TARGET = new ElementType[]{ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE};
{@inheritDoc}
/** * {@inheritDoc} */
public RetentionPolicy getRetention() { AnnotationDescription.Loadable<Retention> retention = getAnnotationType().getDeclaredAnnotations().ofType(Retention.class); return retention == null ? RetentionPolicy.CLASS : retention.loadSilent().value(); }
{@inheritDoc}
/** * {@inheritDoc} */
public Set<ElementType> getElementTypes() { AnnotationDescription.Loadable<Target> target = getAnnotationType().getDeclaredAnnotations().ofType(Target.class); return new HashSet<ElementType>(Arrays.asList(target == null ? DEFAULT_TARGET : target.loadSilent().value())); }
{@inheritDoc}
/** * {@inheritDoc} */
public boolean isInherited() { return getAnnotationType().getDeclaredAnnotations().isAnnotationPresent(Inherited.class); }
{@inheritDoc}
/** * {@inheritDoc} */
public boolean isDocumented() { return getAnnotationType().getDeclaredAnnotations().isAnnotationPresent(Documented.class); } @Override public int hashCode() { int hashCode = 0; for (MethodDescription.InDefinedShape methodDescription : getAnnotationType().getDeclaredMethods()) { hashCode += 31 * getValue(methodDescription).hashCode(); } return hashCode; } @Override public boolean equals(Object other) { if (this == other) { return true; } else if (!(other instanceof AnnotationDescription)) { return false; } AnnotationDescription annotationDescription = ((AnnotationDescription) other); TypeDescription annotationType = getAnnotationType(); if (!annotationDescription.getAnnotationType().equals(annotationType)) { return false; } for (MethodDescription.InDefinedShape methodDescription : annotationType.getDeclaredMethods()) { if (!getValue(methodDescription).equals(annotationDescription.getValue(methodDescription))) { return false; } } return true; } @Override public String toString() { TypeDescription annotationType = getAnnotationType(); StringBuilder toString = new StringBuilder().append('@').append(annotationType.getName()).append('('); boolean firstMember = true; for (MethodDescription.InDefinedShape methodDescription : annotationType.getDeclaredMethods()) { if (firstMember) { firstMember = false; } else { toString.append(", "); } toString.append(methodDescription.getName()).append('=').append(getValue(methodDescription)); } return toString.append(')').toString(); }
An abstract implementation of a loadable annotation description.
Type parameters:
  • <S> – The annotation type this instance was prepared for.
/** * An abstract implementation of a loadable annotation description. * * @param <S> The annotation type this instance was prepared for. */
public abstract static class ForPrepared<S extends Annotation> extends AbstractBase implements Loadable<S> {
{@inheritDoc}
/** * {@inheritDoc} */
public S loadSilent() { try { return load(); } catch (ClassNotFoundException exception) { throw new IllegalStateException("Could not load annotation type or referenced type", exception); } } } }
A description of an already loaded annotation.
Type parameters:
  • <S> – The type of the annotation.
/** * A description of an already loaded annotation. * * @param <S> The type of the annotation. */
class ForLoadedAnnotation<S extends Annotation> extends AbstractBase.ForPrepared<S> {
The represented annotation value.
/** * The represented annotation value. */
private final S annotation;
The annotation's loaded type which might be loaded by a different class loader than the value's annotation type but must be structurally equal to it.
/** * The annotation's loaded type which might be loaded by a different class loader than the value's * annotation type but must be structurally equal to it. */
private final Class<S> annotationType;
Creates a new annotation description for a loaded annotation.
Params:
  • annotation – The annotation to represent.
/** * Creates a new annotation description for a loaded annotation. * * @param annotation The annotation to represent. */
@SuppressWarnings("unchecked") protected ForLoadedAnnotation(S annotation) { this(annotation, (Class<S>) annotation.annotationType()); }
Creates a new annotation description for a loaded annotation.
Params:
  • annotation – The annotation to represent.
  • annotationType – The annotation's loaded type which might be loaded by a different class loader than the value's annotation type but must be structurally equal to it.
/** * Creates a new annotation description for a loaded annotation. * * @param annotation The annotation to represent. * @param annotationType The annotation's loaded type which might be loaded by a different class loader than the value's * annotation type but must be structurally equal to it. */
private ForLoadedAnnotation(S annotation, Class<S> annotationType) { this.annotation = annotation; this.annotationType = annotationType; }
Creates a description of the given annotation.
Params:
  • annotation – The annotation to be described.
Type parameters:
  • <U> – The type of the annotation.
Returns:A description of the given annotation.
/** * Creates a description of the given annotation. * * @param annotation The annotation to be described. * @param <U> The type of the annotation. * @return A description of the given annotation. */
public static <U extends Annotation> Loadable<U> of(U annotation) { return new ForLoadedAnnotation<U>(annotation); }
{@inheritDoc}
/** * {@inheritDoc} */
public S load() throws ClassNotFoundException { return annotationType == annotation.annotationType() ? annotation : AnnotationInvocationHandler.of(annotationType.getClassLoader(), annotationType, asValue(annotation)); }
Extracts the annotation values of an annotation into a property map.
Params:
  • annotation – The annotation to convert.
Returns:A mapping of property names to their annotation value.
/** * Extracts the annotation values of an annotation into a property map. * * @param annotation The annotation to convert. * @return A mapping of property names to their annotation value. */
private static Map<String, AnnotationValue<?, ?>> asValue(Annotation annotation) { Map<String, AnnotationValue<?, ?>> annotationValues = new HashMap<String, AnnotationValue<?, ?>>(); for (Method property : annotation.annotationType().getDeclaredMethods()) { try { annotationValues.put(property.getName(), asValue(property.invoke(annotation), property.getReturnType())); } catch (InvocationTargetException exception) { throw new IllegalStateException("Cannot read " + property, exception.getCause()); } catch (IllegalAccessException exception) { throw new IllegalStateException("Cannot access " + property, exception); } } return annotationValues; }
Transforms an annotation property to an annotation value.
Params:
  • type – The annotation's type.
  • value – The annotations value.
Returns:An annotation value representation.
/** * Transforms an annotation property to an annotation value. * * @param type The annotation's type. * @param value The annotations value. * @return An annotation value representation. */
@SuppressWarnings("unchecked") public static AnnotationValue<?, ?> asValue(Object value, Class<?> type) { // Because enums can implement annotation interfaces, the enum property needs to be checked first. if (Enum.class.isAssignableFrom(type)) { return AnnotationValue.ForEnumerationDescription.<Enum>of(new EnumerationDescription.ForLoadedEnumeration((Enum) value)); } else if (Enum[].class.isAssignableFrom(type)) { Enum<?>[] element = (Enum<?>[]) value; EnumerationDescription[] enumerationDescription = new EnumerationDescription[element.length]; int index = 0; for (Enum<?> anElement : element) { enumerationDescription[index++] = new EnumerationDescription.ForLoadedEnumeration(anElement); } return AnnotationValue.ForDescriptionArray.<Enum>of(TypeDescription.ForLoadedType.of(type.getComponentType()), enumerationDescription); } else if (Annotation.class.isAssignableFrom(type)) { return AnnotationValue.ForAnnotationDescription.<Annotation>of(TypeDescription.ForLoadedType.of(type), asValue((Annotation) value)); } else if (Annotation[].class.isAssignableFrom(type)) { Annotation[] element = (Annotation[]) value; AnnotationDescription[] annotationDescription = new AnnotationDescription[element.length]; int index = 0; for (Annotation anElement : element) { annotationDescription[index++] = new AnnotationDescription.Latent(TypeDescription.ForLoadedType.of(type.getComponentType()), asValue(anElement)); } return AnnotationValue.ForDescriptionArray.of(TypeDescription.ForLoadedType.of(type.getComponentType()), annotationDescription); } else if (Class.class.isAssignableFrom(type)) { return AnnotationValue.ForTypeDescription.<Class>of(TypeDescription.ForLoadedType.of((Class<?>) value)); } else if (Class[].class.isAssignableFrom(type)) { Class<?>[] element = (Class<?>[]) value; TypeDescription[] typeDescription = new TypeDescription[element.length]; int index = 0; for (Class<?> anElement : element) { typeDescription[index++] = TypeDescription.ForLoadedType.of(anElement); } return AnnotationValue.ForDescriptionArray.of(typeDescription); } else { return AnnotationValue.ForConstant.of(value); } }
{@inheritDoc}
/** * {@inheritDoc} */
@SuppressWarnings("deprecation") // Due to isAccessible() call. @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should always be wrapped for clarity") public AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property) { if (!property.getDeclaringType().represents(annotation.annotationType())) { throw new IllegalArgumentException(property + " does not represent " + annotation.annotationType()); } try { boolean accessible = property.getDeclaringType().isPublic(); // method is required to be public Method method = property instanceof MethodDescription.ForLoadedMethod ? ((MethodDescription.ForLoadedMethod) property).getLoadedMethod() : null; if (method == null || method.getDeclaringClass() != annotation.annotationType() || (!accessible && !method.isAccessible())) { method = annotation.annotationType().getMethod(property.getName()); if (!accessible) { AccessController.doPrivileged(new SetAccessibleAction<Method>(method)); } } return asValue(method.invoke(annotation), method.getReturnType()); } catch (InvocationTargetException exception) { throw new IllegalStateException("Error reading annotation property " + property, exception.getCause()); } catch (Exception exception) { throw new IllegalStateException("Cannot access annotation property " + property, exception); } }
{@inheritDoc}
/** * {@inheritDoc} */
@SuppressWarnings("unchecked") public <T extends Annotation> Loadable<T> prepare(Class<T> annotationType) { if (!annotation.annotationType().getName().equals(annotationType.getName())) { throw new IllegalArgumentException(annotationType + " does not represent " + annotation.annotationType()); } return annotationType == annotation.annotationType() ? (Loadable<T>) this : new ForLoadedAnnotation<T>((T) annotation, annotationType); }
{@inheritDoc}
/** * {@inheritDoc} */
public TypeDescription getAnnotationType() { return TypeDescription.ForLoadedType.of(annotation.annotationType()); } }
A latent description of an annotation value that is defined explicitly.
/** * A latent description of an annotation value that is defined explicitly. */
class Latent extends AbstractBase {
The type of the annotation.
/** * The type of the annotation. */
private final TypeDescription annotationType;
The values of the annotation mapped by their property name.
/** * The values of the annotation mapped by their property name. */
private final Map<String, ? extends AnnotationValue<?, ?>> annotationValues;
Creates a new latent annotation description.
Params:
  • annotationType – The type of the annotation.
  • annotationValues – The values of the annotation mapped by their property name.
/** * Creates a new latent annotation description. * * @param annotationType The type of the annotation. * @param annotationValues The values of the annotation mapped by their property name. */
protected Latent(TypeDescription annotationType, Map<String, ? extends AnnotationValue<?, ?>> annotationValues) { this.annotationType = annotationType; this.annotationValues = annotationValues; }
{@inheritDoc}
/** * {@inheritDoc} */
public AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property) { AnnotationValue<?, ?> value = annotationValues.get(property.getName()); if (value != null) { return value; } AnnotationValue<?, ?> defaultValue = property.getDefaultValue(); if (defaultValue != null) { return defaultValue; } throw new IllegalArgumentException("No value defined for: " + property); }
{@inheritDoc}
/** * {@inheritDoc} */
public TypeDescription getAnnotationType() { return annotationType; }
{@inheritDoc}
/** * {@inheritDoc} */
public <T extends Annotation> Loadable<T> prepare(Class<T> annotationType) { if (!this.annotationType.represents(annotationType)) { throw new IllegalArgumentException(annotationType + " does not represent " + this.annotationType); } return new Loadable<T>(annotationType); }
A loadable annotation description of a latent annotation description.
Type parameters:
  • <S> – The annotation type.
/** * A loadable annotation description of a latent annotation description. * * @param <S> The annotation type. */
protected class Loadable<S extends Annotation> extends AbstractBase.ForPrepared<S> {
The annotation type.
/** * The annotation type. */
private final Class<S> annotationType;
Creates a loadable version of a latent annotation description.
Params:
  • annotationType – The annotation type.
/** * Creates a loadable version of a latent annotation description. * * @param annotationType The annotation type. */
protected Loadable(Class<S> annotationType) { this.annotationType = annotationType; }
{@inheritDoc}
/** * {@inheritDoc} */
public S load() throws ClassNotFoundException { return AnnotationDescription.AnnotationInvocationHandler.of(annotationType.getClassLoader(), annotationType, annotationValues); }
{@inheritDoc}
/** * {@inheritDoc} */
public AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property) { return Latent.this.getValue(property); }
{@inheritDoc}
/** * {@inheritDoc} */
public TypeDescription getAnnotationType() { return TypeDescription.ForLoadedType.of(annotationType); }
{@inheritDoc}
/** * {@inheritDoc} */
public <T extends Annotation> Loadable<T> prepare(Class<T> annotationType) { return Latent.this.prepare(annotationType); } } }
A builder for pragmatically creating AnnotationDescription.
/** * A builder for pragmatically creating {@link net.bytebuddy.description.annotation.AnnotationDescription}. */
@HashCodeAndEqualsPlugin.Enhance class Builder {
The annotation type.
/** * The annotation type. */
private final TypeDescription annotationType;
A mapping of annotation properties to their annotation values.
/** * A mapping of annotation properties to their annotation values. */
private final Map<String, AnnotationValue<?, ?>> annotationValues;
Creates a builder for an annotation description.
Params:
  • annotationType – The annotation type.
  • annotationValues – A mapping of annotation properties to their annotation values.
/** * Creates a builder for an annotation description. * * @param annotationType The annotation type. * @param annotationValues A mapping of annotation properties to their annotation values. */
protected Builder(TypeDescription annotationType, Map<String, AnnotationValue<?, ?>> annotationValues) { this.annotationType = annotationType; this.annotationValues = annotationValues; }
Creates a builder for creating an annotation of the given type.
Params:
  • annotationType – The annotation type.
Returns:A builder for creating an annotation of the given type.
/** * Creates a builder for creating an annotation of the given type. * * @param annotationType The annotation type. * @return A builder for creating an annotation of the given type. */
public static Builder ofType(Class<? extends Annotation> annotationType) { return ofType(TypeDescription.ForLoadedType.of(annotationType)); }
Creates a builder for creating an annotation of the given type.
Params:
  • annotationType – A description of the annotation type.
Returns:A builder for creating an annotation of the given type.
/** * Creates a builder for creating an annotation of the given type. * * @param annotationType A description of the annotation type. * @return A builder for creating an annotation of the given type. */
public static Builder ofType(TypeDescription annotationType) { if (!annotationType.isAnnotation()) { throw new IllegalArgumentException("Not an annotation type: " + annotationType); } return new Builder(annotationType, Collections.<String, AnnotationValue<?, ?>>emptyMap()); }
Returns a builder with the additional, given property.
Params:
  • property – The name of the property to define.
  • value – An explicit description of the annotation value.
Returns:A builder with the additional, given property.
/** * Returns a builder with the additional, given property. * * @param property The name of the property to define. * @param value An explicit description of the annotation value. * @return A builder with the additional, given property. */
public Builder define(String property, AnnotationValue<?, ?> value) { MethodList<?> methodDescriptions = annotationType.getDeclaredMethods().filter(named(property)); if (methodDescriptions.isEmpty()) { throw new IllegalArgumentException(annotationType + " does not define a property named " + property); } else if (!methodDescriptions.getOnly().getReturnType().asErasure().isAnnotationValue(value.resolve())) { throw new IllegalArgumentException(value + " cannot be assigned to " + property); } Map<String, AnnotationValue<?, ?>> annotationValues = new HashMap<String, AnnotationValue<?, ?>>(); annotationValues.putAll(this.annotationValues); if (annotationValues.put(methodDescriptions.getOnly().getName(), value) != null) { throw new IllegalArgumentException("Property already defined: " + property); } return new Builder(annotationType, annotationValues); }
Returns a builder with the additional enumeration property.
Params:
  • property – The name of the property to define.
  • value – The enumeration value to define.
Returns:A builder with the additional enumeration property.
/** * Returns a builder with the additional enumeration property. * * @param property The name of the property to define. * @param value The enumeration value to define. * @return A builder with the additional enumeration property. */
public Builder define(String property, Enum<?> value) { return define(property, new EnumerationDescription.ForLoadedEnumeration(value)); }
Returns a builder with the additional enumeration property.
Params:
  • property – The name of the property to define.
  • enumerationType – The type of the enumeration.
  • value – The enumeration value to define.
Returns:A builder with the additional enumeration property.
/** * Returns a builder with the additional enumeration property. * * @param property The name of the property to define. * @param enumerationType The type of the enumeration. * @param value The enumeration value to define. * @return A builder with the additional enumeration property. */
public Builder define(String property, TypeDescription enumerationType, String value) { return define(property, new EnumerationDescription.Latent(enumerationType, value)); }
Returns a builder with the additional enumeration property.
Params:
  • property – The name of the property to define.
  • value – A description of the enumeration value to define.
Returns:A builder with the additional enumeration property.
/** * Returns a builder with the additional enumeration property. * * @param property The name of the property to define. * @param value A description of the enumeration value to define. * @return A builder with the additional enumeration property. */
@SuppressWarnings("unchecked") public Builder define(String property, EnumerationDescription value) { return define(property, AnnotationValue.ForEnumerationDescription.<Enum>of(value)); }
Returns a builder with the additional annotation property.
Params:
  • property – The name of the property to define.
  • annotation – The annotation value to define.
Returns:A builder with the additional annotation property.
/** * Returns a builder with the additional annotation property. * * @param property The name of the property to define. * @param annotation The annotation value to define. * @return A builder with the additional annotation property. */
public Builder define(String property, Annotation annotation) { return define(property, new ForLoadedAnnotation<Annotation>(annotation)); }
Returns a builder with the additional annotation property.
Params:
  • property – The name of the property to define.
  • annotationDescription – A description of the annotation value to define.
Returns:A builder with the additional annotation property.
/** * Returns a builder with the additional annotation property. * * @param property The name of the property to define. * @param annotationDescription A description of the annotation value to define. * @return A builder with the additional annotation property. */
public Builder define(String property, AnnotationDescription annotationDescription) { return define(property, new AnnotationValue.ForAnnotationDescription<Annotation>(annotationDescription)); }
Returns a builder with the additional class property.
Params:
  • property – The name of the property to define.
  • type – The class value to define.
Returns:A builder with the additional class property.
/** * Returns a builder with the additional class property. * * @param property The name of the property to define. * @param type The class value to define. * @return A builder with the additional class property. */
public Builder define(String property, Class<?> type) { return define(property, TypeDescription.ForLoadedType.of(type)); }
Returns a builder with the additional class property.
Params:
  • property – The name of the property to define.
  • typeDescription – A description of the type to define as a property value.
Returns:A builder with the additional class property.
/** * Returns a builder with the additional class property. * * @param property The name of the property to define. * @param typeDescription A description of the type to define as a property value. * @return A builder with the additional class property. */
@SuppressWarnings("unchecked") public Builder define(String property, TypeDescription typeDescription) { return define(property, AnnotationValue.ForTypeDescription.<Class>of(typeDescription)); }
Returns a builder with the additional enumeration array property.
Params:
  • property – The name of the property to define.
  • enumerationType – The type of the enumeration, i.e. the component type of the enumeration array.
  • value – The enumeration values to be contained by the array.
Type parameters:
  • <T> – The enumeration type.
Returns:A builder with the additional class property.
/** * Returns a builder with the additional enumeration array property. * * @param property The name of the property to define. * @param enumerationType The type of the enumeration, i.e. the component type of the enumeration array. * @param value The enumeration values to be contained by the array. * @param <T> The enumeration type. * @return A builder with the additional class property. */
@SuppressWarnings("unchecked") public <T extends Enum<?>> Builder defineEnumerationArray(String property, Class<T> enumerationType, T... value) { EnumerationDescription[] enumerationDescription = new EnumerationDescription[value.length]; int index = 0; for (T aValue : value) { enumerationDescription[index++] = new EnumerationDescription.ForLoadedEnumeration(aValue); } return defineEnumerationArray(property, TypeDescription.ForLoadedType.of(enumerationType), enumerationDescription); }
Returns a builder with the additional enumeration array property.
Params:
  • property – The name of the property to define.
  • enumerationType – The type of the enumerations, i.e. is the component type of the enumeration array.
  • value – The enumeration values to be contained by the array.
Returns:A builder with the additional enumeration property.
/** * Returns a builder with the additional enumeration array property. * * @param property The name of the property to define. * @param enumerationType The type of the enumerations, i.e. is the component type of the enumeration array. * @param value The enumeration values to be contained by the array. * @return A builder with the additional enumeration property. */
public Builder defineEnumerationArray(String property, TypeDescription enumerationType, String... value) { if (!enumerationType.isEnum()) { throw new IllegalArgumentException("Not an enumeration type: " + enumerationType); } EnumerationDescription[] enumerationDescription = new EnumerationDescription[value.length]; for (int i = 0; i < value.length; i++) { enumerationDescription[i] = new EnumerationDescription.Latent(enumerationType, value[i]); } return defineEnumerationArray(property, enumerationType, enumerationDescription); }
Returns a builder with the additional enumeration array property.
Params:
  • property – The name of the property to define.
  • enumerationType – The type of the enumerations, i.e. the component type of the enumeration array.
  • value – Descriptions of the enumerations to be contained by the array.
Returns:A builder with the additional enumeration property.
/** * Returns a builder with the additional enumeration array property. * * @param property The name of the property to define. * @param enumerationType The type of the enumerations, i.e. the component type of the enumeration array. * @param value Descriptions of the enumerations to be contained by the array. * @return A builder with the additional enumeration property. */
@SuppressWarnings("unchecked") public Builder defineEnumerationArray(String property, TypeDescription enumerationType, EnumerationDescription... value) { return define(property, AnnotationValue.ForDescriptionArray.<Enum>of(enumerationType, value)); }
Returns a builder with the additional annotation array property.
Params:
  • property – The name of the property to define.
  • annotationType – The type of the annotations, i.e. the component type of the enumeration array.
  • annotation – The annotation values to be contained by the array.
Type parameters:
  • <T> – The annotation type.
Returns:A builder with the additional annotation property.
/** * Returns a builder with the additional annotation array property. * * @param property The name of the property to define. * @param annotationType The type of the annotations, i.e. the component type of the enumeration array. * @param annotation The annotation values to be contained by the array. * @param <T> The annotation type. * @return A builder with the additional annotation property. */
@SuppressWarnings("unchecked") public <T extends Annotation> Builder defineAnnotationArray(String property, Class<T> annotationType, T... annotation) { return defineAnnotationArray(property, TypeDescription.ForLoadedType.of(annotationType), new AnnotationList.ForLoadedAnnotations(annotation).toArray(new AnnotationDescription[0])); }
Returns a builder with the additional annotation array property.
Params:
  • property – The name of the property to define.
  • annotationType – The type of the annotations, i.e. the component type of the enumeration array.
  • annotationDescription – Descriptions of the annotation values to be contained by the array.
Returns:A builder with the additional annotation property.
/** * Returns a builder with the additional annotation array property. * * @param property The name of the property to define. * @param annotationType The type of the annotations, i.e. the component type of the enumeration array. * @param annotationDescription Descriptions of the annotation values to be contained by the array. * @return A builder with the additional annotation property. */
public Builder defineAnnotationArray(String property, TypeDescription annotationType, AnnotationDescription... annotationDescription) { return define(property, AnnotationValue.ForDescriptionArray.of(annotationType, annotationDescription)); }
Returns a builder with the additional type array property.
Params:
  • property – The name of the property to define.
  • type – The types that should be contained by the array.
Returns:A builder with the additional type array property.
/** * Returns a builder with the additional type array property. * * @param property The name of the property to define. * @param type The types that should be contained by the array. * @return A builder with the additional type array property. */
public Builder defineTypeArray(String property, Class<?>... type) { return defineTypeArray(property, new TypeList.ForLoadedTypes(type).toArray(new TypeDescription[0])); }
Returns a builder with the additional type array property.
Params:
  • property – The name of the property to define.
  • typeDescription – Descriptions of the types that should be contained by the array.
Returns:A builder with the additional type array property.
/** * Returns a builder with the additional type array property. * * @param property The name of the property to define. * @param typeDescription Descriptions of the types that should be contained by the array. * @return A builder with the additional type array property. */
@SuppressWarnings("unchecked") public Builder defineTypeArray(String property, TypeDescription... typeDescription) { return define(property, AnnotationValue.ForDescriptionArray.of(typeDescription)); }
Returns a builder with the additional boolean property.
Params:
  • property – The name of the property to define.
  • value – The boolean value to define for the property.
Returns:A builder with the additional boolean property.
/** * Returns a builder with the additional {@code boolean} property. * * @param property The name of the property to define. * @param value The {@code boolean} value to define for the property. * @return A builder with the additional {@code boolean} property. */
public Builder define(String property, boolean value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional byte property.
Params:
  • property – The name of the property to define.
  • value – The byte value to define for the property.
Returns:A builder with the additional byte property.
/** * Returns a builder with the additional {@code byte} property. * * @param property The name of the property to define. * @param value The {@code byte} value to define for the property. * @return A builder with the additional {@code byte} property. */
public Builder define(String property, byte value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional char property.
Params:
  • property – The name of the property to define.
  • value – The char value to define for the property.
Returns:A builder with the additional char property.
/** * Returns a builder with the additional {@code char} property. * * @param property The name of the property to define. * @param value The {@code char} value to define for the property. * @return A builder with the additional {@code char} property. */
public Builder define(String property, char value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional short property.
Params:
  • property – The name of the property to define.
  • value – The short value to define for the property.
Returns:A builder with the additional short property.
/** * Returns a builder with the additional {@code short} property. * * @param property The name of the property to define. * @param value The {@code short} value to define for the property. * @return A builder with the additional {@code short} property. */
public Builder define(String property, short value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional int property.
Params:
  • property – The name of the property to define.
  • value – The int value to define for the property.
Returns:A builder with the additional int property.
/** * Returns a builder with the additional {@code int} property. * * @param property The name of the property to define. * @param value The {@code int} value to define for the property. * @return A builder with the additional {@code int} property. */
public Builder define(String property, int value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional long property.
Params:
  • property – The name of the property to define.
  • value – The long value to define for the property.
Returns:A builder with the additional long property.
/** * Returns a builder with the additional {@code long} property. * * @param property The name of the property to define. * @param value The {@code long} value to define for the property. * @return A builder with the additional {@code long} property. */
public Builder define(String property, long value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional float property.
Params:
  • property – The name of the property to define.
  • value – The float value to define for the property.
Returns:A builder with the additional float property.
/** * Returns a builder with the additional {@code float} property. * * @param property The name of the property to define. * @param value The {@code float} value to define for the property. * @return A builder with the additional {@code float} property. */
public Builder define(String property, float value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional double property.
Params:
  • property – The name of the property to define.
  • value – The double value to define for the property.
Returns:A builder with the additional double property.
/** * Returns a builder with the additional {@code double} property. * * @param property The name of the property to define. * @param value The {@code double} value to define for the property. * @return A builder with the additional {@code double} property. */
public Builder define(String property, double value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional String property.
Params:
  • property – The name of the property to define.
  • value – The String value to define for the property.
Returns:A builder with the additional String property.
/** * Returns a builder with the additional {@link java.lang.String} property. * * @param property The name of the property to define. * @param value The {@link java.lang.String} value to define for the property. * @return A builder with the additional {@link java.lang.String} property. */
public Builder define(String property, String value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional boolean array property.
Params:
  • property – The name of the property to define.
  • value – The boolean values to define for the property.
Returns:A builder with the additional boolean array property.
/** * Returns a builder with the additional {@code boolean} array property. * * @param property The name of the property to define. * @param value The {@code boolean} values to define for the property. * @return A builder with the additional {@code boolean} array property. */
public Builder defineArray(String property, boolean... value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional byte array property.
Params:
  • property – The name of the property to define.
  • value – The byte values to define for the property.
Returns:A builder with the additional byte array property.
/** * Returns a builder with the additional {@code byte} array property. * * @param property The name of the property to define. * @param value The {@code byte} values to define for the property. * @return A builder with the additional {@code byte} array property. */
public Builder defineArray(String property, byte... value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional char array property.
Params:
  • property – The name of the property to define.
  • value – The char values to define for the property.
Returns:A builder with the additional char array property.
/** * Returns a builder with the additional {@code char} array property. * * @param property The name of the property to define. * @param value The {@code char} values to define for the property. * @return A builder with the additional {@code char} array property. */
public Builder defineArray(String property, char... value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional short array property.
Params:
  • property – The name of the property to define.
  • value – The short values to define for the property.
Returns:A builder with the additional short array property.
/** * Returns a builder with the additional {@code short} array property. * * @param property The name of the property to define. * @param value The {@code short} values to define for the property. * @return A builder with the additional {@code short} array property. */
public Builder defineArray(String property, short... value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional int array property.
Params:
  • property – The name of the property to define.
  • value – The int values to define for the property.
Returns:A builder with the additional int array property.
/** * Returns a builder with the additional {@code int} array property. * * @param property The name of the property to define. * @param value The {@code int} values to define for the property. * @return A builder with the additional {@code int} array property. */
public Builder defineArray(String property, int... value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional long array property.
Params:
  • property – The name of the property to define.
  • value – The long values to define for the property.
Returns:A builder with the additional long array property.
/** * Returns a builder with the additional {@code long} array property. * * @param property The name of the property to define. * @param value The {@code long} values to define for the property. * @return A builder with the additional {@code long} array property. */
public Builder defineArray(String property, long... value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional float array property.
Params:
  • property – The name of the property to define.
  • value – The float values to define for the property.
Returns:A builder with the additional float array property.
/** * Returns a builder with the additional {@code float} array property. * * @param property The name of the property to define. * @param value The {@code float} values to define for the property. * @return A builder with the additional {@code float} array property. */
public Builder defineArray(String property, float... value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional double array property.
Params:
  • property – The name of the property to define.
  • value – The double values to define for the property.
Returns:A builder with the additional double array property.
/** * Returns a builder with the additional {@code double} array property. * * @param property The name of the property to define. * @param value The {@code double} values to define for the property. * @return A builder with the additional {@code double} array property. */
public Builder defineArray(String property, double... value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Returns a builder with the additional String array property.
Params:
  • property – The name of the property to define.
  • value – The String array value to define for the property.
Returns:A builder with the additional String array property.
/** * Returns a builder with the additional {@link java.lang.String} array property. * * @param property The name of the property to define. * @param value The {@link java.lang.String} array value to define for the property. * @return A builder with the additional {@link java.lang.String} array property. */
public Builder defineArray(String property, String... value) { return define(property, AnnotationValue.ForConstant.of(value)); }
Creates an annotation description for the values that were defined for this builder.
Returns:An appropriate annotation description.
/** * Creates an annotation description for the values that were defined for this builder. * * @return An appropriate annotation description. */
public AnnotationDescription build() { for (MethodDescription methodDescription : annotationType.getDeclaredMethods()) { if (annotationValues.get(methodDescription.getName()) == null && methodDescription.getDefaultValue() == null) { throw new IllegalStateException("No value or default value defined for " + methodDescription.getName()); } } return new Latent(annotationType, annotationValues); } } }