// Generated by delombok at Sun Feb 26 12:31:38 KST 2017
package scouter.bytebuddy.description.annotation;
import scouter.bytebuddy.description.enumeration.EnumerationDescription;
import scouter.bytebuddy.description.method.MethodDescription;
import scouter.bytebuddy.description.method.MethodList;
import scouter.bytebuddy.description.type.TypeDescription;
import scouter.bytebuddy.description.type.TypeList;
import scouter.bytebuddy.utility.privilege.SetAccessibleAction;
import scouter.bytebuddy.matcher.ElementMatchers;
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.*;
/**
* 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 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 an inexistent annotation in a type-safe manner.
*/
AnnotationDescription.Loadable<?> UNDEFINED = null;
/**
* 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.
*
* @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.
*
* @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.
*
* @return This annotation's retention policy.
*/
RetentionPolicy getRetention();
/**
* 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.
*
* @return {@code true} if this annotation is inherited.
* @see Inherited
*/
boolean isInherited();
/**
* 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.
*
* @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.
*
* @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 {@link java.lang.ClassNotFoundException} is wrapped in an {@link java.lang.IllegalStateException}.
*
* @return A loaded version of this annotation description.
*/
S loadSilent();
}
/**
* 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 {@link Object#hashCode()} method.
*/
private static final String HASH_CODE = "hashCode";
/**
* The name of the {@link Object#equals(Object)} method.
*/
private static final String EQUALS = "equals";
/**
* The name of the {@link Object#toString()} method.
*/
private static final String TO_STRING = "toString";
/**
* The loaded annotation type.
*/
private final Class<? extends Annotation> annotationType;
/**
* A sorted list of values of this annotation.
*/
private final LinkedHashMap<Method, AnnotationValue.Loaded<?>> values;
/**
* 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.
*
* @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.
*
* @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.
*
* @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;
}
@Override
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.
*
* @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.
*
* @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.
*
* @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))) {
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 boolean equals(Object other) {
if (this == other) return true;
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;
}
@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;
}
/**
* 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.
*/
private final Class<? extends Annotation> annotationType;
/**
* The name of the property without an annotation value.
*/
private final String property;
/**
* 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;
}
@SuppressWarnings("unchecked")
protected static AnnotationValue<?, ?> of(Method method) {
return new MissingValue((Class<? extends Annotation>) method.getDeclaringClass(), method.getName());
}
@Override
public State getState() {
return State.UNDEFINED;
}
@Override
public boolean represents(Object value) {
return false;
}
@Override
public Loaded<Void> load(ClassLoader classLoader) {
return this;
}
@Override
public Loaded<Void> loadSilent(ClassLoader classLoader) {
return this;
}
@Override
public Void resolve() {
throw new IncompleteAnnotationException(annotationType, property);
}
/* does intentionally not implement hashCode, equals and toString */
/**
* 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.
*/
}
}
/**
* 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.
*/
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};
@Override
public RetentionPolicy getRetention() {
AnnotationDescription.Loadable<Retention> retention = getAnnotationType().getDeclaredAnnotations().ofType(Retention.class);
return retention == null ? RetentionPolicy.CLASS : retention.loadSilent().value();
}
@Override
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()));
}
@Override
public boolean isInherited() {
return getAnnotationType().getDeclaredAnnotations().isAnnotationPresent(Inherited.class);
}
@Override
public boolean isDocumented() {
return getAnnotationType().getDeclaredAnnotations().isAnnotationPresent(Documented.class);
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
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 int hashCode() {
int hashCode = 0;
for (MethodDescription.InDefinedShape methodDescription : getAnnotationType().getDeclaredMethods()) {
hashCode += 31 * getValue(methodDescription).hashCode();
}
return hashCode;
}
@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.
*
* @param <S> The annotation type this instance was prepared for.
*/
public static abstract class ForPrepared<S extends Annotation> extends AbstractBase implements Loadable<S> {
@Override
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.
*
* @param <S> The type of the annotation.
*/
class ForLoadedAnnotation<S extends Annotation> extends AbstractBase.ForPrepared<S> {
/**
* 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 structually equal to it.
*/
private final Class<S> annotationType;
/**
* 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.
*
* @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 structually equal to it.
*/
private ForLoadedAnnotation(S annotation, Class<S> annotationType) {
this.annotation = annotation;
this.annotationType = annotationType;
}
/**
* 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);
}
@Override
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.
*
* @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.
*
* @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(new TypeDescription.ForLoadedType(type.getComponentType()), enumerationDescription);
} else if (Annotation.class.isAssignableFrom(type)) {
return AnnotationValue.ForAnnotationDescription.<Annotation>of(new TypeDescription.ForLoadedType(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(new TypeDescription.ForLoadedType(type.getComponentType()), asValue(anElement));
}
return AnnotationValue.ForDescriptionArray.of(new TypeDescription.ForLoadedType(type.getComponentType()), annotationDescription);
} else if (Class.class.isAssignableFrom(type)) {
return AnnotationValue.ForTypeDescription.<Class>of(new TypeDescription.ForLoadedType((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++] = new TypeDescription.ForLoadedType(anElement);
}
return AnnotationValue.ForDescriptionArray.of(typeDescription);
} else {
return AnnotationValue.ForConstant.of(value);
}
}
@Override
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);
}
}
@Override
@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);
}
@Override
public TypeDescription getAnnotationType() {
return new TypeDescription.ForLoadedType(annotation.annotationType());
}
}
/**
* A latent description of an annotation value that is defined explicitly.
*/
class Latent extends AbstractBase {
/**
* The type of the annotation.
*/
private final TypeDescription annotationType;
/**
* The values of the annotation mapped by their property name.
*/
private final Map<String, ? extends AnnotationValue<?, ?>> annotationValues;
/**
* 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;
}
@Override
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);
}
@Override
public TypeDescription getAnnotationType() {
return annotationType;
}
@Override
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.
*
* @param <S> The annotation type.
*/
protected class Loadable<S extends Annotation> extends AbstractBase.ForPrepared<S> {
/**
* The annotation type.
*/
private final Class<S> annotationType;
/**
* Creates a loadable version of a latent annotation description.
*
* @param annotationType The annotation type.
*/
protected Loadable(Class<S> annotationType) {
this.annotationType = annotationType;
}
@Override
public S load() throws ClassNotFoundException {
return AnnotationDescription.AnnotationInvocationHandler.of(annotationType.getClassLoader(), annotationType, annotationValues);
}
@Override
public AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property) {
return Latent.this.getValue(property);
}
@Override
public TypeDescription getAnnotationType() {
return new TypeDescription.ForLoadedType(annotationType);
}
@Override
public <T extends Annotation> Loadable<T> prepare(Class<T> annotationType) {
return Latent.this.prepare(annotationType);
}
}
}
/**
* A builder for pragmatically creating {@link AnnotationDescription}.
*/
class Builder {
/**
* The annotation type.
*/
private final TypeDescription annotationType;
/**
* A mapping of annotation properties to their annotation values.
*/
private final Map<String, AnnotationValue<?, ?>> annotationValues;
/**
* 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.
*
* @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(new TypeDescription.ForLoadedType(annotationType));
}
/**
* 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.
*
* @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(ElementMatchers.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.
*
* @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.
*
* @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.
*
* @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.
*
* @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.
*
* @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.
*
* @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, new TypeDescription.ForLoadedType(type));
}
/**
* 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.
*
* @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, new TypeDescription.ForLoadedType(enumerationType), enumerationDescription);
}
/**
* 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.
*
* @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.
*
* @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, new TypeDescription.ForLoadedType(annotationType), new AnnotationList.ForLoadedAnnotations(annotation).toArray(new AnnotationDescription[annotation.length]));
}
/**
* 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.
*
* @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[type.length]));
}
/**
* 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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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 {@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.
*
* @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);
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof AnnotationDescription.Builder)) return false;
final AnnotationDescription.Builder other = (AnnotationDescription.Builder) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$annotationType = this.annotationType;
final java.lang.Object other$annotationType = other.annotationType;
if (this$annotationType == null ? other$annotationType != null : !this$annotationType.equals(other$annotationType)) return false;
final java.lang.Object this$annotationValues = this.annotationValues;
final java.lang.Object other$annotationValues = other.annotationValues;
if (this$annotationValues == null ? other$annotationValues != null : !this$annotationValues.equals(other$annotationValues)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof AnnotationDescription.Builder;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $annotationType = this.annotationType;
result = result * PRIME + ($annotationType == null ? 43 : $annotationType.hashCode());
final java.lang.Object $annotationValues = this.annotationValues;
result = result * PRIME + ($annotationValues == null ? 43 : $annotationValues.hashCode());
return result;
}
}
}