package net.bytebuddy.utility;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDefinition;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.description.type.TypeList;
import net.bytebuddy.test.utility.JavaVersionRule;
import net.bytebuddy.test.utility.ObjectPropertyAssertion;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class JavaConstantMethodHandleTest {
private static final String BAR = "bar", QUX = "qux";
@Rule
public MethodRule javaVersionRule = new JavaVersionRule();
@Test
@SuppressWarnings("unchecked")
public void testMethodHandleOfMethod() throws Exception {
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle.of(Foo.class.getDeclaredMethod(BAR, Void.class));
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.INVOKE_VIRTUAL));
assertThat(methodHandle.getName(), is(BAR));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is(TypeDescription.VOID));
assertThat(methodHandle.getParameterTypes(), is((List<TypeDescription>) new TypeList.ForLoadedTypes(Void.class)));
assertThat(methodHandle.getDescriptor(), is(new MethodDescription.ForLoadedMethod(Foo.class.getDeclaredMethod(BAR, Void.class)).getDescriptor()));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodHandleOfMethodSpecialInvocation() throws Exception {
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle.ofSpecial(Foo.class.getDeclaredMethod(BAR, Void.class), Foo.class);
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.INVOKE_SPECIAL));
assertThat(methodHandle.getName(), is(BAR));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is(TypeDescription.VOID));
assertThat(methodHandle.getParameterTypes(), is((List<TypeDescription>) new TypeList.ForLoadedTypes(Void.class)));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodHandleOfStaticMethod() throws Exception {
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle.of(Foo.class.getDeclaredMethod(QUX, Void.class));
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.INVOKE_STATIC));
assertThat(methodHandle.getName(), is(QUX));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is(TypeDescription.VOID));
assertThat(methodHandle.getParameterTypes(), is((List<TypeDescription>) new TypeList.ForLoadedTypes(Void.class)));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodHandleOfConstructor() throws Exception {
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle.of(Foo.class.getDeclaredConstructor(Void.class));
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.INVOKE_SPECIAL_CONSTRUCTOR));
assertThat(methodHandle.getName(), is(MethodDescription.CONSTRUCTOR_INTERNAL_NAME));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is(TypeDescription.VOID));
assertThat(methodHandle.getParameterTypes(), is((List<TypeDescription>) new TypeList.ForLoadedTypes(Void.class)));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodHandleOfConstructorSpecialInvocation() throws Exception {
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle
.of(new MethodDescription.ForLoadedConstructor(Foo.class.getDeclaredConstructor(Void.class)));
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.INVOKE_SPECIAL_CONSTRUCTOR));
assertThat(methodHandle.getName(), is(MethodDescription.CONSTRUCTOR_INTERNAL_NAME));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is(TypeDescription.VOID));
assertThat(methodHandle.getParameterTypes(), is((List<TypeDescription>) new TypeList.ForLoadedTypes(Void.class)));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodHandleOfGetter() throws Exception {
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle.ofGetter(Foo.class.getDeclaredField(BAR));
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.GET_FIELD));
assertThat(methodHandle.getName(), is(BAR));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is((TypeDefinition) new TypeDescription.ForLoadedType(Void.class)));
assertThat(methodHandle.getParameterTypes(), is(Collections.<TypeDescription>emptyList()));
}
@Test
public void testMethodHandleOfStaticGetter() throws Exception {
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle.ofGetter(Foo.class.getDeclaredField(QUX));
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.GET_STATIC_FIELD));
assertThat(methodHandle.getName(), is(QUX));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is((TypeDefinition) new TypeDescription.ForLoadedType(Void.class)));
assertThat(methodHandle.getParameterTypes(), is(Collections.<TypeDescription>emptyList()));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodHandleOfSetter() throws Exception {
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle.ofSetter(Foo.class.getDeclaredField(BAR));
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.PUT_FIELD));
assertThat(methodHandle.getName(), is(BAR));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is(TypeDescription.VOID));
assertThat(methodHandle.getParameterTypes(), is((List<TypeDescription>) new TypeList.ForLoadedTypes(Void.class)));
}
@Test
@SuppressWarnings("unchecked")
public void testMethodHandleOfStaticSetter() throws Exception {
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle.ofSetter(Foo.class.getDeclaredField(QUX));
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.PUT_STATIC_FIELD));
assertThat(methodHandle.getName(), is(QUX));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is(TypeDescription.VOID));
assertThat(methodHandle.getParameterTypes(), is((List<TypeDescription>) new TypeList.ForLoadedTypes(Void.class)));
}
@Test
@SuppressWarnings("unchecked")
@JavaVersionRule.Enforce(value = 7, hotSpot = 7)
public void testMethodHandleOfLoadedMethodHandle() throws Exception {
Method publicLookup = Class.forName("java.lang.invoke.MethodHandles").getDeclaredMethod("publicLookup");
Object lookup = publicLookup.invoke(null);
Method unreflected = Class.forName("java.lang.invoke.MethodHandles$Lookup").getDeclaredMethod("unreflect", Method.class);
Object methodHandleLoaded = unreflected.invoke(lookup, Foo.class.getDeclaredMethod(BAR, Void.class));
JavaConstant.MethodHandle methodHandle = JavaConstant.MethodHandle.ofLoaded(methodHandleLoaded);
assertThat(methodHandle.getHandleType(), is(JavaConstant.MethodHandle.HandleType.INVOKE_VIRTUAL));
assertThat(methodHandle.getName(), is(BAR));
assertThat(methodHandle.getOwnerType(), is((TypeDescription) new TypeDescription.ForLoadedType(Foo.class)));
assertThat(methodHandle.getReturnType(), is(TypeDescription.VOID));
assertThat(methodHandle.getParameterTypes(), is((List<TypeDescription>) new TypeList.ForLoadedTypes(Void.class)));
}
@Test(expected = IllegalArgumentException.class)
@JavaVersionRule.Enforce(value = 7, hotSpot = 7)
public void testMethodHandleLoadedIllegal() throws Exception {
JavaConstant.MethodHandle.ofLoaded(new Object());
}
@Test(expected = IllegalArgumentException.class)
@JavaVersionRule.Enforce(value = 7, hotSpot = 7)
public void testMethodHandleLoadedLookupIllegal() throws Exception {
Method publicLookup = Class.forName("java.lang.invoke.MethodHandles").getDeclaredMethod("publicLookup");
Object lookup = publicLookup.invoke(null);
Method unreflect = Class.forName("java.lang.invoke.MethodHandles$Lookup").getDeclaredMethod("unreflect", Method.class);
Object methodHandleLoaded = unreflect.invoke(lookup, Foo.class.getDeclaredMethod(BAR, Void.class));
JavaConstant.MethodHandle.ofLoaded(methodHandleLoaded, new Object());
}
@Test(expected = IllegalArgumentException.class)
public void testIllegalParameterThrowsException() throws Exception {
JavaConstant.MethodHandle.HandleType.of(-1);
}
@Test(expected = IllegalArgumentException.class)
public void testStaticMethodNotSpecial() throws Exception {
MethodDescription.InDefinedShape methodDescription = mock(MethodDescription.InDefinedShape.class);
TypeDescription typeDescription = mock(TypeDescription.class);
when(methodDescription.isStatic()).thenReturn(true);
when(methodDescription.isSpecializableFor(typeDescription)).thenReturn(true);
JavaConstant.MethodHandle.ofSpecial(methodDescription, typeDescription);
}
@Test(expected = IllegalArgumentException.class)
public void testAbstractMethodNotSpecial() throws Exception {
MethodDescription.InDefinedShape methodDescription = mock(MethodDescription.InDefinedShape.class);
TypeDescription typeDescription = mock(TypeDescription.class);
when(methodDescription.isAbstract()).thenReturn(true);
when(methodDescription.isSpecializableFor(typeDescription)).thenReturn(true);
JavaConstant.MethodHandle.ofSpecial(methodDescription, typeDescription);
}
@Test(expected = IllegalArgumentException.class)
public void testMethodNotSpecializable() throws Exception {
MethodDescription.InDefinedShape methodDescription = mock(MethodDescription.InDefinedShape.class);
TypeDescription typeDescription = mock(TypeDescription.class);
when(methodDescription.isSpecializableFor(typeDescription)).thenReturn(false);
JavaConstant.MethodHandle.ofSpecial(methodDescription, typeDescription);
}
@Test
public void testObjectProperties() throws Exception {
ObjectPropertyAssertion.of(JavaConstant.MethodHandle.class).apply();
ObjectPropertyAssertion.of(JavaConstant.MethodHandle.Dispatcher.CreationAction.class).apply();
final Iterator<Method> methods = Arrays.asList(String.class.getDeclaredMethods()).iterator();
final Iterator<Constructor<?>> constructors= Arrays.asList(String.class.getDeclaredConstructors()).iterator();
ObjectPropertyAssertion.of(JavaConstant.MethodHandle.Dispatcher.ForJava7CapableVm.class).create(new ObjectPropertyAssertion.Creator<Method>() {
@Override
public Method create() {
return methods.next();
}
}).create(new ObjectPropertyAssertion.Creator<Constructor<?>>() {
@Override
public Constructor<?> create() {
return constructors.next();
}
}).apply();
ObjectPropertyAssertion.of(JavaConstant.MethodHandle.Dispatcher.ForJava8CapableVm.class).create(new ObjectPropertyAssertion.Creator<Method>() {
@Override
public Method create() {
return methods.next();
}
}).create(new ObjectPropertyAssertion.Creator<Constructor<?>>() {
@Override
public Constructor<?> create() {
return constructors.next();
}
}).apply();
ObjectPropertyAssertion.of(JavaConstant.MethodHandle.Dispatcher.ForLegacyVm.class).apply();
ObjectPropertyAssertion.of(JavaConstant.MethodHandle.HandleType.class).apply();
}
@SuppressWarnings("unused")
public static class Foo {
public static Void qux;
public Void bar;
public Foo(Void value) {
/* empty*/
}
public static void qux(Void value) {
/* empty */
}
public void bar(Void value) {
/* empty */
}
}
}