package net.bytebuddy.dynamic.loading;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.TargetType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.Super;
import net.bytebuddy.test.utility.ClassFileExtraction;
import net.bytebuddy.test.utility.ObjectPropertyAssertion;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
public class ClassInjectorUsingReflectionTest {
private static final String FOO = "foo", BAR = "bar";
private ClassLoader classLoader;
@Before
public void setUp() throws Exception {
classLoader = new URLClassLoader(new URL[0], null);
}
@Test(expected = IllegalArgumentException.class)
public void testBootstrapClassLoader() throws Exception {
new ClassInjector.UsingReflection(ClassLoadingStrategy.BOOTSTRAP_LOADER);
}
@Test
public void testInjection() throws Exception {
new ClassInjector.UsingReflection(classLoader)
.inject(Collections.<TypeDescription, byte[]>singletonMap(new TypeDescription.ForLoadedType(Foo.class), ClassFileExtraction.extract(Foo.class)));
assertThat(classLoader.loadClass(Foo.class.getName()).getClassLoader(), is(classLoader));
}
@Test
public void testDirectInjection() throws Exception {
ClassInjector.UsingReflection.Dispatcher dispatcher = ClassInjector.UsingReflection.Dispatcher.Direct.make().initialize();
assertThat(dispatcher.findClass(classLoader, Foo.class.getName()), nullValue(Class.class));
assertThat(dispatcher.defineClass(classLoader, Foo.class.getName(), ClassFileExtraction.extract(Foo.class), null), notNullValue(Class.class));
assertThat(dispatcher.getPackage(classLoader, Foo.class.getPackage().getName()), nullValue(Package.class));
assertThat(dispatcher.definePackage(classLoader,
Foo.class.getPackage().getName(),
null,
null,
null,
null,
null,
null,
null), notNullValue(Package.class));
assertThat(classLoader.loadClass(Foo.class.getName()).getClassLoader(), is(classLoader));
}
@Test
public void testIndirectInjection() throws Exception {
ClassInjector.UsingReflection.Dispatcher dispatcher = ClassInjector.UsingReflection.Dispatcher.Indirect.make().initialize();
assertThat(dispatcher.findClass(classLoader, Foo.class.getName()), nullValue(Class.class));
assertThat(dispatcher.defineClass(classLoader, Foo.class.getName(), ClassFileExtraction.extract(Foo.class), null), notNullValue(Class.class));
assertThat(dispatcher.getPackage(classLoader, Foo.class.getPackage().getName()), nullValue(Package.class));
assertThat(dispatcher.definePackage(classLoader,
Foo.class.getPackage().getName(),
null,
null,
null,
null,
null,
null,
null), notNullValue(Package.class));
assertThat(classLoader.loadClass(Foo.class.getName()).getClassLoader(), is(classLoader));
}
@Test
public void testDispatcherFaultyInitializationGetClass() throws Exception {
assertThat(new ClassInjector.UsingReflection.Dispatcher.Unavailable(new Exception()).initialize().findClass(getClass().getClassLoader(),
Object.class.getName()), is((Object) Object.class));
}
@Test
public void testDispatcherFaultyInitializationGetClassInexistant() throws Exception {
assertThat(new ClassInjector.UsingReflection.Dispatcher.Unavailable(new Exception()).initialize().findClass(getClass().getClassLoader(),
FOO), nullValue(Class.class));
}
@Test(expected = UnsupportedOperationException.class)
public void testDispatcherFaultyInitializationDefineClass() throws Exception {
new ClassInjector.UsingReflection.Dispatcher.Unavailable(new Exception()).initialize().defineClass(null,
null,
null,
null);
}
@Test(expected = UnsupportedOperationException.class)
public void testDispatcherFaultyInitializationGetPackage() throws Exception {
new ClassInjector.UsingReflection.Dispatcher.Unavailable(new Exception()).initialize().getPackage(null, null);
}
@Test(expected = UnsupportedOperationException.class)
public void testDispatcherFaultyInitializationDefinePackage() throws Exception {
new ClassInjector.UsingReflection.Dispatcher.Unavailable(new Exception()).initialize().definePackage(null,
null,
null,
null,
null,
null,
null,
null,
null);
}
@Test
public void testLegacyDispatcherGetLock() throws Exception {
ClassLoader classLoader = mock(ClassLoader.class);
assertThat(new ClassInjector.UsingReflection.Dispatcher.Direct.ForLegacyVm(null,
null,
null,
null).getClassLoadingLock(classLoader, FOO), is((Object) classLoader));
}
@Test
public void testFaultyDispatcherGetLock() throws Exception {
ClassLoader classLoader = mock(ClassLoader.class);
assertThat(new ClassInjector.UsingReflection.Dispatcher.Unavailable(null).getClassLoadingLock(classLoader, FOO), is((Object) classLoader));
}
@Test
public void testInjectionOrderNoPrematureAuxiliaryInjection() throws Exception {
ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER,
ClassFileExtraction.of(Bar.class, Interceptor.class));
Class<?> type = new ByteBuddy().rebase(Bar.class)
.method(named(BAR))
.intercept(MethodDelegation.to(Interceptor.class)).make()
.load(classLoader, ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
assertThat(type.getDeclaredMethod(BAR, String.class).invoke(type.getDeclaredConstructor().newInstance(), FOO), is((Object) BAR));
}
@Test
public void testAvailability() throws Exception {
assertThat(ClassInjector.UsingReflection.isAvailable(), is(true));
assertThat(new ClassInjector.UsingReflection.Dispatcher.Unavailable(null).isAvailable(), is(false));
}
@Test
public void testObjectProperties() throws Exception {
ObjectPropertyAssertion.of(ClassInjector.UsingReflection.class).apply();
final Iterator<Method> methods = Arrays.asList(String.class.getDeclaredMethods()).iterator();
ObjectPropertyAssertion.of(ClassInjector.UsingReflection.Dispatcher.Direct.ForLegacyVm.class).create(new ObjectPropertyAssertion.Creator<Method>() {
@Override
public Method create() {
return methods.next();
}
}).apply();
ObjectPropertyAssertion.of(ClassInjector.UsingReflection.Dispatcher.Direct.ForJava7CapableVm.class).create(new ObjectPropertyAssertion.Creator<Method>() {
@Override
public Method create() {
return methods.next();
}
}).apply();
ObjectPropertyAssertion.of(ClassInjector.UsingReflection.Dispatcher.Indirect.class).create(new ObjectPropertyAssertion.Creator<Method>() {
@Override
public Method create() {
return methods.next();
}
}).apply();
ObjectPropertyAssertion.of(ClassInjector.UsingReflection.Dispatcher.Unavailable.class).apply();
ObjectPropertyAssertion.of(ClassInjector.UsingReflection.Dispatcher.Unavailable.class).apply();
ObjectPropertyAssertion.of(ClassInjector.UsingReflection.Dispatcher.CreationAction.class).apply();
}
private static class Foo {
/* Note: Foo is know to the system class loader but not to the bootstrap class loader */
}
public static class Bar {
public String bar(String value) {
return value;
}
}
public static class Interceptor {
@RuntimeType
public static Object intercept(@Super(proxyType = TargetType.class) Object zuper,
@AllArguments Object[] args,
@Origin Method method) throws Throwable {
args[0] = BAR;
return method.invoke(zuper, args);
}
}
}