clazz.addMethod(mg.getMethod());
}
static void generate(ClassGen clazz, MethodRef method, FieldGen dataField,
FieldGen handlerField, MethodRef handlerMethodRef) {
ConstantPoolGen cp;
InstructionList il;
cp = clazz.getConstantPool();
il = new InstructionList();
InstructionFactory fac = new InstructionFactory(clazz, cp);
Type methodReturnType = translate(method.getReturnType());
Type[] methodArgTypes = translate(method.getParameterTypes());
MethodGen mg = new MethodGen(
Constants.ACC_FINAL | Constants.ACC_PUBLIC, methodReturnType,
methodArgTypes, null, // arg names
method.getName(), clazz.getClassName(), il, cp);
mg.addAttribute(new Synthetic(cp.addUtf8("Synthetic"), 0, null, cp
.getConstantPool()));
Class[] throwsException = method.getExceptionTypes();
for (int i = 0; i < throwsException.length; i++) {
mg.addException(throwsException[i].getName());
}
//
// BODY
//
il.append(InstructionFactory.createThis());
il.append(fac.createGetField(clazz.getClassName(), handlerField
.getName(), handlerField.getType()));
// push "this" as invoke's first argument
il.append(InstructionFactory.createThis());
// load data value
if (dataField.isStatic()) {
il.append(fac.createGetStatic(clazz.getClassName(), dataField
.getName(), dataField.getType()));
} else {
il.append(InstructionFactory.createThis());
il.append(fac.createGetField(clazz.getClassName(), dataField
.getName(), dataField.getType()));
}
il.append(new PUSH(cp, methodArgTypes.length));
il.append((Instruction) fac.createNewArray(Type.OBJECT, (short) 1));
int index = 1;
for (int i = 0; i < methodArgTypes.length; i++) {
// dup array ref
il.append(InstructionConstants.DUP);
// push index
il.append(new PUSH(cp, i));
// transform parameter
il.append(InstructionFactory.createLoad(methodArgTypes[i], index));
emitCoerceToObject(il, fac, methodArgTypes[i]);
// and store into array
il.append(InstructionFactory.createArrayStore(Type.OBJECT));
index += methodArgTypes[i].getSize();
}
//
// invoke handler's method
//
InstructionHandle tryStart = emitInvoke(il, fac, handlerMethodRef);
// convert to primitive type
emitCoerceFromObject(il, fac, methodReturnType);
// and return
InstructionHandle tryEnd = emitReturn(il, methodReturnType);
//
// catch...
//
InstructionHandle rethrowLocation = il.append(new ATHROW());
Class[] exceptions = method.getExceptionTypes();
boolean handle_throwable_exception = true;
boolean handle_runtime_exception = true;
if (exceptions != null) {
for (int i = 0; i < exceptions.length; i++) {
Class ex = exceptions[i];
if (ex == java.lang.Throwable.class)
handle_throwable_exception = false;
if (ex == java.lang.RuntimeException.class
|| ex == java.lang.Exception.class)
handle_runtime_exception = false;
mg.addExceptionHandler(tryStart, tryEnd, rethrowLocation,
(ObjectType) translate(ex));
}
}
// A RuntimeException should not cause an
// UndeclaredThrowableException, so we catch and re-throw it
// that before throwable.
if (handle_throwable_exception && handle_runtime_exception) {
mg.addExceptionHandler(tryStart, tryEnd, rethrowLocation,
new ObjectType("java.lang.RuntimeException"));
}
// If anything else is thrown, it is wrapped in an
// UndeclaredThrowable
if (handle_throwable_exception) {
InstructionHandle handlerStart = il.append(new ASTORE(1));
il
.append(new NEW(
cp
.addClass("java.lang.reflect.UndeclaredThrowableException")));
il.append(InstructionConstants.DUP);
il.append(new ALOAD(1));
il.append(new INVOKESPECIAL(cp.addMethodref(
"java.lang.reflect.UndeclaredThrowableException", "<init>",
"(Ljava/lang/Throwable;)V")));
il.append(new ATHROW());