package net.bytebuddy.pool; import net.bytebuddy.ByteBuddy; import net.bytebuddy.description.type.AbstractTypeDescriptionTest; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.ClassFileLocator; import net.bytebuddy.dynamic.scaffold.InstrumentedType; import net.bytebuddy.dynamic.scaffold.MethodGraph; import net.bytebuddy.dynamic.scaffold.TypeValidation; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import org.hamcrest.CoreMatchers; import org.junit.Ignore; import org.junit.Test; import java.lang.reflect.Field; import java.lang.reflect.Method; import static net.bytebuddy.matcher.ElementMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class TypePoolDefaultWithLazyResolutionTypeDescriptionTest extends AbstractTypeDescriptionTest { @Override protected TypeDescription describe(Class<?> type) { return describe(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()), TypePool.CacheProvider.NoOp.INSTANCE); } private static TypeDescription describe(Class<?> type, ClassFileLocator classFileLocator, TypePool.CacheProvider cacheProvider) { return new TypePool.Default.WithLazyResolution(cacheProvider, classFileLocator, TypePool.Default.ReaderMode.EXTENDED).describe(type.getName()).resolve(); } @Override protected TypeDescription.Generic describeType(Field field) { return describe(field.getDeclaringClass()).getDeclaredFields().filter(is(field)).getOnly().getType(); } @Override protected TypeDescription.Generic describeReturnType(Method method) { return describe(method.getDeclaringClass()).getDeclaredMethods().filter(is(method)).getOnly().getReturnType(); } @Override protected TypeDescription.Generic describeParameterType(Method method, int index) { return describe(method.getDeclaringClass()).getDeclaredMethods().filter(is(method)).getOnly().getParameters().get(index).getType(); } @Override protected TypeDescription.Generic describeExceptionType(Method method, int index) { return describe(method.getDeclaringClass()).getDeclaredMethods().filter(is(method)).getOnly().getExceptionTypes().get(index); } @Override protected TypeDescription.Generic describeSuperClass(Class<?> type) { return describe(type).getSuperClass(); } @Override protected TypeDescription.Generic describeInterfaceType(Class<?> type, int index) { return describe(type).getInterfaces().get(index); } @Test public void testTypeIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); TypePool typePool = TypePool.Default.WithLazyResolution.of(classFileLocator); TypePool.Resolution resolution = typePool.describe(Object.class.getName()); assertThat(resolution.resolve().getName(), CoreMatchers.is(TypeDescription.OBJECT.getName())); verifyZeroInteractions(classFileLocator); } @Test public void testReferencedTypeIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); TypePool typePool = TypePool.Default.WithLazyResolution.of(classFileLocator); TypePool.Resolution resolution = typePool.describe(String.class.getName()); assertThat(resolution.resolve().getName(), CoreMatchers.is(TypeDescription.STRING.getName())); assertThat(resolution.resolve().getSuperClass().asErasure().getName(), CoreMatchers.is(TypeDescription.OBJECT.getName())); verify(classFileLocator).locate(String.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testTypeIsCached() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); TypePool typePool = TypePool.Default.WithLazyResolution.of(classFileLocator); TypePool.Resolution resolution = typePool.describe(Object.class.getName()); assertThat(resolution.resolve().getModifiers(), CoreMatchers.is(TypeDescription.OBJECT.getModifiers())); assertThat(resolution.resolve().getInterfaces(), CoreMatchers.is(TypeDescription.OBJECT.getInterfaces())); assertThat(typePool.describe(Object.class.getName()).resolve(), CoreMatchers.is(resolution.resolve())); verify(classFileLocator).locate(Object.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testReferencedTypeIsCached() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); TypePool typePool = TypePool.Default.WithLazyResolution.of(classFileLocator); TypePool.Resolution resolution = typePool.describe(String.class.getName()); assertThat(resolution.resolve().getModifiers(), CoreMatchers.is(TypeDescription.STRING.getModifiers())); TypeDescription superClass = resolution.resolve().getSuperClass().asErasure(); assertThat(superClass, CoreMatchers.is(TypeDescription.OBJECT)); assertThat(superClass.getModifiers(), CoreMatchers.is(TypeDescription.OBJECT.getModifiers())); assertThat(superClass.getInterfaces(), CoreMatchers.is(TypeDescription.OBJECT.getInterfaces())); assertThat(typePool.describe(String.class.getName()).resolve(), CoreMatchers.is(resolution.resolve())); verify(classFileLocator).locate(String.class.getName()); verify(classFileLocator).locate(Object.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testNonGenericResolutionIsLazyForSimpleCreationNonFrozen() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); new ByteBuddy() .with(TypeValidation.DISABLED) .with(MethodGraph.Empty.INSTANCE) .with(InstrumentedType.Factory.Default.MODIFIABLE) .redefine(describe(NonGenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()), classFileLocator) .make(); verify(classFileLocator, times(2)).locate(NonGenericType.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testNonGenericResolutionIsLazyForSimpleCreation() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); new ByteBuddy() .with(TypeValidation.DISABLED) .with(MethodGraph.Empty.INSTANCE) .with(InstrumentedType.Factory.Default.FROZEN) .redefine(describe(NonGenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()), classFileLocator) .make(); verify(classFileLocator, times(2)).locate(NonGenericType.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testGenericResolutionIsLazyForSimpleCreation() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); new ByteBuddy() .with(TypeValidation.DISABLED) .with(MethodGraph.Empty.INSTANCE) .with(InstrumentedType.Factory.Default.FROZEN) .redefine(describe(GenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()), classFileLocator) .make(); verify(classFileLocator, times(2)).locate(GenericType.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testNonGenericSuperClassHierarchyResolutionIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); assertThat(describe(NonGenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()).getSuperClass().asErasure(), CoreMatchers.is((TypeDescription) new TypeDescription.ForLoadedType(SampleClass.class))); verify(classFileLocator).locate(NonGenericType.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testNonGenericSuperClassNavigatedHierarchyResolutionIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); assertThat(describe(NonGenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()).getSuperClass().getSuperClass().asErasure(), CoreMatchers.is((TypeDescription) new TypeDescription.ForLoadedType(SuperClass.class))); verify(classFileLocator).locate(NonGenericType.class.getName()); verify(classFileLocator).locate(SampleClass.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testNonGenericSuperInterfaceHierarchyResolutionIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); assertThat(describe(NonGenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()).getInterfaces().getOnly().asErasure(), CoreMatchers.is((TypeDescription) new TypeDescription.ForLoadedType(SampleInterface.class))); verify(classFileLocator).locate(NonGenericType.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testNonGenericSuperInterfaceNavigatedHierarchyResolutionIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); assertThat(describe(NonGenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()).getInterfaces().getOnly() .getInterfaces().getOnly().asErasure(), CoreMatchers.is((TypeDescription) new TypeDescription.ForLoadedType(SuperInterface.class))); verify(classFileLocator).locate(NonGenericType.class.getName()); verify(classFileLocator).locate(SampleInterface.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testGenericSuperClassHierarchyResolutionIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); assertThat(describe(GenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()).getSuperClass().asErasure(), CoreMatchers.is((TypeDescription) new TypeDescription.ForLoadedType(SampleGenericClass.class))); verify(classFileLocator).locate(GenericType.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testGenericSuperClassNavigatedHierarchyResolutionIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); assertThat(describe(GenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()).getSuperClass().getSuperClass().asErasure(), CoreMatchers.is((TypeDescription) new TypeDescription.ForLoadedType(SuperClass.class))); verify(classFileLocator).locate(GenericType.class.getName()); verify(classFileLocator).locate(SampleGenericClass.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testGenericSuperInterfaceHierarchyResolutionIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); assertThat(describe(GenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()).getInterfaces().getOnly().asErasure(), CoreMatchers.is((TypeDescription) new TypeDescription.ForLoadedType(SampleGenericInterface.class))); verify(classFileLocator).locate(GenericType.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testGenericSuperInterfaceNavigatedHierarchyResolutionIsLazy() throws Exception { ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofClassPath()); assertThat(describe(GenericType.class, classFileLocator, new TypePool.CacheProvider.Simple()).getInterfaces().getOnly() .getInterfaces().getOnly().asErasure(), CoreMatchers.is((TypeDescription) new TypeDescription.ForLoadedType(SuperInterface.class))); verify(classFileLocator).locate(GenericType.class.getName()); verify(classFileLocator).locate(SampleGenericInterface.class.getName()); verifyNoMoreInteractions(classFileLocator); } @Test public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(TypePool.Default.WithLazyResolution.LazyResolution.class).apply(); } private static class SuperClass { /* empty */ } private interface SuperInterface { /* empty */ } private static class SampleClass extends SuperClass { /* empty */ } private interface SampleInterface extends SuperInterface { /* empty */ } private static class NonGenericType extends SampleClass implements SampleInterface { Object foo; Object foo(Object argument) throws Exception { return argument; } } private static class SampleGenericClass<T> extends SuperClass { /* empty */ } private interface SampleGenericInterface<T> extends SuperInterface { /* empty */ } private static class GenericType<T extends Exception> extends SampleGenericClass<T> implements SampleGenericInterface<T> { T foo; T foo(T argument) throws T { return argument; } } }