Skip to content

Commit

Permalink
Added further tests and documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rafael Winterhalter committed Mar 31, 2015
1 parent 9a123b9 commit b2e8e77
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 126 deletions.
Expand Up @@ -2986,6 +2986,11 @@ public static class WithImplicitFieldType extends InvokeDynamic {
*/
private final Object value;

/**
* An argument provider that represents the argument with an implicit type.
*/
private final InvocationProvider.ArgumentProvider argumentProvider;

/**
* Creates a new invoke dynamic instance with an implicit field type for the provided value.
*
Expand All @@ -3006,6 +3011,7 @@ protected WithImplicitFieldType(MethodDescription bootstrapMethod,
Object value) {
super(bootstrapMethod, handleArguments, invocationProvider, terminationHandler, assigner, dynamicallyTyped);
this.value = value;
this.argumentProvider = InvocationProvider.ArgumentProvider.ForStaticField.of(value);
}

/**
Expand All @@ -3030,10 +3036,10 @@ public InvokeDynamic as(TypeDescription typeDescription) {
if (!typeDescription.isInstance(value)) {
throw new IllegalArgumentException("Cannot assign " + value + " to " + typeDescription);
}
InvocationProvider.ArgumentProvider argumentProvider = new InvocationProvider.ArgumentProvider.ForStaticField(value, typeDescription);
return new InvokeDynamic(bootstrapMethod,
handleArguments,
invocationProvider.appendArguments(Collections.<InvocationProvider.ArgumentProvider>singletonList(new InvocationProvider
.ArgumentProvider.ForStaticField(value, typeDescription))),
invocationProvider.appendArguments(Collections.singletonList(argumentProvider)),
terminationHandler,
assigner,
dynamicallyTyped);
Expand All @@ -3045,10 +3051,9 @@ public InvokeDynamic as(TypeDescription typeDescription) {
* @return An invoke dynamic instance with the representated value of this instance added to the invocation provider.
*/
private InvokeDynamic materialize() {

return new InvokeDynamic(bootstrapMethod,
handleArguments,
invocationProvider.appendArguments(Collections.singletonList(InvocationProvider.ArgumentProvider.ForStaticField.of(value))),
invocationProvider.appendArguments(Collections.singletonList(argumentProvider)),
terminationHandler,
assigner,
dynamicallyTyped);
Expand Down
Expand Up @@ -21,6 +21,7 @@
import net.bytebuddy.instrumentation.type.TypeDescription;
import net.bytebuddy.instrumentation.type.TypeList;
import net.bytebuddy.utility.JavaInstance;
import net.bytebuddy.utility.JavaType;
import net.bytebuddy.utility.RandomString;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
Expand Down Expand Up @@ -229,6 +230,13 @@ public MethodCall with(Object... argument) {
dynamicallyTyped);
}

/**
* Defines the given types to be provided as arguments to the invoked method where the represented types
* are stored in the generated class's constant pool.
*
* @param typeDescription The type descriptions to provide as arguments.
* @return A method call that hands the provided arguments to the invoked method.
*/
public MethodCall with(TypeDescription... typeDescription) {
List<ArgumentLoader> argumentLoaders = new ArrayList<ArgumentLoader>(typeDescription.length);
for (TypeDescription aTypeDescription : typeDescription) {
Expand All @@ -243,6 +251,13 @@ public MethodCall with(TypeDescription... typeDescription) {
dynamicallyTyped);
}

/**
* Defines the given Java instances to be provided as arguments to the invoked method where the given
* instances are stored in the generated class's constant pool.
*
* @param javaInstance The Java instances to provide as arguments.
* @return A method call that hands the provided arguments to the invoked method.
*/
public MethodCall with(JavaInstance... javaInstance) {
List<ArgumentLoader> argumentLoaders = new ArrayList<ArgumentLoader>(javaInstance.length);
for (JavaInstance aJavaInstance : javaInstance) {
Expand Down Expand Up @@ -981,26 +996,30 @@ protected ForStaticField(Object value) {
public static ArgumentLoader of(Object value) {
if (value == null) {
return ForNullConstant.INSTANCE;
} else if (value.getClass() == String.class) {
} else if (value instanceof String) {
return new ForTextConstant((String) value);
} else if (value.getClass() == Boolean.class) {
} else if (value instanceof Boolean) {
return new ForBooleanConstant((Boolean) value);
} else if (value.getClass() == Byte.class) {
} else if (value instanceof Byte) {
return new ForByteConstant((Byte) value);
} else if (value.getClass() == Short.class) {
} else if (value instanceof Short) {
return new ForShortConstant((Short) value);
} else if (value.getClass() == Character.class) {
} else if (value instanceof Character) {
return new ForCharacterConstant((Character) value);
} else if (value.getClass() == Integer.class) {
} else if (value instanceof Integer) {
return new ForIntegerConstant((Integer) value);
} else if (value.getClass() == Long.class) {
} else if (value instanceof Long) {
return new ForLongConstant((Long) value);
} else if (value.getClass() == Float.class) {
} else if (value instanceof Float) {
return new ForFloatConstant((Float) value);
} else if (value.getClass() == Double.class) {
} else if (value instanceof Double) {
return new ForDoubleConstant((Double) value);
} else if (value.getClass() == Class.class) {
} else if (value instanceof Class) {
return new ForClassConstant(new TypeDescription.ForLoadedType((Class<?>) value));
} else if (JavaType.METHOD_HANDLE.getTypeStub().isInstance(value)) {
return new ForJavaInstance(JavaInstance.MethodHandle.of(value));
} else if (JavaType.METHOD_TYPE.getTypeStub().isInstance(value)) {
return new ForJavaInstance(JavaInstance.MethodType.of(value));
} else {
return new ForStaticField(value);
}
Expand Down Expand Up @@ -1771,10 +1790,21 @@ public String toString() {
}
}

/**
* Loads a Java instance onto the operand stack.
*/
class ForJavaInstance implements ArgumentLoader {

/**
* The Java instance to load onto the operand stack.
*/
private final JavaInstance javaInstance;

/**
* Creates a new argument loader for a Java instance.
*
* @param javaInstance The Java instance to load as an argument.
*/
public ForJavaInstance(JavaInstance javaInstance) {
this.javaInstance = javaInstance;
}
Expand Down
Expand Up @@ -230,7 +230,7 @@ public void testBootstrapOfMethodsWithParametersWrapperReference() throws Except
.withReference(makeMethodHandle()).as(JavaType.METHOD_HANDLE.load()) // avoid direct method handle
.withReference(value),
classLoader,
isDeclaredBy(Simple.class));
isDeclaredBy(Simple.class));
assertThat(dynamicType.getLoaded().getDeclaredFields().length, is(13));
assertThat(dynamicType.getLoaded().newInstance().foo(),
is("" + BOOLEAN + BYTE + SHORT + CHARACTER + INTEGER + LONG + FLOAT + DOUBLE + FOO + CLASS + makeMethodType(CLASS) + makeMethodHandle() + value));
Expand Down
Expand Up @@ -2,13 +2,16 @@

import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.instrumentation.method.MethodDescription;
import net.bytebuddy.instrumentation.method.MethodList;
import net.bytebuddy.instrumentation.method.bytecode.stack.StackManipulation;
import net.bytebuddy.instrumentation.method.bytecode.stack.assign.Assigner;
import net.bytebuddy.instrumentation.method.bytecode.stack.constant.TextConstant;
import net.bytebuddy.instrumentation.method.bytecode.stack.member.MethodReturn;
import net.bytebuddy.instrumentation.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.test.utility.*;
import net.bytebuddy.utility.JavaInstance;
import net.bytebuddy.utility.JavaType;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand Down Expand Up @@ -54,35 +57,34 @@ public void setUp() throws Exception {
classLoader = new PrecompiledTypeClassLoader(getClass().getClassLoader());
}


@Test
public void testStaticMethodInvocationWithoutArguments() throws Exception {
DynamicType.Loaded<StaticMethod> loaded = instrument(StaticMethod.class,
MethodCall.invoke(StaticMethod.class.getDeclaredMethod(BAR)),
StaticMethod.class.getClassLoader(),
DynamicType.Loaded<SimpleMethod> loaded = instrument(SimpleMethod.class,
MethodCall.invoke(SimpleMethod.class.getDeclaredMethod(BAR)),
SimpleMethod.class.getClassLoader(),
named(FOO));
assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0));
assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1));
assertThat(loaded.getLoaded().getDeclaredFields().length, is(0));
StaticMethod instance = loaded.getLoaded().newInstance();
SimpleMethod instance = loaded.getLoaded().newInstance();
assertThat(instance.foo(), is(BAR));
assertNotEquals(StaticMethod.class, instance.getClass());
assertThat(instance, instanceOf(StaticMethod.class));
assertNotEquals(SimpleMethod.class, instance.getClass());
assertThat(instance, instanceOf(SimpleMethod.class));
}

@Test
public void testExternalStaticMethodInvocationWithoutArguments() throws Exception {
DynamicType.Loaded<StaticMethod> loaded = instrument(StaticMethod.class,
DynamicType.Loaded<SimpleMethod> loaded = instrument(SimpleMethod.class,
MethodCall.invoke(StaticExternalMethod.class.getDeclaredMethod(BAR)),
StaticMethod.class.getClassLoader(),
SimpleMethod.class.getClassLoader(),
named(FOO));
assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0));
assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1));
assertThat(loaded.getLoaded().getDeclaredFields().length, is(0));
StaticMethod instance = loaded.getLoaded().newInstance();
SimpleMethod instance = loaded.getLoaded().newInstance();
assertThat(instance.foo(), is(BAR));
assertNotEquals(StaticMethod.class, instance.getClass());
assertThat(instance, instanceOf(StaticMethod.class));
assertNotEquals(SimpleMethod.class, instance.getClass());
assertThat(instance, instanceOf(SimpleMethod.class));
}

@Test
Expand Down Expand Up @@ -359,6 +361,56 @@ public void testWithFieldTarget() throws Exception {
assertThat(instance.foo(), is(target.toString()));
}

@Test
public void testUnloadedType() throws Exception {
DynamicType.Loaded<SimpleMethod> loaded = instrument(SimpleMethod.class,
MethodCall.invoke(Foo.class.getDeclaredMethod(BAR, Object.class, Object.class))
.with(new TypeDescription.ForLoadedType(Object.class), new TypeDescription.ForLoadedType(String.class)),
SimpleMethod.class.getClassLoader(),
named(FOO));
assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0));
assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1));
assertThat(loaded.getLoaded().getDeclaredFields().length, is(0));
SimpleMethod instance = loaded.getLoaded().newInstance();
assertThat(instance.foo(), is("" + Object.class + String.class));
assertNotEquals(SimpleMethod.class, instance.getClass());
assertThat(instance, instanceOf(SimpleMethod.class));
}

@Test
@JavaVersionRule.Enforce(7)
public void testJava7Types() throws Exception {
DynamicType.Loaded<SimpleMethod> loaded = instrument(SimpleMethod.class,
MethodCall.invoke(Foo.class.getDeclaredMethod(BAR, Object.class, Object.class))
.with(makeMethodHandle(), makeMethodType(void.class)),
SimpleMethod.class.getClassLoader(),
named(FOO));
assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0));
assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1));
assertThat(loaded.getLoaded().getDeclaredFields().length, is(0));
SimpleMethod instance = loaded.getLoaded().newInstance();
assertThat(instance.foo(), is("" + makeMethodHandle() + makeMethodType(void.class)));
assertNotEquals(SimpleMethod.class, instance.getClass());
assertThat(instance, instanceOf(SimpleMethod.class));
}

@Test
@JavaVersionRule.Enforce(7)
public void testJava7TypesExplicit() throws Exception {
DynamicType.Loaded<SimpleMethod> loaded = instrument(SimpleMethod.class,
MethodCall.invoke(Foo.class.getDeclaredMethod(BAR, Object.class, Object.class))
.with(JavaInstance.MethodHandle.of(makeMethodHandle()), JavaInstance.MethodType.of(makeMethodType(void.class))),
SimpleMethod.class.getClassLoader(),
named(FOO));
assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0));
assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1));
assertThat(loaded.getLoaded().getDeclaredFields().length, is(0));
SimpleMethod instance = loaded.getLoaded().newInstance();
assertThat(instance.foo(), is("" + makeMethodHandle() + makeMethodType(void.class)));
assertNotEquals(SimpleMethod.class, instance.getClass());
assertThat(instance, instanceOf(SimpleMethod.class));
}

@Test
@JavaVersionRule.Enforce(8)
public void testDefaultMethod() throws Exception {
Expand Down Expand Up @@ -454,9 +506,10 @@ public void testObjectProperties() throws Exception {
ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForShortConstant.class).apply();
ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForTextConstant.class).apply();
ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForClassConstant.class).apply();
ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForJavaInstance.class).apply();
}

public static class StaticMethod {
public static class SimpleMethod {

public String foo() {
return null;
Expand Down Expand Up @@ -485,10 +538,6 @@ public String bar() {
}
}

public static class SuperConstructorCall {
/* empty */
}

public static class SelfReference {

public SelfReference foo() {
Expand Down Expand Up @@ -561,4 +610,20 @@ public static String bar(String value) {
return null;
}
}

private static Object makeMethodType(Class<?> returnType, Class<?>... parameterType) throws Exception {
return JavaType.METHOD_TYPE.load().getDeclaredMethod("methodType", Class.class, Class[].class).invoke(null, returnType, parameterType);
}

public static class Foo {
public static String bar(Object arg0, Object arg1) {
return "" + arg0 + arg1;
}
}

private static Object makeMethodHandle() throws Exception {
Object lookup = Class.forName("java.lang.invoke.MethodHandles").getDeclaredMethod("publicLookup").invoke(null);
return JavaType.METHOD_HANDLES_LOOKUP.load().getDeclaredMethod("findStatic", Class.class, String.class, JavaType.METHOD_TYPE.load())
.invoke(lookup, Foo.class, BAR, makeMethodType(String.class, Object.class, Object.class));
}
}

This file was deleted.

0 comments on commit b2e8e77

Please sign in to comment.