// be sync
// on the real object
int newAccess = access & (~ACC_NATIVE) & (~ACC_SYNCHRONIZED);
MethodVisitor mv = cv.visitMethod(newAccess, name, desc, signature, exceptions);
// use a GeneratorAdapter to build the invoke call directly in byte code
GeneratorAdapter methodAdapter = new GeneratorAdapter(mv, newAccess, name, desc);
/*
* Stage 1 creates the bytecode for adding the reflected method of the
* superclass to a static field in the subclass: private static Method
* methodName_parm1_parm2... = null; static{ methodName_parm1_parm2... =
* superClass.getDeclaredMethod(methodName,new Class[]{method args}; }
*
* Stage 2 is to call the ih.invoke(this,methodName_parm1_parm2,args) in
* the new subclass methods Stage 3 is to cast the return value to the
* correct type
*/
/*
* Stage 1 use superClass.getMethod(methodName,new Class[]{method args}
* from the Class object on the stack
*/
// load the static superclass Class onto the stack
staticAdapter.getStatic(newClassType, currentClassFieldName, CLASS_TYPE);
// push the method name string arg onto the stack
staticAdapter.push(name);
// create an array of the method parm class[] arg
staticAdapter.push(targetMethodParameters.length);
staticAdapter.newArray(CLASS_TYPE);
int index = 0;
for (Type t : targetMethodParameters) {
staticAdapter.dup();
staticAdapter.push(index);
switch (t.getSort())
{
case Type.BOOLEAN:
staticAdapter.getStatic(Type.getType(java.lang.Boolean.class), "TYPE", CLASS_TYPE);
break;
case Type.BYTE:
staticAdapter.getStatic(Type.getType(java.lang.Byte.class), "TYPE", CLASS_TYPE);
break;
case Type.CHAR:
staticAdapter.getStatic(Type.getType(java.lang.Character.class), "TYPE", CLASS_TYPE);
break;
case Type.DOUBLE:
staticAdapter.getStatic(Type.getType(java.lang.Double.class), "TYPE", CLASS_TYPE);
break;
case Type.FLOAT:
staticAdapter.getStatic(Type.getType(java.lang.Float.class), "TYPE", CLASS_TYPE);
break;
case Type.INT:
staticAdapter.getStatic(Type.getType(java.lang.Integer.class), "TYPE", CLASS_TYPE);
break;
case Type.LONG:
staticAdapter.getStatic(Type.getType(java.lang.Long.class), "TYPE", CLASS_TYPE);
break;
case Type.SHORT:
staticAdapter.getStatic(Type.getType(java.lang.Short.class), "TYPE", CLASS_TYPE);
break;
default:
case Type.OBJECT:
staticAdapter.push(t);
break;
}
staticAdapter.arrayStore(CLASS_TYPE);
index++;
}
// invoke the getMethod
staticAdapter.invokeVirtual(CLASS_TYPE, new Method("getDeclaredMethod", METHOD_TYPE,
new Type[] { STRING_TYPE, Type.getType(java.lang.Class[].class) }));
// store the reflected method in the static field
staticAdapter.putStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
/*
* Stage 2 call the ih.invoke(this,supermethod,parms)
*/
// load this to get the ih field
methodAdapter.loadThis();
// load the invocation handler from the field (the location of the
// InvocationHandler.invoke)
methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
// loadThis (the first arg of the InvocationHandler.invoke)
methodAdapter.loadThis();
// load the method to invoke (the second arg of the
// InvocationHandler.invoke)
methodAdapter.getStatic(newClassType, methodStaticFieldName, METHOD_TYPE);
// load all the method arguments onto the stack as an object array (the
// third arg of the InvocationHandler.invoke)
methodAdapter.loadArgArray();
// generate the invoke method
Method invocationHandlerInvokeMethod = new Method("invoke", OBJECT_TYPE, new Type[] {
OBJECT_TYPE, METHOD_TYPE, Type.getType(java.lang.Object[].class) });
// call the invoke method of the invocation handler
methodAdapter.invokeInterface(IH_TYPE, invocationHandlerInvokeMethod);
/*
* Stage 3 the returned object is now on the top of the stack We need to
* check the type and cast as necessary
*/
switch (returnType.getSort())
{
case Type.BOOLEAN:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Boolean.class));
methodAdapter.unbox(Type.BOOLEAN_TYPE);
break;
case Type.BYTE:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Byte.class));
methodAdapter.unbox(Type.BYTE_TYPE);
break;
case Type.CHAR:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Character.class));
methodAdapter.unbox(Type.CHAR_TYPE);
break;
case Type.DOUBLE:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Double.class));
methodAdapter.unbox(Type.DOUBLE_TYPE);
break;
case Type.FLOAT:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Float.class));
methodAdapter.unbox(Type.FLOAT_TYPE);
break;
case Type.INT:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Integer.class));
methodAdapter.unbox(Type.INT_TYPE);
break;
case Type.LONG:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Long.class));
methodAdapter.unbox(Type.LONG_TYPE);
break;
case Type.SHORT:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Short.class));
methodAdapter.unbox(Type.SHORT_TYPE);
break;
case Type.VOID:
methodAdapter.cast(OBJECT_TYPE, Type.getType(Void.class));
methodAdapter.unbox(Type.VOID_TYPE);
break;
default:
case Type.OBJECT:
// in this case check the cast and cast the object to the return
// type
methodAdapter.checkCast(returnType);
methodAdapter.cast(OBJECT_TYPE, returnType);
break;
}
// return the (appropriately cast) result of the invocation from the
// stack
methodAdapter.returnValue();
// end the method
methodAdapter.endMethod();
LOGGER.debug(Constants.LOG_EXIT, "processMethod");
}