package net.bytebuddy.dynamic; import net.bytebuddy.asm.AsmVisitorWrapper; import net.bytebuddy.description.annotation.AnnotationDescription; import net.bytebuddy.description.annotation.AnnotationValue; import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.field.FieldList; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.method.ParameterDescription; import net.bytebuddy.description.modifier.*; import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeVariableToken; import net.bytebuddy.dynamic.loading.ByteArrayClassLoader; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.dynamic.scaffold.InstrumentedType; import net.bytebuddy.implementation.*; import net.bytebuddy.implementation.bind.annotation.SuperCall; import net.bytebuddy.implementation.bytecode.ByteCodeAppender; import net.bytebuddy.implementation.bytecode.StackManipulation; import net.bytebuddy.implementation.bytecode.constant.NullConstant; import net.bytebuddy.implementation.bytecode.constant.TextConstant; import net.bytebuddy.implementation.bytecode.member.FieldAccess; import net.bytebuddy.implementation.bytecode.member.MethodReturn; import net.bytebuddy.pool.TypePool; import net.bytebuddy.test.utility.CallTraceable; import net.bytebuddy.test.utility.ClassFileExtraction; import net.bytebuddy.test.utility.JavaVersionRule; import net.bytebuddy.test.utility.MockitoRule; import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.*; import java.net.URL; import java.net.URLClassLoader; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; 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 AbstractDynamicTypeBuilderTest { private static final String FOO = "foo", BAR = "bar", QUX = "qux", TO_STRING = "toString"; private static final String TYPE_VARIABLE_NAME = "net.bytebuddy.test.precompiled.TypeAnnotation", VALUE = "value"; private static final int MODIFIERS = Opcodes.ACC_PUBLIC; private static final boolean BOOLEAN_VALUE = true; private static final int INTEGER_VALUE = 42; private static final long LONG_VALUE = 42L; private static final float FLOAT_VALUE = 42f; private static final double DOUBLE_VALUE = 42d; private static final String BOOLEAN_FIELD = "booleanField"; private static final String BYTE_FIELD = "byteField"; private static final String CHARACTER_FIELD = "characterField"; private static final String SHORT_FIELD = "shortField"; private static final String INTEGER_FIELD = "integerField"; private static final String LONG_FIELD = "longField"; private static final String FLOAT_FIELD = "floatField"; private static final String DOUBLE_FIELD = "doubleField"; private static final String STRING_FIELD = "stringField"; @Rule public TestRule mockitoRule = new MockitoRule(this); private Type list, fooVariable; protected abstract DynamicType.Builder<?> createPlain(); protected abstract DynamicType.Builder<?> createPlainWithoutValidation(); @Before public void setUp() throws Exception { list = Holder.class.getDeclaredField("list").getGenericType(); fooVariable = ((ParameterizedType) Holder.class.getDeclaredField("fooList").getGenericType()).getActualTypeArguments()[0]; } @Test public void testMethodDefinition() throws Exception { Class<?> type = createPlain() .defineMethod(FOO, Object.class, Visibility.PUBLIC) .throwing(Exception.class) .intercept(new Implementation.Simple(new TextConstant(FOO), MethodReturn.REFERENCE)) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); Method method = type.getDeclaredMethod(FOO); assertThat(method.getReturnType(), CoreMatchers.<Class<?>>is(Object.class)); assertThat(method.getExceptionTypes(), is(new Class<?>[]{Exception.class})); assertThat(method.getModifiers(), is(Modifier.PUBLIC)); assertThat(method.invoke(type.getDeclaredConstructor().newInstance()), is((Object) FOO)); } @Test public void testAbstractMethodDefinition() throws Exception { Class<?> type = createPlain() .modifiers(Visibility.PUBLIC, TypeManifestation.ABSTRACT) .defineMethod(FOO, Object.class, Visibility.PUBLIC) .throwing(Exception.class) .withoutCode() .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); Method method = type.getDeclaredMethod(FOO); assertThat(method.getReturnType(), CoreMatchers.<Class<?>>is(Object.class)); assertThat(method.getExceptionTypes(), is(new Class<?>[]{Exception.class})); assertThat(method.getModifiers(), is(Modifier.PUBLIC | Modifier.ABSTRACT)); } @Test public void testConstructorDefinition() throws Exception { Class<?> type = createPlain() .defineConstructor(Visibility.PUBLIC).withParameters(Void.class) .throwing(Exception.class) .intercept(MethodCall.invoke(Object.class.getDeclaredConstructor())) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); Constructor<?> constructor = type.getDeclaredConstructor(Void.class); assertThat(constructor.getExceptionTypes(), is(new Class<?>[]{Exception.class})); assertThat(constructor.getModifiers(), is(Modifier.PUBLIC)); assertThat(constructor.newInstance((Object) null), notNullValue(Object.class)); } @Test public void testFieldDefinition() throws Exception { Class<?> type = createPlain() .defineField(FOO, Void.class, Visibility.PUBLIC) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); Field field = type.getDeclaredField(FOO); assertThat(field.getType(), CoreMatchers.<Class<?>>is(Void.class)); assertThat(field.getModifiers(), is(Modifier.PUBLIC)); } @Test public void testFieldDefaultValueDefinition() throws Exception { Class<?> type = createPlain() .defineField(BOOLEAN_FIELD, boolean.class, Visibility.PUBLIC, Ownership.STATIC).value(BOOLEAN_VALUE) .defineField(BYTE_FIELD, byte.class, Visibility.PUBLIC, Ownership.STATIC).value(INTEGER_VALUE) .defineField(SHORT_FIELD, short.class, Visibility.PUBLIC, Ownership.STATIC).value(INTEGER_VALUE) .defineField(CHARACTER_FIELD, char.class, Visibility.PUBLIC, Ownership.STATIC).value(INTEGER_VALUE) .defineField(INTEGER_FIELD, int.class, Visibility.PUBLIC, Ownership.STATIC).value(INTEGER_VALUE) .defineField(LONG_FIELD, long.class, Visibility.PUBLIC, Ownership.STATIC).value(LONG_VALUE) .defineField(FLOAT_FIELD, float.class, Visibility.PUBLIC, Ownership.STATIC).value(FLOAT_VALUE) .defineField(DOUBLE_FIELD, double.class, Visibility.PUBLIC, Ownership.STATIC).value(DOUBLE_VALUE) .defineField(STRING_FIELD, String.class, Visibility.PUBLIC, Ownership.STATIC).value(FOO) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredField(BOOLEAN_FIELD).get(null), is((Object) BOOLEAN_VALUE)); assertThat(type.getDeclaredField(BYTE_FIELD).get(null), is((Object) (byte) INTEGER_VALUE)); assertThat(type.getDeclaredField(SHORT_FIELD).get(null), is((Object) (short) INTEGER_VALUE)); assertThat(type.getDeclaredField(CHARACTER_FIELD).get(null), is((Object) (char) INTEGER_VALUE)); assertThat(type.getDeclaredField(INTEGER_FIELD).get(null), is((Object) INTEGER_VALUE)); assertThat(type.getDeclaredField(LONG_FIELD).get(null), is((Object) LONG_VALUE)); assertThat(type.getDeclaredField(FLOAT_FIELD).get(null), is((Object) FLOAT_VALUE)); assertThat(type.getDeclaredField(DOUBLE_FIELD).get(null), is((Object) DOUBLE_VALUE)); assertThat(type.getDeclaredField(STRING_FIELD).get(null), is((Object) FOO)); } @Test public void testApplicationOrder() throws Exception { assertThat(createPlain() .method(named(TO_STRING)).intercept(new Implementation.Simple(new TextConstant(FOO), MethodReturn.REFERENCE)) .method(named(TO_STRING)).intercept(new Implementation.Simple(new TextConstant(BAR), MethodReturn.REFERENCE)) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded() .getDeclaredConstructor() .newInstance() .toString(), is(BAR)); } @Test public void testTypeInitializer() throws Exception { ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassFileExtraction.of(Bar.class)); Class<?> type = createPlain() .invokable(isTypeInitializer()).intercept(MethodCall.invoke(Bar.class.getDeclaredMethod("invoke"))) .make() .load(classLoader, ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredConstructor().newInstance(), notNullValue(Object.class)); Class<?> foo = classLoader.loadClass(Bar.class.getName()); assertThat(foo.getDeclaredField(FOO).get(null), is((Object) FOO)); } @Test public void testConstructorInvokingMethod() throws Exception { Class<?> type = createPlain() .defineMethod(FOO, Object.class, Visibility.PUBLIC) .intercept(new Implementation.Simple(new TextConstant(FOO), MethodReturn.REFERENCE)) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); Method method = type.getDeclaredMethod(FOO); assertThat(method.invoke(type.getDeclaredConstructor().newInstance()), is((Object) FOO)); } @Test public void testMethodTransformation() throws Exception { Class<?> type = createPlain() .method(named(TO_STRING)) .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(); assertThat(type.getDeclaredConstructor().newInstance().toString(), is(FOO)); assertThat(type.getDeclaredMethod(TO_STRING).getModifiers(), is(Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC)); } @Test public void testFieldTransformation() throws Exception { Class<?> type = createPlain() .defineField(FOO, Void.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 public void testIgnoredMethod() throws Exception { Class<?> type = createPlain() .ignoreAlso(named(TO_STRING)) .method(named(TO_STRING)) .intercept(new Implementation.Simple(new TextConstant(FOO), MethodReturn.REFERENCE)) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredConstructor().newInstance().toString(), CoreMatchers.not(FOO)); } @Test public void testIgnoredMethodDoesNotApplyForDefined() throws Exception { Class<?> type = createPlain() .ignoreAlso(named(FOO)) .defineMethod(FOO, String.class, Visibility.PUBLIC) .intercept(new Implementation.Simple(new TextConstant(FOO), MethodReturn.REFERENCE)) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredMethod(FOO).invoke(type.getDeclaredConstructor().newInstance()), is((Object) FOO)); } @Test public void testPreparedField() throws Exception { ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassFileExtraction.of(SampleAnnotation.class)); Class<?> type = createPlain() .defineMethod(BAR, String.class, Visibility.PUBLIC) .intercept(new PreparedField()) .make() .load(classLoader, ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredFields().length, is(1)); assertThat(type.getDeclaredField(FOO).getName(), is(FOO)); assertThat(type.getDeclaredField(FOO).getType(), CoreMatchers.<Class<?>>is(Object.class)); assertThat(type.getDeclaredField(FOO).getModifiers(), is(MODIFIERS)); assertThat(type.getDeclaredField(FOO).getAnnotations().length, is(1)); Annotation annotation = type.getDeclaredField(FOO).getAnnotations()[0]; assertThat(annotation.annotationType().getName(), is(SampleAnnotation.class.getName())); Method foo = annotation.annotationType().getDeclaredMethod(FOO); assertThat(foo.invoke(annotation), is((Object) BAR)); } @Test public void testPreparedMethod() throws Exception { ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassFileExtraction.of(SampleAnnotation.class)); Class<?> type = createPlain() .defineMethod(BAR, String.class, Visibility.PUBLIC) .intercept(new PreparedMethod()) .make() .load(classLoader, ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredMethods().length, is(2)); assertThat(type.getDeclaredMethod(FOO, Object.class).getName(), is(FOO)); assertThat(type.getDeclaredMethod(FOO, Object.class).getReturnType(), CoreMatchers.<Class<?>>is(Object.class)); assertThat(type.getDeclaredMethod(FOO, Object.class).getParameterTypes().length, is(1)); assertThat(type.getDeclaredMethod(FOO, Object.class).getParameterTypes()[0], CoreMatchers.<Class<?>>is(Object.class)); assertThat(type.getDeclaredMethod(FOO, Object.class).getModifiers(), is(MODIFIERS)); assertThat(type.getDeclaredMethod(FOO, Object.class).getAnnotations().length, is(1)); Annotation methodAnnotation = type.getDeclaredMethod(FOO, Object.class).getAnnotations()[0]; assertThat(methodAnnotation.annotationType().getName(), is(SampleAnnotation.class.getName())); Method methodMethod = methodAnnotation.annotationType().getDeclaredMethod(FOO); assertThat(methodMethod.invoke(methodAnnotation), is((Object) BAR)); assertThat(type.getDeclaredMethod(FOO, Object.class).getParameterAnnotations()[0].length, is(1)); Annotation parameterAnnotation = type.getDeclaredMethod(FOO, Object.class).getParameterAnnotations()[0][0]; assertThat(parameterAnnotation.annotationType().getName(), is(SampleAnnotation.class.getName())); Method parameterMethod = parameterAnnotation.annotationType().getDeclaredMethod(FOO); assertThat(parameterMethod.invoke(parameterAnnotation), is((Object) QUX)); } @Test @SuppressWarnings("unchecked") public void testWriterHint() 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 void visitEnd() { MethodVisitor mv = visitMethod(Opcodes.ACC_PUBLIC, FOO, "()Ljava/lang/String;", null, null); mv.visitCode(); mv.visitLdcInsn(FOO); mv.visitInsn(Opcodes.ARETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } }; } }); when(asmVisitorWrapper.mergeWriter(0)).thenReturn(ClassWriter.COMPUTE_MAXS); Class<?> type = createPlain() .visit(asmVisitorWrapper) .make() .load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredMethod(FOO).invoke(type.getDeclaredConstructor().newInstance()), is((Object) FOO)); verify(asmVisitorWrapper).mergeWriter(0); verify(asmVisitorWrapper, atMost(1)).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 public void testExplicitTypeInitializer() throws Exception { assertThat(createPlain() .defineField(FOO, String.class, Ownership.STATIC, Visibility.PUBLIC) .initializer(new ByteCodeAppender() { @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) { return new Size(new StackManipulation.Compound( new TextConstant(FOO), FieldAccess.forField(instrumentedMethod.getDeclaringType().getDeclaredFields().filter(named(FOO)).getOnly()).write() ).apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize()); } }).make() .load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER) .getLoaded() .getDeclaredField(FOO) .get(null), is((Object) FOO)); } @Test public void testSerialVersionUid() throws Exception { Class<?> type = createPlain() .serialVersionUid(42L) .make() .load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); Field field = type.getDeclaredField("serialVersionUID"); field.setAccessible(true); assertThat((Long) field.get(null), is(42L)); assertThat(field.getType(), is((Object) long.class)); assertThat(field.getModifiers(), is(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)); } @Test public void testTypeVariable() throws Exception { Class<?> type = createPlain() .typeVariable(FOO) .typeVariable(BAR, String.class) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getTypeParameters().length, is(2)); assertThat(type.getTypeParameters()[0].getName(), is(FOO)); assertThat(type.getTypeParameters()[0].getBounds().length, is(1)); assertThat(type.getTypeParameters()[0].getBounds()[0], is((Object) Object.class)); assertThat(type.getTypeParameters()[1].getName(), is(BAR)); assertThat(type.getTypeParameters()[1].getBounds().length, is(1)); assertThat(type.getTypeParameters()[1].getBounds()[0], is((Object) String.class)); } @Test public void testTypeVariableTransformation() throws Exception { Class<?> type = createPlain() .typeVariable(FOO) .typeVariable(BAR, String.class) .transform(named(BAR), new Transformer<TypeVariableToken>() { @Override public TypeVariableToken transform(TypeDescription instrumentedType, TypeVariableToken target) { return new TypeVariableToken(target.getSymbol(), Collections.singletonList(new TypeDescription.Generic.OfNonGenericType.ForLoadedType(Integer.class))); } }) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getTypeParameters().length, is(2)); assertThat(type.getTypeParameters()[0].getName(), is(FOO)); assertThat(type.getTypeParameters()[0].getBounds().length, is(1)); assertThat(type.getTypeParameters()[0].getBounds()[0], is((Object) Object.class)); assertThat(type.getTypeParameters()[1].getName(), is(BAR)); assertThat(type.getTypeParameters()[1].getBounds().length, is(1)); assertThat(type.getTypeParameters()[1].getBounds()[0], is((Object) Integer.class)); } @Test public void testGenericFieldDefinition() throws Exception { Class<?> type = createPlain() .defineField(QUX, list) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredField(QUX).getGenericType(), is(list)); } @Test public void testGenericMethodDefinition() throws Exception { Class<?> type = createPlain() .defineMethod(QUX, list) .withParameter(list, BAR, ProvisioningState.MANDATED) .throwing(fooVariable) .typeVariable(FOO, Exception.class) .intercept(StubMethod.INSTANCE) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(type.getDeclaredMethod(QUX, List.class).getTypeParameters().length, is(1)); assertThat(type.getDeclaredMethod(QUX, List.class).getTypeParameters()[0].getName(), is(FOO)); assertThat(type.getDeclaredMethod(QUX, List.class).getTypeParameters()[0].getBounds().length, is(1)); assertThat(type.getDeclaredMethod(QUX, List.class).getTypeParameters()[0].getBounds()[0], is((Object) Exception.class)); assertThat(type.getDeclaredMethod(QUX, List.class).getGenericReturnType(), is(list)); assertThat(type.getDeclaredMethod(QUX, List.class).getGenericExceptionTypes()[0], is((Type) type.getDeclaredMethod(QUX, List.class).getTypeParameters()[0])); assertThat(type.getDeclaredMethod(QUX, List.class).getGenericParameterTypes().length, is(1)); assertThat(type.getDeclaredMethod(QUX, List.class).getGenericParameterTypes()[0], is(list)); } @Test @JavaVersionRule.Enforce(8) public void testGenericMethodDefinitionMetaDataParameter() throws Exception { Class<?> type = createPlain() .defineMethod(QUX, list) .withParameter(list, BAR, ProvisioningState.MANDATED) .throwing(fooVariable) .typeVariable(FOO, Exception.class) .intercept(StubMethod.INSTANCE) .make() .load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(TypeDefinition.Sort.describe(type).getDeclaredMethods().filter(named(QUX)).getOnly().getParameters().getOnly().getName(), is(BAR)); assertThat(TypeDefinition.Sort.describe(type).getDeclaredMethods().filter(named(QUX)).getOnly().getParameters().getOnly().getModifiers(), is(ProvisioningState.MANDATED.getMask())); } @Test(expected = ClassFormatError.class) public void testUnvalidated() throws Exception { createPlainWithoutValidation() .defineField(FOO, void.class) .make() .load(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassLoadingStrategy.Default.WRAPPER); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testTypeVariableOnTypeAnnotationClassBound() 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 = createPlain() .typeVariable(FOO, TypeDescription.Generic.Builder.rawType(Object.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE * 2).build())) .annotateTypeVariable(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); assertThat(type.getTypeParameters().length, is(1)); assertThat(type.getTypeParameters()[0].getBounds().length, is(1)); assertThat(type.getTypeParameters()[0].getBounds()[0], is((Object) Object.class)); 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(INTEGER_VALUE)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[0]).ofTypeVariableBoundType(0) .asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[0]).ofTypeVariableBoundType(0) .asList().ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE * 2)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testTypeVariableOnTypeAnnotationInterfaceBound() 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 = createPlain() .typeVariable(FOO, TypeDescription.Generic.Builder.rawType(Runnable.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE * 2).build())) .annotateTypeVariable(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); assertThat(type.getTypeParameters().length, is(1)); assertThat(type.getTypeParameters()[0].getBounds().length, is(1)); assertThat(type.getTypeParameters()[0].getBounds()[0], is((Object) Runnable.class)); 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(INTEGER_VALUE)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[0]).ofTypeVariableBoundType(0) .asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(type.getTypeParameters()[0]).ofTypeVariableBoundType(0) .asList().ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE * 2)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testTypeVariableOnTypeAnnotationTypeVariableBound() 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 = createPlain() .typeVariable(FOO) .annotateTypeVariable(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .typeVariable(BAR, TypeDescription.Generic.Builder.rawType(Object.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE * 3).build())) .annotateTypeVariable(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE * 2).build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); assertThat(type.getTypeParameters().length, is(2)); assertThat(type.getTypeParameters()[0].getBounds().length, is(1)); assertThat(type.getTypeParameters()[0].getBounds()[0], is((Object) Object.class)); assertThat(type.getTypeParameters()[1].getBounds().length, is(1)); assertThat(type.getTypeParameters()[1].getBounds()[0], is((Object) Object.class)); 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(INTEGER_VALUE)); 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(INTEGER_VALUE * 2)); 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(INTEGER_VALUE * 3)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testTypeAnnotationOnInterfaceType() 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 = createPlain() .merge(TypeManifestation.ABSTRACT) .implement(TypeDescription.Generic.Builder.rawType(Runnable.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build())) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); assertThat(type.getInterfaces().length, is(1)); assertThat(type.getInterfaces()[0], is((Object) Runnable.class)); 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(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnFieldType() 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(); Field field = createPlain() .defineField(FOO, TypeDescription.Generic.Builder.rawType(Object.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build())) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredField(FOO); assertThat(field.getType(), is((Object) Object.class)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).asList().ofType(typeAnnotationType) .getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testTypeVariableOnMethodAnnotationClassBound() 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(); Method method = createPlain() .merge(TypeManifestation.ABSTRACT) .defineMethod(FOO, void.class) .typeVariable(FOO, TypeDescription.Generic.Builder.rawType(Object.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE * 2).build())) .annotateTypeVariable(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .withoutCode() .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredMethod(FOO); assertThat(method.getTypeParameters().length, is(1)); assertThat(method.getTypeParameters()[0].getBounds().length, is(1)); assertThat(method.getTypeParameters()[0].getBounds()[0], is((Object) Object.class)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).asList().ofType(typeAnnotationType) .getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).ofTypeVariableBoundType(0) .asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).ofTypeVariableBoundType(0) .asList().ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE * 2)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testTypeVariableOnMethodAnnotationInterfaceBound() 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(); Method method = createPlain() .merge(TypeManifestation.ABSTRACT) .defineMethod(FOO, void.class) .typeVariable(FOO, TypeDescription.Generic.Builder.rawType(Runnable.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE * 2).build())) .annotateTypeVariable(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .withoutCode() .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredMethod(FOO); assertThat(method.getTypeParameters().length, is(1)); assertThat(method.getTypeParameters()[0].getBounds().length, is(1)); assertThat(method.getTypeParameters()[0].getBounds()[0], is((Object) Runnable.class)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).asList().ofType(typeAnnotationType) .getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).ofTypeVariableBoundType(0) .asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).ofTypeVariableBoundType(0) .asList().ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE * 2)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testTypeVariableOnMethodAnnotationTypeVariableBound() 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(); Method method = createPlain() .merge(TypeManifestation.ABSTRACT) .defineMethod(FOO, void.class) .typeVariable(FOO).annotateTypeVariable(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .typeVariable(BAR, TypeDescription.Generic.Builder.rawType(Object.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE * 3).build())) .annotateTypeVariable(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE * 2).build()) .withoutCode() .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredMethod(FOO); assertThat(method.getTypeParameters().length, is(2)); assertThat(method.getTypeParameters()[0].getBounds().length, is(1)); assertThat(method.getTypeParameters()[0].getBounds()[0], is((Object) Object.class)); assertThat(method.getTypeParameters()[1].getBounds().length, is(1)); assertThat(method.getTypeParameters()[1].getBounds()[0], is((Object) Object.class)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[0]).asList().ofType(typeAnnotationType) .getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[1]).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[1]).asList().ofType(typeAnnotationType) .getValue(value).resolve(Integer.class), is(INTEGER_VALUE * 2)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[1]).ofTypeVariableBoundType(0) .asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveTypeVariable(method.getTypeParameters()[1]).ofTypeVariableBoundType(0) .asList().ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE * 3)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnMethodReturnType() 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(); Method method = createPlain() .merge(TypeManifestation.ABSTRACT) .defineMethod(FOO, TypeDescription.Generic.Builder.rawType(Object.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build())) .withoutCode() .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredMethod(FOO); assertThat(method.getReturnType(), is((Object) Object.class)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveReturnType(method).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveReturnType(method).asList().ofType(typeAnnotationType) .getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnMethodParameterType() 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(); Method method = createPlain() .merge(TypeManifestation.ABSTRACT) .defineMethod(FOO, void.class).withParameters(TypeDescription.Generic.Builder.rawType(Object.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build())) .withoutCode() .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredMethod(FOO, Object.class); assertThat(method.getParameterTypes().length, is(1)); assertThat(method.getParameterTypes()[0], is((Object) Object.class)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveParameterType(method, 0).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveParameterType(method, 0).asList().ofType(typeAnnotationType) .getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnMethodExceptionType() 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(); Method method = createPlain() .merge(TypeManifestation.ABSTRACT) .defineMethod(FOO, void.class).throwing(TypeDescription.Generic.Builder.rawType(Exception.class) .build(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build())) .withoutCode() .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredMethod(FOO); assertThat(method.getExceptionTypes().length, is(1)); assertThat(method.getExceptionTypes()[0], is((Object) Exception.class)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveExceptionType(method, 0).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveExceptionType(method, 0).asList().ofType(typeAnnotationType) .getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnWildcardWithoutBound() 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(); Field field = createPlain() .defineField(FOO, TypeDescription.Generic.Builder.parameterizedType(new TypeDescription.ForLoadedType(Collection.class), TypeDescription.Generic.Builder.unboundWildcard(AnnotationDescription.Builder.ofType(typeAnnotationType) .define(VALUE, INTEGER_VALUE).build())).build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredField(FOO); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofTypeArgument(0).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofTypeArgument(0).asList().ofType(typeAnnotationType) .getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnWildcardUpperBoundBound() 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(); Field field = createPlain() .defineField(FOO, TypeDescription.Generic.Builder.parameterizedType(new TypeDescription.ForLoadedType(Collection.class), TypeDescription.Generic.Builder.rawType(Object.class) .annotate(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .asWildcardUpperBound()).build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredField(FOO); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofTypeArgument(0).ofWildcardUpperBoundType(0).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofTypeArgument(0).ofWildcardUpperBoundType(0).asList() .ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnWildcardLowerBoundBound() 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(); Field field = createPlain() .defineField(FOO, TypeDescription.Generic.Builder.parameterizedType(new TypeDescription.ForLoadedType(Collection.class), TypeDescription.Generic.Builder.rawType(Object.class) .annotate(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .asWildcardLowerBound()).build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredField(FOO); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofTypeArgument(0).ofWildcardLowerBoundType(0).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofTypeArgument(0).ofWildcardLowerBoundType(0).asList() .ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnGenericComponentType() 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(); Field field = createPlain() .defineField(FOO, TypeDescription.Generic.Builder.parameterizedType(new TypeDescription.ForLoadedType(Collection.class), TypeDescription.Generic.Builder.unboundWildcard()) .annotate(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .asArray() .build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredField(FOO); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofComponentType().asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofComponentType().asList() .ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnNonGenericComponentType() 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(); Field field = createPlain() .defineField(FOO, TypeDescription.Generic.Builder.rawType(Object.class) .annotate(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .asArray() .build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredField(FOO); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofComponentType().asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofComponentType().asList() .ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnParameterizedType() 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(); Field field = createPlain() .defineField(FOO, TypeDescription.Generic.Builder.parameterizedType(new TypeDescription.ForLoadedType(Collection.class), TypeDescription.Generic.Builder.unboundWildcard(AnnotationDescription.Builder.ofType(typeAnnotationType) .define(VALUE, INTEGER_VALUE).build())) .build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredField(FOO); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofTypeArgument(0).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).ofTypeArgument(0).asList() .ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") public void testAnnotationTypeOnNestedType() 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(); Field field = createPlain() .defineField(FOO, TypeDescription.Generic.Builder.rawType(new TypeDescription.ForLoadedType(Nested.Inner.class), TypeDescription.Generic.Builder.rawType(Nested.class).build()) .annotate(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredField(FOO); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).asList() .ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test @JavaVersionRule.Enforce(8) @SuppressWarnings("unchecked") @Ignore("The Java reflection API does not currently support nested generic types") public void testAnnotationTypeOnNestedParameterizedType() 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(); Field field = createPlain() .defineField(FOO, TypeDescription.Generic.Builder.parameterizedType(new TypeDescription.ForLoadedType(GenericNested.Inner.class), TypeDescription.Generic.Builder.parameterizedType(GenericNested.class, Void.class).build(), Collections.<TypeDefinition>emptyList()) .annotate(AnnotationDescription.Builder.ofType(typeAnnotationType).define(VALUE, INTEGER_VALUE).build()) .build()) .make() .load(typeAnnotationType.getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredField(FOO); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).asList().size(), is(1)); assertThat(TypeDescription.Generic.AnnotationReader.DISPATCHER.resolveFieldType(field).asList() .ofType(typeAnnotationType).getValue(value).resolve(Integer.class), is(INTEGER_VALUE)); } @Test public void testBridgeResolutionAmbiguous() throws Exception { Class<?> type = createPlain() .defineMethod(QUX, String.class, Visibility.PUBLIC) .intercept(FixedValue.value(FOO)) .defineMethod(QUX, Object.class, Visibility.PUBLIC) .intercept(FixedValue.value(BAR)) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); for (Method method : type.getDeclaredMethods()) { if (method.getReturnType() == String.class) { assertThat(method.getName(), is(QUX)); assertThat(method.getParameterTypes().length, is(0)); assertThat(method.invoke(type.getDeclaredConstructor().newInstance()), is((Object) BAR)); } else if (method.getReturnType() == Object.class) { assertThat(method.getName(), is(QUX)); assertThat(method.getParameterTypes().length, is(0)); assertThat(method.invoke(type.getDeclaredConstructor().newInstance()), is((Object) BAR)); } else { throw new AssertionError(); } } } @Test public void testCanOverloadMethodByReturnType() throws Exception { Class<?> type = createPlain() .defineMethod(QUX, String.class, Visibility.PUBLIC) .intercept(FixedValue.value(FOO)) .defineMethod(QUX, Object.class, Ownership.STATIC, Visibility.PUBLIC) // Is static to avoid method graph compiler. .intercept(FixedValue.value(BAR)) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); for (Method method : type.getDeclaredMethods()) { if (method.getReturnType() == String.class) { assertThat(method.getName(), is(QUX)); assertThat(method.getParameterTypes().length, is(0)); assertThat(method.invoke(type.getDeclaredConstructor().newInstance()), is((Object) FOO)); } else if (method.getReturnType() == Object.class) { assertThat(method.getName(), is(QUX)); assertThat(method.getParameterTypes().length, is(0)); assertThat(method.invoke(null), is((Object) BAR)); } else { throw new AssertionError(); } } } @Test public void testCanOverloadFieldByType() throws Exception { Class<?> type = createPlain() .defineField(QUX, String.class, Ownership.STATIC, Visibility.PUBLIC) .value(FOO) .defineField(QUX, long.class, Ownership.STATIC, Visibility.PUBLIC) .value(42L) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); for (Field field : type.getDeclaredFields()) { if (field.getType() == String.class) { assertThat(field.getName(), is(QUX)); assertThat(field.get(null), is((Object) FOO)); } else if (field.getType() == long.class) { assertThat(field.getName(), is(QUX)); assertThat(field.get(null), is((Object) 42L)); } else { throw new AssertionError(); } } } @Test public void testInterfaceInterception() throws Exception { assertThat(((SampleInterface) createPlain() .implement(SampleInterface.class) .intercept(FixedValue.value(FOO)) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredConstructor() .newInstance()).foo(), is(FOO)); } @Test public void testInterfaceInterceptionPreviousSuperseeded() throws Exception { assertThat(((SampleInterface) createPlain() .method(named(FOO)) .intercept(ExceptionMethod.throwing(AssertionError.class)) .implement(SampleInterface.class) .intercept(FixedValue.value(FOO)) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredConstructor() .newInstance()).foo(), is(FOO)); } @Test public void testInterfaceInterceptionLaterSuperseeding() throws Exception { assertThat(((SampleInterface) createPlain() .implement(SampleInterface.class) .intercept(ExceptionMethod.throwing(AssertionError.class)) .method(named(FOO)) .intercept(FixedValue.value(FOO)) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredConstructor() .newInstance()).foo(), is(FOO)); } @Test public void testInterfaceInterceptionSubClass() throws Exception { assertThat(((SampleInterface) createPlain() .implement(SampleInterface.SubInterface.class) .intercept(FixedValue.value(FOO)) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded() .getDeclaredConstructor() .newInstance()).foo(), is(FOO)); } @Test public void testInterfaceMakesClassMethodPublic() throws Exception { Class<?> type = createPlain() .implement(Cloneable.class) .method(named("clone")) .intercept(FixedValue.self()) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); Cloneable cloneable = (Cloneable) type.getDeclaredConstructor().newInstance(); assertThat(cloneable.clone(), sameInstance((Object) cloneable)); } @Retention(RetentionPolicy.RUNTIME) public @interface SampleAnnotation { String foo(); } public static class Foo { /* empty */ } public static class Bar { public static String foo; public static void invoke() { foo = FOO; } } public static class BridgeRetention<T> extends CallTraceable { public T foo() { register(FOO); return null; } public static class Inner extends BridgeRetention<String> { /* empty */ } } public static class CallSuperMethod<T> extends CallTraceable { public T foo(T value) { register(FOO); return value; } public static class Inner extends CallSuperMethod<String> { /* empty */ } } private static class PreparedField implements Implementation { @Override public InstrumentedType prepare(InstrumentedType instrumentedType) { return instrumentedType.withField(new FieldDescription.Token(FOO, MODIFIERS, TypeDescription.Generic.OBJECT, Collections.singletonList(AnnotationDescription.Builder.ofType(SampleAnnotation.class).define(FOO, BAR).build()))); } @Override public ByteCodeAppender appender(Target implementationTarget) { return new ByteCodeAppender.Simple(NullConstant.INSTANCE, MethodReturn.REFERENCE); } } private static class PreparedMethod implements Implementation { @Override public InstrumentedType prepare(InstrumentedType instrumentedType) { return instrumentedType.withMethod(new MethodDescription.Token(FOO, MODIFIERS, Collections.<TypeVariableToken>emptyList(), TypeDescription.Generic.OBJECT, Collections.singletonList(new ParameterDescription.Token(TypeDescription.Generic.OBJECT, Collections.singletonList(AnnotationDescription.Builder.ofType(SampleAnnotation.class).define(FOO, QUX).build()))), Collections.singletonList(new TypeDescription.Generic.OfNonGenericType.ForLoadedType(Exception.class)), Collections.singletonList(AnnotationDescription.Builder.ofType(SampleAnnotation.class).define(FOO, BAR).build()), AnnotationValue.UNDEFINED, TypeDescription.Generic.UNDEFINED)); } @Override public ByteCodeAppender appender(Target implementationTarget) { return new ByteCodeAppender.Simple(NullConstant.INSTANCE, MethodReturn.REFERENCE); } } public static class InterfaceOverrideInterceptor { public static String intercept(@SuperCall Callable<String> zuper) throws Exception { return zuper.call() + BAR; } } @SuppressWarnings("unused") private static class Holder<foo> { List<?> list; List<foo> fooList; } @SuppressWarnings("unused") public static class Nested { public class Inner { /* empty */ } } @SuppressWarnings("unused") public static class GenericNested<T> { public class Inner { /* empty */ } } public interface Cloneable { Object clone(); } public interface SampleInterface { String foo(); interface SubInterface extends SampleInterface { } } }