in asm/src/main/java/org/apache/commons/proxy2/asm/ASMProxyFactory.java [157:287]
private static void processMethod(final ClassWriter cw, final Method method, final Type proxyType,
final String handlerName) throws ProxyFactoryException
{
final Type sig = Type.getType(method);
final Type[] exceptionTypes = getTypes(method.getExceptionTypes());
// push the method definition
final int access = (ACC_PUBLIC | ACC_PROTECTED) & method.getModifiers();
final org.objectweb.asm.commons.Method m = org.objectweb.asm.commons.Method.getMethod(method);
final GeneratorAdapter mg = new GeneratorAdapter(access, m, null, getTypes(method.getExceptionTypes()), cw);
final Label tryBlock = exceptionTypes.length > 0 ? mg.mark() : null;
mg.push(Type.getType(method.getDeclaringClass()));
// the following code generates the bytecode for this line of Java:
// Method method = <proxy>.class.getMethod("add", new Class[] {
// <array of function argument classes> });
// get the method name to invoke, and push to stack
mg.push(method.getName());
// create the Class[]
mg.push(sig.getArgumentTypes().length);
final Type classType = Type.getType(Class.class);
mg.newArray(classType);
// push parameters into array
for (int i = 0; i < sig.getArgumentTypes().length; i++)
{
// keep copy of array on stack
mg.dup();
// push index onto stack
mg.push(i);
mg.push(sig.getArgumentTypes()[i]);
mg.arrayStore(classType);
}
// invoke getMethod() with the method name and the array of types
mg.invokeVirtual(classType, org.objectweb.asm.commons.Method
.getMethod("java.lang.reflect.Method getDeclaredMethod(String, Class[])"));
// store the returned method for later
// the following code generates bytecode equivalent to:
// return ((<returntype>) invoker.invoke(this, method, new Object[]
// { <function arguments }))[.<primitive>Value()];
mg.loadThis();
mg.getField(proxyType, handlerName, INVOKER_TYPE);
// put below method:
mg.swap();
// we want to pass "this" in as the first parameter
mg.loadThis();
// put below method:
mg.swap();
// need to construct the array of objects passed in
// create the Object[]
mg.push(sig.getArgumentTypes().length);
final Type objectType = Type.getType(Object.class);
mg.newArray(objectType);
// push parameters into array
for (int i = 0; i < sig.getArgumentTypes().length; i++)
{
// keep copy of array on stack
mg.dup();
// push index onto stack
mg.push(i);
mg.loadArg(i);
mg.valueOf(sig.getArgumentTypes()[i]);
mg.arrayStore(objectType);
}
// invoke the invoker
mg.invokeInterface(INVOKER_TYPE, org.objectweb.asm.commons.Method
.getMethod("Object invoke(Object, java.lang.reflect.Method, Object[])"));
// cast the result
mg.unbox(sig.getReturnType());
// push return
mg.returnValue();
// catch InvocationTargetException
if (exceptionTypes.length > 0)
{
final Type caughtExceptionType = Type.getType(InvocationTargetException.class);
mg.catchException(tryBlock, mg.mark(), caughtExceptionType);
final Label throwCause = new Label();
mg.invokeVirtual(caughtExceptionType,
org.objectweb.asm.commons.Method.getMethod("Throwable getCause()"));
for (int i = 0; i < exceptionTypes.length; i++)
{
mg.dup();
mg.push(exceptionTypes[i]);
mg.swap();
mg.invokeVirtual(classType,
org.objectweb.asm.commons.Method.getMethod("boolean isInstance(Object)"));
// if true, throw cause:
mg.ifZCmp(GeneratorAdapter.NE, throwCause);
}
// no exception types matched; throw
// UndeclaredThrowableException:
final int cause = mg.newLocal(Type.getType(Exception.class));
mg.storeLocal(cause);
final Type undeclaredType = Type.getType(UndeclaredThrowableException.class);
mg.newInstance(undeclaredType);
mg.dup();
mg.loadLocal(cause);
mg.invokeConstructor(undeclaredType, new org.objectweb.asm.commons.Method("<init>", Type.VOID_TYPE,
new Type[] { Type.getType(Throwable.class) }));
mg.throwException();
mg.mark(throwCause);
mg.throwException();
}
// finish this method
mg.endMethod();
}