package net.bytebuddy.dynamic.scaffold.inline;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.field.FieldList;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.modifier.MethodManifestation;
import net.bytebuddy.description.modifier.TypeManifestation;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.AbstractDynamicTypeBuilderTest;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.Transformer;
import net.bytebuddy.dynamic.loading.ByteArrayClassLoader;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.loading.PackageDefinitionStrategy;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.MethodCall;
import net.bytebuddy.implementation.StubMethod;
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
import net.bytebuddy.implementation.bytecode.constant.TextConstant;
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.pool.TypePool;
import net.bytebuddy.test.scope.GenericType;
import net.bytebuddy.test.utility.ClassFileExtraction;
import net.bytebuddy.test.utility.JavaVersionRule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.LocalVariablesSorter;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.*;
import java.lang.reflect.Type;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import static junit.framework.TestCase.assertEquals;
import static net.bytebuddy.matcher.ElementMatchers.isTypeInitializer;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
public abstract class AbstractDynamicTypeBuilderForInliningTest extends AbstractDynamicTypeBuilderTest {
private static final String FOO = "foo", BAR = "bar";
private static final int QUX = 42;
private static final String PARAMETER_NAME_CLASS = "net.bytebuddy.test.precompiled.ParameterNames";
private static final String SIMPLE_TYPE_ANNOTATED = "net.bytebuddy.test.precompiled.SimpleTypeAnnotatedType";
private static final String TYPE_VARIABLE_NAME = "net.bytebuddy.test.precompiled.TypeAnnotation", VALUE = "value";
@Rule
public MethodRule javaVersionRule = new JavaVersionRule();
private TypePool typePool;
@Before
public void setUp() throws Exception {
super.setUp();
typePool = TypePool.Default.ofClassPath();
}
@After
public void tearDown() throws Exception {
typePool.clear();
}
protected abstract DynamicType.Builder<?> create(Class<?> type);
protected abstract DynamicType.Builder<?> create(TypeDescription typeDescription, ClassFileLocator classFileLocator);
protected abstract DynamicType.Builder<?> createDisabledContext();
protected abstract DynamicType.Builder<?> createDisabledRetention(Class<?> annotatedClass);
@Test
public void testTypeInitializerRetention() throws Exception {
Class<?> type = create(Qux.class)
.invokable(isTypeInitializer()).intercept(MethodCall.invoke(Qux.class.getDeclaredMethod("invoke")))
.make()
.load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
assertThat(type.getDeclaredConstructor().newInstance(), notNullValue(Object.class));
assertThat(type.getDeclaredField(FOO).get(null), is((Object) FOO));
assertThat(type.getDeclaredField(BAR).get(null), is((Object) BAR));
}
@Test
public void testDefaultValue() throws Exception {
Class<?> dynamicType = create(Baz.class)
.method(named(FOO)).defaultValue(FOO, String.class)
.make()
.load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
assertThat(dynamicType.getDeclaredMethods().length, is(1));
assertThat(dynamicType.getDeclaredMethod(FOO).getDefaultValue(), is((Object) FOO));
}
@Test
@JavaVersionRule.Enforce(8)
public void testParameterMetaDataRetention() throws Exception {
Class<?> dynamicType = create(Class.forName(PARAMETER_NAME_CLASS))
.method(named(FOO)).intercept(StubMethod.INSTANCE)
.make()
.load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
Class<?> executable = Class.forName("java.lang.reflect.Executable");
Method getParameters = executable.getDeclaredMethod("getParameters");
Class<?> parameter = Class.forName("java.lang.reflect.Parameter");
Method getName = parameter.getDeclaredMethod("getName");
Method getModifiers = parameter.getDeclaredMethod("getModifiers");
Method first = dynamicType.getDeclaredMethod("foo", String.class, long.class, int.class);
Object[] methodParameter = (Object[]) getParameters.invoke(first);
assertThat(getName.invoke(methodParameter[0]), is((Object) "first"));
assertThat(getName.invoke(methodParameter[1]), is((Object) "second"));
assertThat(getName.invoke(methodParameter[2]), is((Object) "third"));
assertThat(getModifiers.invoke(methodParameter[0]), is((Object) Opcodes.ACC_FINAL));
assertThat(getModifiers.invoke(methodParameter[1]), is((Object) 0));
assertThat(getModifiers.invoke(methodParameter[2]), is((Object) 0));
}
@Test
public void testGenericType() throws Exception {
ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassFileExtraction.of(GenericType.class));
Class<?> dynamicType = create(GenericType.Inner.class)
.method(named(FOO)).intercept(StubMethod.INSTANCE)
.make()
.load(classLoader, ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
assertThat(dynamicType.getTypeParameters().length, is(2));
assertThat(dynamicType.getTypeParameters()[0].getName(), is("T"));
assertThat(dynamicType.getTypeParameters()[0].getBounds().length, is(1));
assertThat(dynamicType.getTypeParameters()[0].getBounds()[0], instanceOf(Class.class));
assertThat(dynamicType.getTypeParameters()[0].getBounds()[0], is((Type) String.class));
assertThat(dynamicType.getTypeParameters()[1].getName(), is("S"));
assertThat(dynamicType.getTypeParameters()[1].getBounds().length, is(1));
assertThat(dynamicType.getTypeParameters()[1].getBounds()[0], is((Type) dynamicType.getTypeParameters()[0]));
assertThat(dynamicType.getGenericSuperclass(), instanceOf(ParameterizedType.class));
assertThat(((ParameterizedType) dynamicType.getGenericSuperclass()).getActualTypeArguments().length, is(1));
assertThat(((ParameterizedType) dynamicType.getGenericSuperclass()).getActualTypeArguments()[0], instanceOf(ParameterizedType.class));
ParameterizedType superClass = (ParameterizedType) ((ParameterizedType) dynamicType.getGenericSuperclass()).getActualTypeArguments()[0];
assertThat(superClass.getActualTypeArguments().length, is(2));
assertThat(superClass.getActualTypeArguments()[0], is((Type) dynamicType.getTypeParameters()[0]));
assertThat(superClass.getActualTypeArguments()[1], is((Type) dynamicType.getTypeParameters()[1]));
assertThat(superClass.getOwnerType(), instanceOf(ParameterizedType.class));
assertThat(((ParameterizedType) superClass.getOwnerType()).getRawType(), instanceOf(Class.class));
assertThat(((Class<?>) ((ParameterizedType) superClass.getOwnerType()).getRawType()).getName(), is(GenericType.class.getName()));
assertThat(((ParameterizedType) superClass.getOwnerType()).getActualTypeArguments().length, is(1));
assertThat(((ParameterizedType) superClass.getOwnerType()).getActualTypeArguments()[0],
is((Type) ((Class<?>) ((ParameterizedType) superClass.getOwnerType()).getRawType()).getTypeParameters()[0]));
assertThat(dynamicType.getGenericInterfaces().length, is(1));
assertThat(dynamicType.getGenericInterfaces()[0], instanceOf(ParameterizedType.class));
assertThat(((ParameterizedType) dynamicType.getGenericInterfaces()[0]).getActualTypeArguments()[0], instanceOf(ParameterizedType.class));
assertThat(((ParameterizedType) dynamicType.getGenericInterfaces()[0]).getRawType(), is((Type) Callable.class));
assertThat(((ParameterizedType) dynamicType.getGenericInterfaces()[0]).getOwnerType(), nullValue(Type.class));
assertThat(((ParameterizedType) ((ParameterizedType) dynamicType.getGenericInterfaces()[0]).getActualTypeArguments()[0])
.getActualTypeArguments().length, is(2));
ParameterizedType interfaceType = (ParameterizedType) ((ParameterizedType) dynamicType.getGenericInterfaces()[0]).getActualTypeArguments()[0];
assertThat(interfaceType.getRawType(), is((Type) Map.class));
assertThat(interfaceType.getActualTypeArguments().length, is(2));
assertThat(interfaceType.getActualTypeArguments()[0], instanceOf(WildcardType.class));
assertThat(((WildcardType) interfaceType.getActualTypeArguments()[0]).getUpperBounds().length, is(1));
assertThat(((WildcardType) interfaceType.getActualTypeArguments()[0]).getUpperBounds()[0], is((Type) Object.class));
assertThat(((WildcardType) interfaceType.getActualTypeArguments()[0]).getLowerBounds().length, is(1));
assertThat(((WildcardType) interfaceType.getActualTypeArguments()[0]).getLowerBounds()[0], is((Type) String.class));
assertThat(interfaceType.getActualTypeArguments()[1], instanceOf(WildcardType.class));
assertThat(((WildcardType) interfaceType.getActualTypeArguments()[1]).getUpperBounds().length, is(1));
assertThat(((WildcardType) interfaceType.getActualTypeArguments()[1]).getUpperBounds()[0], is((Type) String.class));
assertThat(((WildcardType) interfaceType.getActualTypeArguments()[1]).getLowerBounds().length, is(0));
Method foo = dynamicType.getDeclaredMethod(FOO, String.class);
assertThat(foo.getGenericReturnType(), instanceOf(ParameterizedType.class));
assertThat(((ParameterizedType) foo.getGenericReturnType()).getActualTypeArguments().length, is(1));
assertThat(((ParameterizedType) foo.getGenericReturnType()).getActualTypeArguments()[0], instanceOf(GenericArrayType.class));
assertThat(((GenericArrayType) ((ParameterizedType) foo.getGenericReturnType()).getActualTypeArguments()[0]).getGenericComponentType(),
is((Type) dynamicType.getTypeParameters()[0]));
assertThat(foo.getTypeParameters().length, is(2));
assertThat(foo.getTypeParameters()[0].getName(), is("V"));
assertThat(foo.getTypeParameters()[0].getBounds().length, is(1));
assertThat(foo.getTypeParameters()[0].getBounds()[0], is((Type) dynamicType.getTypeParameters()[0]));
assertThat(foo.getTypeParameters()[1].getName(), is("W"));
assertThat(foo.getTypeParameters()[1].getBounds().length, is(1));
assertThat(foo.getTypeParameters()[1].getBounds()[0], is((Type) Exception.class));
assertThat(foo.getGenericParameterTypes().length, is(1));
assertThat(foo.getGenericParameterTypes()[0], is((Type) foo.getTypeParameters()[0]));
assertThat(foo.getGenericExceptionTypes().length, is(1));
assertThat(foo.getGenericExceptionTypes()[0], is((Type) foo.getTypeParameters()[1]));
Method call = dynamicType.getDeclaredMethod("call");
assertThat(call.getGenericReturnType(), is((Type) interfaceType));
}
@Test
@SuppressWarnings("unchecked")
public void testBridgeMethodCreation() throws Exception {
Class<?> dynamicType = create(BridgeRetention.Inner.class)
.method(named(FOO)).intercept(new Implementation.Simple(new TextConstant(FOO), MethodReturn.REFERENCE))
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST)
.getLoaded();
assertEquals(String.class, dynamicType.getDeclaredMethod(FOO).getReturnType());
assertThat(dynamicType.getDeclaredMethod(FOO).getGenericReturnType(), is((Type) String.class));
BridgeRetention<String> bridgeRetention = (BridgeRetention<String>) dynamicType.getDeclaredConstructor().newInstance();
assertThat(bridgeRetention.foo(), is(FOO));
bridgeRetention.assertZeroCalls();
}
@Test
@SuppressWarnings("unchecked")
public void testBridgeMethodCreationForExistingBridgeMethod() throws Exception {
Class<?> dynamicType = create(CallSuperMethod.Inner.class)
.method(named(FOO)).intercept(net.bytebuddy.implementation.SuperMethodCall.INSTANCE)
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST)
.getLoaded();
assertThat(dynamicType.getDeclaredMethods().length, is(2));
assertEquals(String.class, dynamicType.getDeclaredMethod(FOO, String.class).getReturnType());
assertThat(dynamicType.getDeclaredMethod(FOO, String.class).getGenericReturnType(), is((Type) String.class));
assertThat(dynamicType.getDeclaredMethod(FOO, String.class).isBridge(), is(false));
assertEquals(Object.class, dynamicType.getDeclaredMethod(FOO, Object.class).getReturnType());
assertThat(dynamicType.getDeclaredMethod(FOO, Object.class).getGenericReturnType(), is((Type) Object.class));
assertThat(dynamicType.getDeclaredMethod(FOO, Object.class).isBridge(), is(true));
CallSuperMethod<String> callSuperMethod = (CallSuperMethod<String>) dynamicType.getDeclaredConstructor().newInstance();
assertThat(callSuperMethod.foo(FOO), is(FOO));
callSuperMethod.assertOnlyCall(FOO);
}
@Test
public void testBridgeMethodForAbstractMethod() throws Exception {
Class<?> dynamicType = create(AbstractGenericType.Inner.class)
.modifiers(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC)
.method(named(FOO)).withoutCode()
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST)
.getLoaded();
assertThat(dynamicType.getDeclaredMethods().length, is(2));
assertEquals(Void.class, dynamicType.getDeclaredMethod(FOO, Void.class).getReturnType());
assertThat(dynamicType.getDeclaredMethod(FOO, Void.class).getGenericReturnType(), is((Type) Void.class));
assertThat(dynamicType.getDeclaredMethod(FOO, Void.class).isBridge(), is(false));
assertThat(Modifier.isAbstract(dynamicType.getDeclaredMethod(FOO, Void.class).getModifiers()), is(true));
assertEquals(Object.class, dynamicType.getDeclaredMethod(FOO, Object.class).getReturnType());
assertThat(dynamicType.getDeclaredMethod(FOO, Object.class).getGenericReturnType(), is((Type) Object.class));
assertThat(dynamicType.getDeclaredMethod(FOO, Object.class).isBridge(), is(true));
assertThat(Modifier.isAbstract(dynamicType.getDeclaredMethod(FOO, Object.class).getModifiers()), is(false));
}
@Test
public void testVisibilityBridge() throws Exception {
ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER,
ClassFileExtraction.of(PackagePrivateVisibilityBridgeExtension.class, VisibilityBridge.class, FooBar.class));
Class<?> type = create(PackagePrivateVisibilityBridgeExtension.class)
.modifiers(Opcodes.ACC_PUBLIC)
.make()
.load(classLoader, ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
assertThat(type.getDeclaredConstructors().length, is(1));
Constructor<?> constructor = type.getDeclaredConstructor();
constructor.setAccessible(true);
assertThat(type.getDeclaredMethods().length, is(2));
Method foo = type.getDeclaredMethod(FOO, String.class);
foo.setAccessible(true);
assertThat(foo.isBridge(), is(true));
assertThat(foo.getDeclaredAnnotations().length, is(1));
assertThat(foo.getDeclaredAnnotations()[0].annotationType().getName(), is(FooBar.class.getName()));
assertThat(foo.invoke(constructor.newInstance(), BAR), is((Object) (FOO + BAR)));
assertThat(foo.getParameterAnnotations()[0].length, is(1));
assertThat(foo.getParameterAnnotations()[0][0].annotationType().getName(), is(FooBar.class.getName()));
assertThat(foo.invoke(constructor.newInstance(), BAR), is((Object) (FOO + BAR)));
Method bar = type.getDeclaredMethod(BAR, List.class);
bar.setAccessible(true);
assertThat(bar.isBridge(), is(true));
assertThat(bar.getDeclaredAnnotations().length, is(0));
List<?> list = new ArrayList<Object>();
assertThat(bar.invoke(constructor.newInstance(), list), sameInstance((Object) list));
assertThat(bar.getGenericReturnType(), instanceOf(Class.class));
assertThat(bar.getGenericParameterTypes()[0], instanceOf(Class.class));
assertThat(bar.getGenericExceptionTypes()[0], instanceOf(Class.class));
}
@Test
public void testNoVisibilityBridgeForNonPublicType() throws Exception {
ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER,
ClassFileExtraction.of(PackagePrivateVisibilityBridgeExtension.class, VisibilityBridge.class, FooBar.class));
Class<?> type = create(PackagePrivateVisibilityBridgeExtension.class)
.modifiers(0)
.make()
.load(classLoader, ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
assertThat(type.getDeclaredConstructors().length, is(1));
assertThat(type.getDeclaredMethods().length, is(0));
}
@Test
public void testNoVisibilityBridgeForInheritedType() throws Exception {
ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER,
ClassFileExtraction.of(PublicVisibilityBridgeExtension.class, VisibilityBridge.class, FooBar.class));
Class<?> type = new ByteBuddy().subclass(PublicVisibilityBridgeExtension.class)
.modifiers(Opcodes.ACC_PUBLIC)
.make()
.load(classLoader, ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
assertThat(type.getDeclaredConstructors().length, is(1));
assertThat(type.getDeclaredMethods().length, is(0));
}
@Test
public void testNoVisibilityBridgeForAbstractMethod() throws Exception {
ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER,
ClassFileExtraction.of(PackagePrivateVisibilityBridgeExtensionAbstractMethod.class, VisibilityBridgeAbstractMethod.class));
Class<?> type = create(PackagePrivateVisibilityBridgeExtensionAbstractMethod.class)
.modifiers(Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT)
.make()
.load(classLoader, ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
assertThat(type.getDeclaredConstructors().length, is(1));
assertThat(type.getDeclaredMethods().length, is(0));
}
@Test
public void testMethodTransformationExistingMethod() throws Exception {
Class<?> type = create(Transform.class)
.method(named(FOO))
.intercept(new Implementation.Simple(new TextConstant(FOO), MethodReturn.REFERENCE))
.transform(Transformer.ForMethod.withModifiers(MethodManifestation.FINAL))
.make()
.load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
Method foo = type.getDeclaredMethod(FOO);
assertThat(foo.invoke(type.getDeclaredConstructor().newInstance()), is((Object) FOO));
assertThat(foo.getModifiers(), is(Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC));
}
@Test
public void testFieldTransformationExistingField() throws Exception {
Class<?> type = create(Transform.class)
.field(named(FOO))
.transform(Transformer.ForField.withModifiers(Visibility.PUBLIC))
.make()
.load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
assertThat(type.getDeclaredField(FOO).getModifiers(), is(Opcodes.ACC_PUBLIC));
}
@Test
@SuppressWarnings("unchecked")
public void testReaderHint() throws Exception {
AsmVisitorWrapper asmVisitorWrapper = mock(AsmVisitorWrapper.class);
when(asmVisitorWrapper.wrap(any(TypeDescription.class),
any(ClassVisitor.class),
any(Implementation.Context.class),
any(TypePool.class),
any(FieldList.class),
any(MethodList.class),
anyInt(),
anyInt())).then(new Answer<ClassVisitor>() {
@Override
public ClassVisitor answer(InvocationOnMock invocationOnMock) throws Throwable {
return new ClassVisitor(Opcodes.ASM5, (ClassVisitor) invocationOnMock.getArguments()[1]) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new LocalVariablesSorter(access, desc, super.visitMethod(access, name, desc, signature, exceptions));
}
};
}
});
when(asmVisitorWrapper.mergeWriter(0)).thenReturn(ClassWriter.COMPUTE_MAXS);
when(asmVisitorWrapper.mergeReader(0)).thenReturn(ClassReader.EXPAND_FRAMES);
Class<?> type = create(StackMapFrames.class)
.visit(asmVisitorWrapper)
.make()
.load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
assertThat(type.getDeclaredMethod(FOO).invoke(type.getDeclaredConstructor().newInstance()), is((Object) BAR));
verify(asmVisitorWrapper).mergeWriter(0);
verify(asmVisitorWrapper).mergeReader(0);
verify(asmVisitorWrapper).wrap(any(TypeDescription.class),
any(ClassVisitor.class),
any(Implementation.Context.class),
any(TypePool.class),
any(FieldList.class),
any(MethodList.class),
anyInt(),
anyInt());
verifyNoMoreInteractions(asmVisitorWrapper);
}
@Test(expected = IllegalStateException.class)
public void testForbidTypeInitilizerInterception() throws Exception {
createDisabledContext()
.initializer(new ByteCodeAppender.Simple())
.make();
}
@Test
public void testDisabledAnnotationRetention() throws Exception {
Class<?> type = createDisabledRetention(Annotated.class)
.field(ElementMatchers.any()).annotateField(new Annotation[0])
.method(ElementMatchers.any()).intercept(StubMethod.INSTANCE)
.make()
.load(new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER,
ClassFileExtraction.of(SampleAnnotation.class)), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
@SuppressWarnings("unchecked")
Class<? extends Annotation> sampleAnnotation = (Class<? extends Annotation>) type.getClassLoader().loadClass(SampleAnnotation.class.getName());
assertThat(type.isAnnotationPresent(sampleAnnotation), is(true));
assertThat(type.getDeclaredField(FOO).isAnnotationPresent(sampleAnnotation), is(false));
assertThat(type.getDeclaredMethod(FOO, Void.class).isAnnotationPresent(sampleAnnotation), is(false));
assertThat(type.getDeclaredMethod(FOO, Void.class).getParameterAnnotations()[0].length, is(0));
}
@Test
public void testEnabledAnnotationRetention() throws Exception {
Class<?> type = create(Annotated.class)
.field(ElementMatchers.any()).annotateField(new Annotation[0])
.method(ElementMatchers.any()).intercept(StubMethod.INSTANCE)
.make()
.load(new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER,
ClassFileExtraction.of(SampleAnnotation.class)), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
@SuppressWarnings("unchecked")
Class<? extends Annotation> sampleAnnotation = (Class<? extends Annotation>) type.getClassLoader().loadClass(SampleAnnotation.class.getName());
assertThat(type.isAnnotationPresent(sampleAnnotation), is(true));
assertThat(type.getDeclaredField(FOO).isAnnotationPresent(sampleAnnotation), is(true));
assertThat(type.getDeclaredMethod(FOO, Void.class).isAnnotationPresent(sampleAnnotation), is(true));
assertThat(type.getDeclaredMethod(FOO, Void.class).getParameterAnnotations()[0].length, is(1));
assertThat(type.getDeclaredMethod(FOO, Void.class).getParameterAnnotations()[0][0].annotationType(), is((Object) sampleAnnotation));
}
@Test
@JavaVersionRule.Enforce(8)
@SuppressWarnings("unchecked")
public void testAnnotationTypeOnInterfaceType() throws Exception {
Class<? extends Annotation> typeAnnotationType = (Class<? extends Annotation>) Class.forName(TYPE_VARIABLE_NAME);
MethodDescription.InDefinedShape value = new TypeDescription.ForLoadedType(typeAnnotationType).getDeclaredMethods().filter(named(VALUE)).getOnly();
Class<?> type = create(Class.forName(SIMPLE_TYPE_ANNOTATED))
.merge(TypeManifestation.ABSTRACT)
.implement(TypeDescription.Generic.Builder.rawType(Callable.class)
.build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, QUX * 3).build()))
.make()
.load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST)
.getLoaded();
assertThat(type.getInterfaces().length, is(2));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveInterfaceType(type, 0).asList().size(), is(1));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveInterfaceType(type, 0).asList().ofType(typeAnnotationType)
.getValue(value).resolve(Integer.class), is(QUX * 2));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveInterfaceType(type, 1).asList().size(), is(1));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveInterfaceType(type, 1).asList().ofType(typeAnnotationType)
.getValue(value).resolve(Integer.class), is(QUX * 3));
}
@Test
@JavaVersionRule.Enforce(8)
@SuppressWarnings("unchecked")
public void testAnnotationTypeOnTypeVariableType() throws Exception {
Class<? extends Annotation> typeAnnotationType = (Class<? extends Annotation>) Class.forName(TYPE_VARIABLE_NAME);
MethodDescription.InDefinedShape value = new TypeDescription.ForLoadedType(typeAnnotationType).getDeclaredMethods().filter(named(VALUE)).getOnly();
Class<?> type = create(Class.forName(SIMPLE_TYPE_ANNOTATED))
.merge(TypeManifestation.ABSTRACT)
.typeVariable(BAR, TypeDescription.Generic.Builder.rawType(Callable.class)
.build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, QUX * 4).build()))
.annotateTypeVariable(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, QUX * 3).build())
.make()
.load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST)
.getLoaded();
assertThat(type.getTypeParameters().length, is(2));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[0]).asList().size(), is(1));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[0]).asList().ofType(typeAnnotationType)
.getValue(value).resolve(Integer.class), is(QUX));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[1]).asList().size(), is(1));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[1]).asList().ofType(typeAnnotationType)
.getValue(value).resolve(Integer.class), is(QUX * 3));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[1]).ofTypeVariableBoundType(0)
.asList().size(), is(1));
assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[1]).ofTypeVariableBoundType(0)
.asList().ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(QUX * 4));
}
public @interface Baz {
String foo();
}
@Retention(RetentionPolicy.RUNTIME)
public @interface FooBar {
/* empty */
}
public static class Qux {
public static final String foo;
public static String bar;
static {
foo = FOO;
}
public static void invoke() {
bar = BAR;
}
}
@SuppressWarnings("unused")
static class VisibilityBridge {
@FooBar
public String foo(@FooBar String value) {
return FOO + value;
}
public <T extends Exception> List<String> bar(List<String> value) throws T {
return value;
}
void qux() {
/* empty */
}
protected void baz() {
/* empty */
}
public final void foobar() {
/* empty */
}
}
static class PackagePrivateVisibilityBridgeExtension extends VisibilityBridge {
/* empty */
}
public static class PublicVisibilityBridgeExtension extends VisibilityBridge {
/* empty */
}
abstract static class VisibilityBridgeAbstractMethod {
public abstract void foo();
}
abstract static class PackagePrivateVisibilityBridgeExtensionAbstractMethod extends VisibilityBridgeAbstractMethod {
/* empty */
}
@SuppressWarnings("unused")
public static class Transform {
Void foo;
public String foo() {
return null;
}
}
public abstract static class AbstractGenericType<T> {
public abstract T foo(T t);
public abstract static class Inner extends AbstractGenericType<Void> {
/* empty */
}
}
public static class StackMapFrames {
public boolean foo;
public String foo() {
return foo
? FOO
: BAR;
}
}
@SampleAnnotation
@SuppressWarnings("unused")
public static class Annotated {
@SampleAnnotation
Void foo;
@SampleAnnotation
void foo(@SampleAnnotation Void v) {
/* empty */
}
}
@Retention(RetentionPolicy.RUNTIME)
public @interface SampleAnnotation {
/* empty */
}
}