Skip to content

Commit

Permalink
Added tests and missing matcher. Fixed handling of bootstrap class lo…
Browse files Browse the repository at this point in the history
…ader for annotation handler.
  • Loading branch information
raphw committed Jul 14, 2015
1 parent 808f503 commit adc14c0
Show file tree
Hide file tree
Showing 33 changed files with 971 additions and 217 deletions.
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
import net.bytebuddy.description.type.TypeList; import net.bytebuddy.description.type.TypeList;
import net.bytebuddy.utility.PropertyDispatcher; import net.bytebuddy.utility.PropertyDispatcher;


import java.lang.annotation.Annotation; import java.lang.annotation.*;
import java.lang.annotation.AnnotationTypeMismatchException;
import java.lang.annotation.IncompleteAnnotationException;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;


Expand Down Expand Up @@ -70,6 +68,24 @@ public interface AnnotationDescription {
*/ */
<T extends Annotation> Loadable<T> prepare(Class<T> annotationType); <T extends Annotation> Loadable<T> prepare(Class<T> annotationType);


RetentionPolicy getRetention();

/**
* 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();

/** /**
* A description of an annotation's value. * A description of an annotation's value.
* *
Expand Down Expand Up @@ -1074,11 +1090,6 @@ class AnnotationInvocationHandler<T extends Annotation> implements InvocationHan
*/ */
private static final String TO_STRING = "toString"; private static final String TO_STRING = "toString";


/**
* The class loader to use.
*/
private final ClassLoader classLoader;

/** /**
* The loaded annotation type. * The loaded annotation type.
*/ */
Expand All @@ -1092,14 +1103,10 @@ class AnnotationInvocationHandler<T extends Annotation> implements InvocationHan
/** /**
* Creates a new invocation handler. * Creates a new invocation handler.
* *
* @param classLoader The class loader for loading this value.
* @param annotationType The loaded annotation type. * @param annotationType The loaded annotation type.
* @param values A sorted list of values of this annotation. * @param values A sorted list of values of this annotation.
*/ */
protected AnnotationInvocationHandler(ClassLoader classLoader, protected AnnotationInvocationHandler(Class<T> annotationType, LinkedHashMap<Method, AnnotationValue.Loaded<?>> values) {
Class<T> annotationType,
LinkedHashMap<Method, AnnotationValue.Loaded<?>> values) {
this.classLoader = classLoader;
this.annotationType = annotationType; this.annotationType = annotationType;
this.values = values; this.values = values;
} }
Expand All @@ -1122,9 +1129,9 @@ public static <S extends Annotation> InvocationHandler of(ClassLoader classLoade
AnnotationDescription.AnnotationValue<?, ?> annotationValue = values.get(method.getName()); AnnotationDescription.AnnotationValue<?, ?> annotationValue = values.get(method.getName());
loadedValues.put(method, annotationValue == null loadedValues.put(method, annotationValue == null
? DefaultValue.of(method) ? DefaultValue.of(method)
: annotationValue.load(classLoader)); : annotationValue.load(classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader));
} }
return new AnnotationInvocationHandler<S>(classLoader, annotationType, loadedValues); return new AnnotationInvocationHandler<S>(annotationType, loadedValues);
} }


/** /**
Expand Down Expand Up @@ -1292,7 +1299,6 @@ public int hashCode() {
public String toString() { public String toString() {
return "TypePool.LazyTypeDescription.AnnotationInvocationHandler{" + return "TypePool.LazyTypeDescription.AnnotationInvocationHandler{" +
"annotationType=" + annotationType + "annotationType=" + annotationType +
", classLoader=" + classLoader +
", values=" + values + ", values=" + values +
'}'; '}';
} }
Expand Down Expand Up @@ -1410,6 +1416,24 @@ public Void resolve() {
*/ */
abstract class AbstractAnnotationDescription implements AnnotationDescription { abstract class AbstractAnnotationDescription implements AnnotationDescription {


@Override
public RetentionPolicy getRetention() {
AnnotationDescription.Loadable<Retention> retention = getAnnotationType().getDeclaredAnnotations().ofType(Retention.class);
return retention == null
? RetentionPolicy.SOURCE
: retention.loadSilent().value();
}

@Override
public boolean isInherited() {
return getAnnotationType().getDeclaredAnnotations().isAnnotationPresent(Inherited.class);
}

@Override
public boolean isDocumented() {
return getAnnotationType().getDeclaredAnnotations().isAnnotationPresent(Documented.class);
}

@Override @Override
public <T> T getValue(MethodDescription methodDescription, Class<T> type) { public <T> T getValue(MethodDescription methodDescription, Class<T> type) {
return type.cast(getValue(methodDescription)); return type.cast(getValue(methodDescription));
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -1,11 +1,15 @@
package net.bytebuddy.description.annotation; package net.bytebuddy.description.annotation;


import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.FilterableList; import net.bytebuddy.matcher.FilterableList;


import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited; import java.lang.annotation.RetentionPolicy;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;


/** /**
* Defines a list of annotation instances. * Defines a list of annotation instances.
Expand Down Expand Up @@ -46,6 +50,14 @@ public interface AnnotationList extends FilterableList<AnnotationDescription, An
*/ */
AnnotationList inherited(Set<? extends TypeDescription> ignoredTypes); AnnotationList inherited(Set<? extends TypeDescription> ignoredTypes);


/**
* Only retains annotations with the given retention policy.
*
* @param matcher A matcher for the required retention policy.
* @return A of annotations only with elements
*/
AnnotationList visibility(ElementMatcher<? super RetentionPolicy> matcher);

/** /**
* An abstract base implementation of an annotation list. * An abstract base implementation of an annotation list.
*/ */
Expand All @@ -64,7 +76,7 @@ public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
@Override @Override
public boolean isAnnotationPresent(TypeDescription annotationType) { public boolean isAnnotationPresent(TypeDescription annotationType) {
for (AnnotationDescription annotation : this) { for (AnnotationDescription annotation : this) {
if (annotation.getAnnotationType().represents(annotation.getClass())) { if (annotation.getAnnotationType().equals(annotationType)) {
return true; return true;
} }
} }
Expand All @@ -83,16 +95,26 @@ public <T extends Annotation> AnnotationDescription.Loadable<T> ofType(Class<T>


@Override @Override
public AnnotationList inherited(Set<? extends TypeDescription> ignoredTypes) { public AnnotationList inherited(Set<? extends TypeDescription> ignoredTypes) {
List<AnnotationDescription> inherited = new LinkedList<AnnotationDescription>(); List<AnnotationDescription> inherited = new ArrayList<AnnotationDescription>(size());
for (AnnotationDescription annotation : this) { for (AnnotationDescription annotation : this) {
if (!ignoredTypes.contains(annotation.getAnnotationType()) if (!ignoredTypes.contains(annotation.getAnnotationType()) && annotation.isInherited()) {
&& annotation.getAnnotationType().getDeclaredAnnotations().isAnnotationPresent(Inherited.class)) {
inherited.add(annotation); inherited.add(annotation);
} }
} }
return wrap(inherited); return wrap(inherited);
} }


@Override
public AnnotationList visibility(ElementMatcher<? super RetentionPolicy> matcher) {
List<AnnotationDescription> annotationDescriptions = new ArrayList<AnnotationDescription>(size());
for (AnnotationDescription annotation : this) {
if (matcher.matches(annotation.getRetention())) {
annotationDescriptions.add(annotation);
}
}
return wrap(annotationDescriptions);
}

@Override @Override
protected AnnotationList wrap(List<AnnotationDescription> values) { protected AnnotationList wrap(List<AnnotationDescription> values) {
return new Explicit(values); return new Explicit(values);
Expand Down Expand Up @@ -234,5 +256,10 @@ public <T extends Annotation> AnnotationDescription.Loadable<T> ofType(Class<T>
public AnnotationList inherited(Set<? extends TypeDescription> ignoredTypes) { public AnnotationList inherited(Set<? extends TypeDescription> ignoredTypes) {
return this; return this;
} }

@Override
public AnnotationList visibility(ElementMatcher<? super RetentionPolicy> matcher) {
return this;
}
} }
} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public interface TypeList extends FilterableList<TypeDescription, TypeList> {
* @param visitor The visitor to apply to each type. * @param visitor The visitor to apply to each type.
* @return This type list with all types transformed by the supplied visitor. * @return This type list with all types transformed by the supplied visitor.
*/ */
TypeList accept(GenericTypeDescription.Visitor<? extends TypeDescription> visitor); GenericTypeList accept(GenericTypeDescription.Visitor<? extends GenericTypeDescription> visitor);


/** /**
* An abstract base implementation of a type list. * An abstract base implementation of a type list.
Expand All @@ -56,12 +56,12 @@ protected TypeList wrap(List<TypeDescription> values) {
} }


@Override @Override
public TypeList accept(GenericTypeDescription.Visitor<? extends TypeDescription> visitor) { public GenericTypeList accept(GenericTypeDescription.Visitor<? extends GenericTypeDescription> visitor) {
List<TypeDescription> visited = new ArrayList<TypeDescription>(size()); List<GenericTypeDescription> visited = new ArrayList<GenericTypeDescription>(size());
for (TypeDescription typeDescription : this) { for (TypeDescription typeDescription : this) {
visited.add(typeDescription.accept(visitor)); visited.add(typeDescription.accept(visitor));
} }
return new Explicit(visited); return new GenericTypeList.Explicit(visited);
} }
} }


Expand Down Expand Up @@ -199,8 +199,8 @@ public GenericTypeList asGenericTypes() {
} }


@Override @Override
public TypeList accept(GenericTypeDescription.Visitor<? extends TypeDescription> visitor) { public GenericTypeList accept(GenericTypeDescription.Visitor<? extends GenericTypeDescription> visitor) {
return this; return new GenericTypeList.Empty();
} }
} }
} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList; import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.field.FieldList;
import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.method.ParameterDescription; import net.bytebuddy.description.method.ParameterDescription;
Expand Down Expand Up @@ -284,6 +285,18 @@ public static <T extends MethodDescription> ElementMatcher.Junction<T> anyOf(Met
return anyOf(new MethodList.ForLoadedType(new Constructor<?>[0], nonNull(value))); return anyOf(new MethodList.ForLoadedType(new Constructor<?>[0], nonNull(value)));
} }


/**
* Creates a matcher that matches any of the given fields as {@link FieldDescription}s
* by the {@link java.lang.Object#equals(Object)} method. None of the values must be {@code null}.
*
* @param value The input values to be compared against.
* @param <T> The type of the matched object.
* @return A matcher that checks for the equality with any of the given objects.
*/
public static <T extends FieldDescription> ElementMatcher.Junction<T> anyOf(Field... value) {
return anyOf(new FieldList.ForLoadedField(nonNull(value)));
}

/** /**
* Creates a matcher that matches any of the given annotations as {@link AnnotationDescription}s * Creates a matcher that matches any of the given annotations as {@link AnnotationDescription}s
* by the {@link java.lang.Object#equals(Object)} method. None of the values must be {@code null}. * by the {@link java.lang.Object#equals(Object)} method. None of the values must be {@code null}.
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5244,7 +5244,7 @@ public S load() throws ClassNotFoundException {
public S load(ClassLoader classLoader) throws ClassNotFoundException { public S load(ClassLoader classLoader) throws ClassNotFoundException {
return (S) Proxy.newProxyInstance(classLoader, return (S) Proxy.newProxyInstance(classLoader,
new Class<?>[]{annotationType}, new Class<?>[]{annotationType},
AnnotationInvocationHandler.of(annotationType.getClassLoader(), annotationType, values)); AnnotationInvocationHandler.of(classLoader, annotationType, values));
} }


@Override @Override
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;


import java.lang.annotation.Annotation; import java.lang.annotation.*;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collections; import java.util.Collections;


Expand Down Expand Up @@ -375,6 +373,23 @@ public void testValuesDefaults() throws Exception {
assertValue(defaultSecond, "annotationArrayValue", new AnnotationDescription[]{AnnotationDescription.ForLoadedAnnotation.of(OTHER_ANNOTATION)}, OTHER_ANNOTATION_ARRAY); assertValue(defaultSecond, "annotationArrayValue", new AnnotationDescription[]{AnnotationDescription.ForLoadedAnnotation.of(OTHER_ANNOTATION)}, OTHER_ANNOTATION_ARRAY);
} }


@Test
public void testRetention() throws Exception {
assertThat(describe(first).getRetention(), is(RetentionPolicy.RUNTIME));
}

@Test
public void testInheritance() throws Exception {
assertThat(describe(first).isInherited(), is(false));
assertThat(describe(defaultFirst).isInherited(), is(true));
}

@Test
public void testDocumented() throws Exception {
assertThat(describe(first).isDocumented(), is(false));
assertThat(describe(defaultFirst).isDocumented(), is(true));
}

private void assertValue(Annotation annotation, String methodName, Object rawValue, Object loadedValue) throws Exception { private void assertValue(Annotation annotation, String methodName, Object rawValue, Object loadedValue) throws Exception {
assertThat(describe(annotation).getValue(new MethodDescription assertThat(describe(annotation).getValue(new MethodDescription
.ForLoadedMethod(annotation.annotationType().getDeclaredMethod(methodName))), is(rawValue)); .ForLoadedMethod(annotation.annotationType().getDeclaredMethod(methodName))), is(rawValue));
Expand Down Expand Up @@ -450,6 +465,8 @@ public enum SampleEnumeration {
Other[] annotationArrayValue(); Other[] annotationArrayValue();
} }


@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface SampleDefault { public @interface SampleDefault {


Expand Down
Loading

0 comments on commit adc14c0

Please sign in to comment.