package net.bytebuddy.description.type; import net.bytebuddy.description.TypeVariableSource; import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.annotation.AnnotationList; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.dynamic.loading.ByteArrayClassLoader; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.implementation.bytecode.StackSize; import net.bytebuddy.test.packaging.SimpleType; import net.bytebuddy.test.scope.EnclosingType; import net.bytebuddy.test.utility.ClassFileExtraction; import net.bytebuddy.test.visibility.Sample; import org.hamcrest.CoreMatchers; import org.hamcrest.Matcher; import org.junit.Test; import org.objectweb.asm.*; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Array; import java.lang.reflect.GenericSignatureFormatError; import java.util.*; import java.util.concurrent.Callable; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public abstract class AbstractTypeDescriptionTest extends AbstractTypeDescriptionGenericVariableDefiningTest { private static final String FOO = "foo", BAR = "bar"; private final List<Class<?>> standardTypes; @SuppressWarnings({"unchecked", "deprecation"}) protected AbstractTypeDescriptionTest() { standardTypes = Arrays.asList( Object.class, Object[].class, SampleClass.class, SampleClass[].class, SampleInterface.class, SampleInterface[].class, SampleAnnotation.class, SampleAnnotation[].class, void.class, byte.class, byte[].class, short.class, short[].class, char.class, char[].class, int.class, int[].class, long.class, long[].class, float.class, float[].class, double.class, double[].class, new EnclosingType().localMethod, Array.newInstance(new EnclosingType().localConstructor, 1).getClass(), new EnclosingType().anonymousMethod, Array.newInstance(new EnclosingType().anonymousMethod, 1).getClass(), new EnclosingType().localConstructor, Array.newInstance(new EnclosingType().localConstructor, 1).getClass(), new EnclosingType().anonymousConstructor, Array.newInstance(new EnclosingType().anonymousConstructor, 1).getClass(), EnclosingType.LOCAL_INITIALIZER, Array.newInstance(EnclosingType.LOCAL_INITIALIZER.getClass(), 1).getClass(), EnclosingType.ANONYMOUS_INITIALIZER, Array.newInstance(EnclosingType.ANONYMOUS_INITIALIZER, 1).getClass(), EnclosingType.LOCAL_METHOD, Array.newInstance(EnclosingType.LOCAL_METHOD.getClass(), 1).getClass(), EnclosingType.ANONYMOUS_METHOD, Array.newInstance(EnclosingType.ANONYMOUS_METHOD, 1).getClass(), EnclosingType.INNER, Array.newInstance(EnclosingType.INNER, 1).getClass(), EnclosingType.NESTED, Array.newInstance(EnclosingType.NESTED, 1).getClass(), EnclosingType.PRIVATE_INNER, Array.newInstance(EnclosingType.PRIVATE_INNER, 1).getClass(), EnclosingType.PRIVATE_NESTED, Array.newInstance(EnclosingType.PRIVATE_NESTED, 1).getClass(), EnclosingType.PROTECTED_INNER, Array.newInstance(EnclosingType.PROTECTED_INNER, 1).getClass(), EnclosingType.PROTECTED_NESTED, Array.newInstance(EnclosingType.PROTECTED_NESTED, 1).getClass(), EnclosingType.PACKAGE_INNER, Array.newInstance(EnclosingType.PACKAGE_INNER, 1).getClass(), EnclosingType.PACKAGE_NESTED, Array.newInstance(EnclosingType.PACKAGE_NESTED, 1).getClass(), EnclosingType.FINAL_NESTED, Array.newInstance(EnclosingType.FINAL_NESTED, 1).getClass(), EnclosingType.FINAL_INNER, Array.newInstance(EnclosingType.FINAL_INNER, 1).getClass(), EnclosingType.DEPRECATED, Array.newInstance(EnclosingType.DEPRECATED, 1).getClass()); } @Test public void testPrecondition() throws Exception { assertThat(describe(SampleClass.class), not(describe(SampleInterface.class))); assertThat(describe(SampleClass.class), not(describe(SampleAnnotation.class))); assertThat(describe(SampleClass.class), is(describe(SampleClass.class))); assertThat(describe(SampleInterface.class), is(describe(SampleInterface.class))); assertThat(describe(SampleAnnotation.class), is(describe(SampleAnnotation.class))); assertThat(describe(SampleClass.class), is((TypeDescription) new TypeDescription.ForLoadedType(SampleClass.class))); assertThat(describe(SampleInterface.class), is((TypeDescription) new TypeDescription.ForLoadedType(SampleInterface.class))); assertThat(describe(SampleAnnotation.class), is((TypeDescription) new TypeDescription.ForLoadedType(SampleAnnotation.class))); } @Test public void testStackSize() throws Exception { assertThat(describe(void.class).getStackSize(), is(StackSize.ZERO)); assertThat(describe(boolean.class).getStackSize(), is(StackSize.SINGLE)); assertThat(describe(byte.class).getStackSize(), is(StackSize.SINGLE)); assertThat(describe(short.class).getStackSize(), is(StackSize.SINGLE)); assertThat(describe(char.class).getStackSize(), is(StackSize.SINGLE)); assertThat(describe(int.class).getStackSize(), is(StackSize.SINGLE)); assertThat(describe(long.class).getStackSize(), is(StackSize.DOUBLE)); assertThat(describe(float.class).getStackSize(), is(StackSize.SINGLE)); assertThat(describe(double.class).getStackSize(), is(StackSize.DOUBLE)); assertThat(describe(Object.class).getStackSize(), is(StackSize.SINGLE)); assertThat(describe(SampleClass.class).getStackSize(), is(StackSize.SINGLE)); assertThat(describe(Object[].class).getStackSize(), is(StackSize.SINGLE)); assertThat(describe(long[].class).getStackSize(), is(StackSize.SINGLE)); } @Test public void testName() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).getName(), is(type.getName())); } } @Test public void testSourceName() throws Exception { for (Class<?> type : standardTypes) { if (type.isArray()) { assertThat(describe(type).getActualName(), is(type.getComponentType().getName() + "[]")); } else { assertThat(describe(type).getActualName(), is(type.getName())); } } } @Test public void testInternalName() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).getInternalName(), is(Type.getInternalName(type))); } } @Test public void testCanonicalName() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).getCanonicalName(), is(type.getCanonicalName())); } } @Test public void testSimpleName() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).getSimpleName(), is(type.getSimpleName())); } } @Test public void testIsMemberClass() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).isMemberClass(), is(type.isMemberClass())); } } @Test public void testIsAnonymousClass() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).isAnonymousClass(), is(type.isAnonymousClass())); } } @Test public void testIsLocalClass() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).isLocalClass(), is(type.isLocalClass())); } } @Test public void testJavaName() throws Exception { assertThat(describe(Object.class).getActualName(), is(Object.class.getName())); assertThat(describe(SampleClass.class).getActualName(), is(SampleClass.class.getName())); assertThat(describe(void.class).getActualName(), is(void.class.getName())); assertThat(describe(boolean.class).getActualName(), is(boolean.class.getName())); assertThat(describe(byte.class).getActualName(), is(byte.class.getName())); assertThat(describe(short.class).getActualName(), is(short.class.getName())); assertThat(describe(char.class).getActualName(), is(char.class.getName())); assertThat(describe(int.class).getActualName(), is(int.class.getName())); assertThat(describe(long.class).getActualName(), is(long.class.getName())); assertThat(describe(float.class).getActualName(), is(float.class.getName())); assertThat(describe(double.class).getActualName(), is(double.class.getName())); assertThat(describe(Object[].class).getActualName(), is(Object.class.getName() + "[]")); assertThat(describe(SampleClass[].class).getActualName(), is(SampleClass.class.getName() + "[]")); assertThat(describe(Object[][].class).getActualName(), is(Object.class.getName() + "[][]")); assertThat(describe(boolean[].class).getActualName(), is(boolean.class.getName() + "[]")); assertThat(describe(byte[].class).getActualName(), is(byte.class.getName() + "[]")); assertThat(describe(short[].class).getActualName(), is(short.class.getName() + "[]")); assertThat(describe(char[].class).getActualName(), is(char.class.getName() + "[]")); assertThat(describe(int[].class).getActualName(), is(int.class.getName() + "[]")); assertThat(describe(long[].class).getActualName(), is(long.class.getName() + "[]")); assertThat(describe(float[].class).getActualName(), is(float.class.getName() + "[]")); assertThat(describe(double[].class).getActualName(), is(double.class.getName() + "[]")); } @Test public void testDescriptor() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).getDescriptor(), is(Type.getDescriptor(type))); } } @Test public void testModifiers() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).getModifiers(), is(type.getModifiers())); } } @Test public void testDeclaringType() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).getDeclaringType(), type.getDeclaringClass() == null ? nullValue(TypeDescription.class) : is((TypeDescription) new TypeDescription.ForLoadedType(type.getDeclaringClass()))); } } @Test public void testEnclosingMethod() throws Exception { for (Class<?> type : standardTypes) { Matcher<MethodDescription> matcher; if (type.getEnclosingMethod() != null) { matcher = CoreMatchers.<MethodDescription>is(new MethodDescription.ForLoadedMethod(type.getEnclosingMethod())); } else if (type.getEnclosingConstructor() != null) { matcher = CoreMatchers.<MethodDescription>is(new MethodDescription.ForLoadedConstructor(type.getEnclosingConstructor())); } else { matcher = nullValue(MethodDescription.class); } assertThat(describe(type).getEnclosingMethod(), matcher); } } @Test public void testEnclosingType() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).getEnclosingType(), type.getEnclosingClass() == null ? nullValue(TypeDescription.class) : is((TypeDescription) new TypeDescription.ForLoadedType(type.getEnclosingClass()))); } } @Test public void testHashCode() throws Exception { assertThat(describe(SampleClass.class).hashCode(), is(SampleClass.class.getName().hashCode())); assertThat(describe(SampleInterface.class).hashCode(), is(SampleInterface.class.getName().hashCode())); assertThat(describe(SampleAnnotation.class).hashCode(), is(SampleAnnotation.class.getName().hashCode())); assertThat(describe(SampleClass.class).hashCode(), is(describe(SampleClass.class).hashCode())); assertThat(describe(SampleClass.class).hashCode(), not(describe(SampleInterface.class).hashCode())); assertThat(describe(SampleClass.class).hashCode(), not(describe(SampleAnnotation.class).hashCode())); assertThat(describe(Object[].class).hashCode(), is(describe(Object[].class).hashCode())); assertThat(describe(Object[].class).hashCode(), not(describe(Object.class).hashCode())); assertThat(describe(void.class).hashCode(), is(void.class.getName().hashCode())); } @Test public void testEquals() throws Exception { TypeDescription identical = describe(SampleClass.class); assertThat(identical, is(identical)); TypeDescription equalFirst = mock(TypeDescription.class); when(equalFirst.getSort()).thenReturn(TypeDefinition.Sort.NON_GENERIC); when(equalFirst.asErasure()).thenReturn(equalFirst); when(equalFirst.getName()).thenReturn(SampleClass.class.getName()); assertThat(describe(SampleClass.class), is(equalFirst)); assertThat(describe(SampleClass.class), not(describe(SampleInterface.class))); assertThat(describe(SampleClass.class), not((TypeDescription) new TypeDescription.ForLoadedType(SampleInterface.class))); TypeDefinition nonRawType = mock(TypeDescription.Generic.class); when(nonRawType.getSort()).thenReturn(TypeDefinition.Sort.VARIABLE); assertThat(describe(SampleClass.class), not(nonRawType)); assertThat(describe(SampleClass.class), not(new Object())); assertThat(describe(SampleClass.class), not(equalTo(null))); assertThat(describe(Object[].class), is((TypeDescription) new TypeDescription.ForLoadedType(Object[].class))); assertThat(describe(Object[].class), not(TypeDescription.OBJECT)); } @Test public void testIsInstance() throws Exception { assertThat(describe(SampleClass.class).isInstance(new SampleClass()), is(true)); assertThat(describe(SampleClass.class).isInstance(new Object()), is(false)); assertThat(describe(SampleInterface.class).isInstance(new SampleInterfaceImplementation()), is(true)); assertThat(describe(Object[].class).isInstance(new Object[0]), is(true)); assertThat(describe(Object[].class).isInstance(new Object()), is(false)); } @Test public void testPackage() throws Exception { assertThat(describe(SampleClass.class).getPackage(), is((PackageDescription) new PackageDescription.ForLoadedPackage(SampleClass.class.getPackage()))); assertThat(describe(Object.class).getPackage(), is((PackageDescription) new PackageDescription.ForLoadedPackage(Object.class.getPackage()))); assertThat(describe(Object[].class).getPackage(), nullValue(PackageDescription.class)); } @Test public void testActualModifiers() throws Exception { assertThat(describe(SampleClass.class).getActualModifiers(true), is(SampleClass.class.getModifiers() | Opcodes.ACC_SUPER)); assertThat(describe(SampleClass.class).getActualModifiers(false), is(SampleClass.class.getModifiers())); assertThat(describe(SampleInterface.class).getActualModifiers(true), is((SampleInterface.class.getModifiers() & ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC) | Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER))); assertThat(describe(SampleInterface.class).getActualModifiers(false), is((SampleInterface.class.getModifiers() & ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC) | Opcodes.ACC_PUBLIC))); assertThat(describe(SampleAnnotation.class).getActualModifiers(true), is((SampleAnnotation.class.getModifiers() & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)) | Opcodes.ACC_SUPER)); assertThat(describe(SampleAnnotation.class).getActualModifiers(false), is((SampleAnnotation.class.getModifiers() & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)))); assertThat(describe(SamplePackagePrivate.class).getActualModifiers(true), is((SamplePackagePrivate.class.getModifiers() & ~(Opcodes.ACC_STATIC)) | Opcodes.ACC_SUPER)); assertThat(describe(SamplePackagePrivate.class).getActualModifiers(false), is((SamplePackagePrivate.class.getModifiers() & ~(Opcodes.ACC_STATIC)))); } @Test public void testActualModifiersDeprecation() throws Exception { assertThat(describe(EnclosingType.DEPRECATED).getActualModifiers(false), is(Opcodes.ACC_DEPRECATED)); assertThat(describe(EnclosingType.DEPRECATED).getActualModifiers(true), is(Opcodes.ACC_DEPRECATED | Opcodes.ACC_SUPER)); } @Test public void testSuperClass() throws Exception { assertThat(describe(Object.class).getSuperClass(), nullValue(TypeDescription.Generic.class)); assertThat(describe(SampleInterface.class).getSuperClass(), nullValue(TypeDescription.Generic.class)); assertThat(describe(SampleAnnotation.class).getSuperClass(), nullValue(TypeDescription.Generic.class)); assertThat(describe(void.class).getSuperClass(), nullValue(TypeDescription.Generic.class)); assertThat(describe(SampleClass.class).getSuperClass(), is(TypeDescription.Generic.OBJECT)); assertThat(describe(SampleIndirectInterfaceImplementation.class).getSuperClass(), is((TypeDefinition) new TypeDescription.ForLoadedType(SampleInterfaceImplementation.class))); assertThat(describe(Object[].class).getSuperClass(), is(TypeDescription.Generic.OBJECT)); } @Test public void testInterfaces() throws Exception { assertThat(describe(Object.class).getInterfaces(), is((TypeList.Generic) new TypeList.Generic.Empty())); assertThat(describe(SampleInterface.class).getInterfaces(), is((TypeList.Generic) new TypeList.Generic.Empty())); assertThat(describe(SampleAnnotation.class).getInterfaces(), is((TypeList.Generic) new TypeList.Generic.ForLoadedTypes(Annotation.class))); assertThat(describe(SampleInterfaceImplementation.class).getInterfaces(), is((TypeList.Generic) new TypeList.Generic.ForLoadedTypes(SampleInterface.class))); assertThat(describe(SampleIndirectInterfaceImplementation.class).getInterfaces(), is((TypeList.Generic) new TypeList.Generic.Empty())); assertThat(describe(SampleTransitiveInterfaceImplementation.class).getInterfaces(), is((TypeList.Generic) new TypeList.Generic.ForLoadedTypes(SampleTransitiveInterface.class))); assertThat(describe(Object[].class).getInterfaces(), is((TypeList.Generic) new TypeList.Generic.ForLoadedTypes(Cloneable.class, Serializable.class))); } @Test public void testToString() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).toString(), is(type.toString())); } } @Test public void testIsAssignable() throws Exception { assertThat(describe(Object.class).isAssignableTo(Object.class), is(true)); assertThat(describe(Object.class).isAssignableFrom(Object.class), is(true)); assertThat(describe(Object[].class).isAssignableTo(Object.class), is(true)); assertThat(describe(Object.class).isAssignableFrom(Object[].class), is(true)); assertThat(describe(Object[].class).isAssignableTo(Serializable.class), is(true)); assertThat(describe(Serializable.class).isAssignableFrom(Object[].class), is(true)); assertThat(describe(Object[].class).isAssignableTo(Cloneable.class), is(true)); assertThat(describe(Cloneable.class).isAssignableFrom(Object[].class), is(true)); assertThat(describe(String[].class).isAssignableTo(Object[].class), is(true)); assertThat(describe(Object[].class).isAssignableFrom(String[].class), is(true)); assertThat(describe(Object[].class).isAssignableFrom(String[][].class), is(true)); assertThat(describe(String[][].class).isAssignableTo(Object[].class), is(true)); assertThat(describe(String[].class).isAssignableFrom(String[][].class), is(false)); assertThat(describe(String[][].class).isAssignableTo(String[].class), is(false)); assertThat(describe(Cloneable[].class).isAssignableFrom(String[].class), is(false)); assertThat(describe(String[].class).isAssignableTo(Cloneable[].class), is(false)); assertThat(describe(Foo[].class).isAssignableFrom(String[].class), is(false)); assertThat(describe(String[].class).isAssignableTo(Foo[].class), is(false)); assertThat(describe(int.class).isAssignableTo(int.class), is(true)); assertThat(describe(int.class).isAssignableFrom(int.class), is(true)); assertThat(describe(void.class).isAssignableTo(void.class), is(true)); assertThat(describe(void.class).isAssignableFrom(void.class), is(true)); assertThat(describe(SampleInterfaceImplementation.class).isAssignableTo(SampleInterface.class), is(true)); assertThat(describe(SampleInterface.class).isAssignableFrom(SampleInterfaceImplementation.class), is(true)); assertThat(describe(SampleTransitiveInterfaceImplementation.class).isAssignableTo(SampleInterface.class), is(true)); assertThat(describe(SampleInterface.class).isAssignableFrom(SampleTransitiveInterfaceImplementation.class), is(true)); assertThat(describe(SampleInterface.class).isAssignableTo(Object.class), is(true)); assertThat(describe(Object.class).isAssignableFrom(SampleInterface.class), is(true)); assertThat(describe(SampleInterfaceImplementation.class).isAssignableTo(SampleClass.class), is(false)); assertThat(describe(SampleClass.class).isAssignableFrom(SampleInterfaceImplementation.class), is(false)); assertThat(describe(SampleInterfaceImplementation.class).isAssignableTo(boolean.class), is(false)); assertThat(describe(boolean.class).isAssignableFrom(SampleInterfaceImplementation.class), is(false)); assertThat(describe(boolean.class).isAssignableTo(Object.class), is(false)); assertThat(describe(Object.class).isAssignableFrom(boolean.class), is(false)); assertThat(describe(boolean[].class).isAssignableTo(Object.class), is(true)); assertThat(describe(Object.class).isAssignableFrom(boolean[].class), is(true)); assertThat(describe(boolean[].class).isAssignableTo(Object[].class), is(false)); assertThat(describe(Object[].class).isAssignableFrom(boolean[].class), is(false)); } @Test public void testIsAssignableClassLoader() throws Exception { ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassFileExtraction.of(SimpleType.class), ByteArrayClassLoader.PersistenceHandler.MANIFEST); Class<?> otherSimpleType = classLoader.loadClass(SimpleType.class.getName()); assertThat(describe(SimpleType.class).isAssignableFrom(describe(otherSimpleType)), is(true)); assertThat(describe(SimpleType.class).isAssignableTo(describe(otherSimpleType)), is(true)); assertThat(describe(Object.class).isAssignableFrom(describe(otherSimpleType)), is(true)); assertThat(describe(otherSimpleType).isAssignableTo(describe(Object.class)), is(true)); } @Test public void testIsVisible() throws Exception { assertThat(describe(SampleClass.class).isVisibleTo(new TypeDescription.ForLoadedType(SampleInterface.class)), is(true)); assertThat(describe(SamplePackagePrivate.class).isVisibleTo(new TypeDescription.ForLoadedType(SampleClass.class)), is(true)); assertThat(describe(SampleInterface.class).isVisibleTo(new TypeDescription.ForLoadedType(SampleClass.class)), is(true)); assertThat(describe(SampleAnnotation.class).isVisibleTo(new TypeDescription.ForLoadedType(SampleClass.class)), is(true)); assertThat(describe(SamplePackagePrivate.class).isVisibleTo(TypeDescription.OBJECT), is(false)); assertThat(describe(SampleInterface.class).isVisibleTo(TypeDescription.OBJECT), is(true)); assertThat(describe(SampleAnnotation.class).isVisibleTo(TypeDescription.OBJECT), is(false)); assertThat(describe(int.class).isVisibleTo(TypeDescription.OBJECT), is(true)); assertThat(describe(SampleInterface[].class).isVisibleTo(TypeDescription.OBJECT), is(true)); assertThat(describe(SamplePackagePrivate[].class).isVisibleTo(TypeDescription.OBJECT), is(false)); } @Test public void testAnnotations() throws Exception { assertAnnotations(SampleClass.class); assertAnnotations(SampleInterface.class); assertAnnotations(SampleClassInherited.class); assertAnnotations(SampleClassInheritedOverride.class); } private void assertAnnotations(Class<?> type) { assertThat(describe(type).getDeclaredAnnotations(), hasItems(new AnnotationList.ForLoadedAnnotations(type.getDeclaredAnnotations()) .toArray(new AnnotationDescription[type.getDeclaredAnnotations().length]))); assertThat(describe(type).getDeclaredAnnotations().size(), is(type.getDeclaredAnnotations().length)); assertThat(describe(type).getInheritedAnnotations(), hasItems(new AnnotationList.ForLoadedAnnotations(type.getAnnotations()) .toArray(new AnnotationDescription[type.getAnnotations().length]))); assertThat(describe(type).getInheritedAnnotations().size(), is(type.getAnnotations().length)); } @Test public void testDeclaredTypes() throws Exception { assertThat(describe(SampleClass.class).getDeclaredTypes().size(), is(0)); assertThat(describe(AbstractTypeDescriptionTest.class).getDeclaredTypes(), is((TypeList) new TypeList.ForLoadedTypes(AbstractTypeDescriptionTest.class.getDeclaredClasses()))); } @Test public void testComponentType() throws Exception { assertThat(describe(Object.class).getComponentType(), nullValue(Object.class)); assertThat(describe(Object[].class).getComponentType(), is(describe(Object.class))); } @Test public void testWrapperType() throws Exception { assertThat(describe(Object.class).isPrimitiveWrapper(), is(false)); assertThat(describe(Boolean.class).isPrimitiveWrapper(), is(true)); assertThat(describe(Byte.class).isPrimitiveWrapper(), is(true)); assertThat(describe(Short.class).isPrimitiveWrapper(), is(true)); assertThat(describe(Character.class).isPrimitiveWrapper(), is(true)); assertThat(describe(Integer.class).isPrimitiveWrapper(), is(true)); assertThat(describe(Long.class).isPrimitiveWrapper(), is(true)); assertThat(describe(Float.class).isPrimitiveWrapper(), is(true)); assertThat(describe(Double.class).isPrimitiveWrapper(), is(true)); assertThat(describe(Void.class).isPrimitiveWrapper(), is(false)); } @Test public void testConstantPool() throws Exception { assertThat(describe(Object.class).isConstantPool(), is(false)); assertThat(describe(boolean.class).isConstantPool(), is(false)); assertThat(describe(int.class).isConstantPool(), is(true)); assertThat(describe(Integer.class).isConstantPool(), is(false)); assertThat(describe(String.class).isConstantPool(), is(true)); assertThat(describe(Class.class).isConstantPool(), is(true)); } @Test public void testGenericType() throws Exception { assertThat(describe(SampleGenericType.class).getTypeVariables(), is(new TypeDescription.ForLoadedType(SampleGenericType.class).getTypeVariables())); assertThat(describe(SampleGenericType.class).getSuperClass(), is(new TypeDescription.ForLoadedType(SampleGenericType.class).getSuperClass())); assertThat(describe(SampleGenericType.class).getInterfaces(), is(new TypeDescription.ForLoadedType(SampleGenericType.class).getInterfaces())); } @Test public void testHierarchyIteration() throws Exception { Iterator<TypeDefinition> iterator = describe(Traversal.class).iterator(); assertThat(iterator.hasNext(), is(true)); assertThat(iterator.next(), is((TypeDefinition) new TypeDescription.ForLoadedType(Traversal.class))); assertThat(iterator.hasNext(), is(true)); assertThat(iterator.next(), is((TypeDefinition) TypeDescription.OBJECT)); assertThat(iterator.hasNext(), is(false)); } @Test(expected = NoSuchElementException.class) public void testHierarchyEnds() throws Exception { Iterator<TypeDefinition> iterator = describe(Object.class).iterator(); assertThat(iterator.hasNext(), is(true)); assertThat(iterator.next(), is((TypeDefinition) TypeDescription.OBJECT)); assertThat(iterator.hasNext(), is(false)); iterator.next(); } @Test(expected = GenericSignatureFormatError.class) public void testMalformedTypeSignature() throws Exception { TypeDescription typeDescription = describe(SignatureMalformer.malform(MalformedBase.class)); assertThat(typeDescription.getInterfaces().size(), is(1)); typeDescription.getInterfaces().getOnly().getSort(); } @Test(expected = GenericSignatureFormatError.class) public void testMalformedFieldSignature() throws Exception { TypeDescription typeDescription = describe(SignatureMalformer.malform(MalformedBase.class)); assertThat(typeDescription.getDeclaredFields().size(), is(1)); typeDescription.getDeclaredFields().getOnly().getType().getSort(); } @Test(expected = GenericSignatureFormatError.class) public void testMalformedMethodSignature() throws Exception { TypeDescription typeDescription = describe(SignatureMalformer.malform(MalformedBase.class)); assertThat(typeDescription.getDeclaredMethods().filter(isMethod()).size(), is(1)); typeDescription.getDeclaredMethods().filter(isMethod()).getOnly().getReturnType().getSort(); } @Test public void testRepresents() throws Exception { assertThat(describe(Object.class).represents(Object.class), is(true)); assertThat(describe(Object.class).represents(Serializable.class), is(false)); assertThat(describe(List.class).represents(SimpleParameterizedType.class.getDeclaredField(FOO).getGenericType()), is(false)); } @Test public void testNonAvailableAnnotations() throws Exception { TypeDescription typeDescription = describe(new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassFileExtraction.of(MissingAnnotations.class), ByteArrayClassLoader.PersistenceHandler.MANIFEST).loadClass(MissingAnnotations.class.getName())); assertThat(typeDescription.getDeclaredAnnotations().isAnnotationPresent(SampleAnnotation.class), is(false)); assertThat(typeDescription.getDeclaredFields().getOnly().getDeclaredAnnotations().isAnnotationPresent(SampleAnnotation.class), is(false)); assertThat(typeDescription.getDeclaredMethods().filter(isMethod()).getOnly().getDeclaredAnnotations().isAnnotationPresent(SampleAnnotation.class), is(false)); } @Test public void testIsPackageDescription() throws Exception { assertThat(describe(Class.forName(Sample.class.getPackage().getName() + "." + PackageDescription.PACKAGE_CLASS_NAME)).isPackageType(), is(true)); assertThat(describe(Object.class).isPackageType(), is(false)); } @Test public void testEnclosingSource() throws Exception { assertThat(describe(SampleClass.class).getEnclosingSource(), is((TypeVariableSource) describe(AbstractTypeDescriptionTest.class))); assertThat(describe(Traversal.class).getEnclosingSource(), nullValue(TypeVariableSource.class)); } @Test public void testInMethodType() throws Exception { assertThat(describe(inMethodClass()).getEnclosingMethod(), is((TypeVariableSource) new MethodDescription.ForLoadedMethod(AbstractTypeDescriptionTest.class.getDeclaredMethod("inMethodClass")))); assertThat(describe(inMethodClass()).getEnclosingSource(), is((TypeVariableSource) new MethodDescription.ForLoadedMethod(AbstractTypeDescriptionTest.class.getDeclaredMethod("inMethodClass")))); } @Test public void testEnclosingAndDeclaringType() throws Exception { assertThat(describe(SampleClass.class).getEnclosingType(), is(describe(AbstractTypeDescriptionTest.class))); assertThat(describe(SampleClass.class).getDeclaringType(), is(describe(AbstractTypeDescriptionTest.class))); Class<?> anonymousType = new Object() { /* empty */ }.getClass(); assertThat(describe(anonymousType).getEnclosingType(), is(describe(AbstractTypeDescriptionTest.class))); assertThat(describe(anonymousType).getDeclaringType(), nullValue(TypeDescription.class)); } @Test public void testIsGenerified() throws Exception { assertThat(describe(GenericSample.class).isGenerified(), is(true)); assertThat(describe(GenericSample.Inner.class).isGenerified(), is(true)); assertThat(describe(GenericSample.Nested.class).isGenerified(), is(false)); assertThat(describe(GenericSample.NestedInterface.class).isGenerified(), is(false)); assertThat(describe(Object.class).isGenerified(), is(false)); } @Test public void testGetSegmentCount() throws Exception { assertThat(describe(GenericSample.class).getSegmentCount(), is(0)); assertThat(describe(GenericSample.Inner.class).getSegmentCount(), is(1)); assertThat(describe(GenericSample.Nested.class).getSegmentCount(), is(0)); assertThat(describe(GenericSample.NestedInterface.class).getSegmentCount(), is(0)); assertThat(describe(Object.class).getSegmentCount(), is(0)); } @Test public void testBoxed() throws Exception { assertThat(describe(boolean.class).asBoxed(), is(describe(Boolean.class))); assertThat(describe(byte.class).asBoxed(), is(describe(Byte.class))); assertThat(describe(short.class).asBoxed(), is(describe(Short.class))); assertThat(describe(char.class).asBoxed(), is(describe(Character.class))); assertThat(describe(int.class).asBoxed(), is(describe(Integer.class))); assertThat(describe(long.class).asBoxed(), is(describe(Long.class))); assertThat(describe(float.class).asBoxed(), is(describe(Float.class))); assertThat(describe(double.class).asBoxed(), is(describe(Double.class))); assertThat(describe(void.class).asBoxed(), is(describe(void.class))); assertThat(describe(Object.class).asBoxed(), is(describe(Object.class))); } @Test public void testUnboxed() throws Exception { assertThat(describe(Boolean.class).asUnboxed(), is(describe(boolean.class))); assertThat(describe(Byte.class).asUnboxed(), is(describe(byte.class))); assertThat(describe(Short.class).asUnboxed(), is(describe(short.class))); assertThat(describe(Character.class).asUnboxed(), is(describe(char.class))); assertThat(describe(Integer.class).asUnboxed(), is(describe(int.class))); assertThat(describe(Long.class).asUnboxed(), is(describe(long.class))); assertThat(describe(Float.class).asUnboxed(), is(describe(float.class))); assertThat(describe(Double.class).asUnboxed(), is(describe(double.class))); assertThat(describe(Void.class).asUnboxed(), is(describe(Void.class))); assertThat(describe(Object.class).asUnboxed(), is(describe(Object.class))); } private Class<?> inMethodClass() { class InMethod { /* empty */ } return InMethod.class; } protected interface SampleInterface { /* empty */ } @Retention(RetentionPolicy.RUNTIME) private @interface SampleAnnotation { /* empty */ } @Inherited @Retention(RetentionPolicy.RUNTIME) private @interface OtherAnnotation { String value(); } public interface SampleTransitiveInterface extends SampleInterface { /* empty */ } private static class SignatureMalformer extends ClassVisitor { private static final String FOO = "foo"; public SignatureMalformer(ClassVisitor classVisitor) { super(Opcodes.ASM5, classVisitor); } public static Class<?> malform(Class<?> type) throws Exception { ClassReader classReader = new ClassReader(type.getName()); ClassWriter classWriter = new ClassWriter(classReader, 0); classReader.accept(new SignatureMalformer(classWriter), 0); ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, Collections.singletonMap(type.getName(), classWriter.toByteArray()), ByteArrayClassLoader.PersistenceHandler.MANIFEST); return classLoader.loadClass(type.getName()); } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, access, name, FOO, superName, interfaces); } @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { return super.visitField(access, name, desc, FOO, value); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { return super.visitMethod(access, name, desc, FOO, exceptions); } } @SuppressWarnings("unused") public abstract static class MalformedBase<T> implements Callable<T> { Callable<T> foo; abstract Callable<T> foo(); } static class SamplePackagePrivate { /* empty */ } public static class SampleInterfaceImplementation implements SampleInterface { /* empty */ } public static class SampleIndirectInterfaceImplementation extends SampleInterfaceImplementation { /* empty */ } public static class SampleTransitiveInterfaceImplementation implements SampleTransitiveInterface { /* empty */ } public static class SampleGenericType<T extends ArrayList<T> & Callable<T>, S extends Callable<?>, U extends Callable<? extends Callable<U>>, V extends ArrayList<? super ArrayList<V>>, W extends Callable<W[]>> extends ArrayList<T> implements Callable<T> { @Override public T call() throws Exception { return null; } } public static class Traversal { /* empty */ } @SampleAnnotation @OtherAnnotation(FOO) public class SampleClass { /* empty */ } public class SampleClassInherited extends SampleClass { /* empty */ } @OtherAnnotation(BAR) public class SampleClassInheritedOverride extends SampleClass { /* empty */ } @SuppressWarnings("unused") public static class InnerInnerClass { public static class Foo { /* empty */ } } @SampleAnnotation public static class MissingAnnotations { @SampleAnnotation Void foo; @SampleAnnotation void foo(@SampleAnnotation Void foo) { /* empty */ } } private static class GenericSample<T> { static class Nested { /* empty */ } class Inner { /* empty */ } interface NestedInterface { /* empty */ } } }