@Override public void overrideMethod(ClassMethod method, Method superclassMethod) { CodeAttribute ca = method.getCodeAttribute(); if (method.getName().equals("_getProxyInvocationDispatcher")) { ca.aload(0); ca.getfield(getClassName(), INVOCATION_DISPATCHER_FIELD, InvocationDispatcher.class); ca.returnInstruction(); } else if (method.getName().equals("_setProxyInvocationDispatcher")) { ca.aload(0); ca.aload(1); ca.putfield(getClassName(), INVOCATION_DISPATCHER_FIELD, InvocationDispatcher.class); ca.returnInstruction(); } else { throw new RuntimeException("Unkown method on interface " + ProxyInstance.class); } }
// we simply want to load the corresponding identifier // and then forward it to the dispatcher @Override public void overrideMethod(ClassMethod method, Method superclassMethod) { CodeAttribute ca = method.getCodeAttribute(); // first we need to check the constructed field ca.aload(0); ca.getfield(getClassName(), CONSTRUCTED_GUARD, "Z"); // if the object has not been constructed yet invoke the superclass version of the method BranchEnd end = ca.ifne(); ca.aload(0); ca.loadMethodParameters(); ca.invokespecial(getSuperClassName(), method.getName(), method.getDescriptor()); ca.returnInstruction(); // normal invocation path begins here ca.branchEnd(end); ca.aload(0); ca.getfield(getClassName(), INVOCATION_DISPATCHER_FIELD, InvocationDispatcher.class); // now we have the dispatcher on the stack, we need to build an invocation ca.newInstruction(Invocation.class.getName()); ca.dup(); // the constructor we are using is Invocation(final Class<?> declaringClass, final // MethodIdentifier // methodIdentifier, final Object... args) ca.loadClass(getClassName()); loadMethodIdentifier(superclassMethod, method); // now we need to stick the parameters into an array, boxing if nessesary String[] params = method.getParameters(); ca.iconst(params.length); ca.anewarray("java/lang/Object"); int loadPosition = 1; for (int i = 0; i < params.length; ++i) { ca.dup(); ca.iconst(i); String type = params[i]; if (type.length() == 1) { // primitive char typeChar = type.charAt(0); switch (typeChar) { case 'I': ca.iload(loadPosition); Boxing.boxInt(ca); break; case 'S': ca.iload(loadPosition); Boxing.boxShort(ca); break; case 'B': ca.iload(loadPosition); Boxing.boxByte(ca); break; case 'Z': ca.iload(loadPosition); Boxing.boxBoolean(ca); break; case 'C': ca.iload(loadPosition); Boxing.boxChar(ca); break; case 'D': ca.dload(loadPosition); Boxing.boxDouble(ca); loadPosition++; break; case 'J': ca.lload(loadPosition); Boxing.boxLong(ca); loadPosition++; break; case 'F': ca.fload(loadPosition); Boxing.boxFloat(ca); break; default: throw new RuntimeException("Unkown primitive type descriptor: " + typeChar); } } else { ca.aload(loadPosition); } ca.aastore(); loadPosition++; } ca.invokespecial( Invocation.class.getName(), "<init>", "(Ljava/lang/Class;Lorg/jboss/invocation/MethodIdentifier;[Ljava/lang/Object;)V"); // now we have the invocation on top of the stack, with the dispatcher below it ca.invokeinterface( InvocationDispatcher.class.getName(), "dispatch", "(Lorg/jboss/invocation/Invocation;)Lorg/jboss/invocation/InvocationReply;"); ca.invokevirtual(InvocationReply.class.getName(), "getReply", "()Ljava/lang/Object;"); if (superclassMethod.getReturnType() != void.class) { if (superclassMethod.getReturnType().isPrimitive()) { Boxing.unbox(ca, method.getReturnType()); } else { ca.checkcast(superclassMethod.getReturnType().getName()); } } ca.returnInstruction(); }