/**
     * Gets the correct return instruction for a proxy method
     *
     * @param pool
     * @param methodDescriptor
     */
    public static void addReturnProxyMethod(String methodDescriptor, Bytecode b) {
      String ret = DescriptorUtils.getReturnType(methodDescriptor);
      // if the return type is larger than one then it is not a primitive
      // so just do an ARETURN
      if (ret.length() != 1) {
        b.addCheckcast(DescriptorUtils.getReturnTypeInJvmFormat(methodDescriptor));
        b.add(Opcode.ARETURN);
        return;
      }
      // void methods are special
      if (ret.equals("V")) {
        b.add(Opcode.RETURN);
        return;
      } else {
        // unbox the primitive type

        char tp = ret.charAt(0);
        Boxing.unbox(b, tp);
        if (tp == 'F') {
          b.add(Opcode.FRETURN);
        } else if (tp == 'D') {
          b.add(Opcode.DRETURN);
        } else if (tp == 'J') {
          b.add(Opcode.LRETURN);
        } else {
          b.add(Opcode.IRETURN);
        }
        return;
      }
    }
예제 #2
0
 public void getDeclaredMethod(
     ClassFile file,
     Bytecode code,
     String declaringClass,
     String methodName,
     String[] parameterTypes) {
   // get the correct class type to use to resolve the method
   MethodInformation methodInfo =
       new StaticMethodInformation(
           "getTargetClass",
           parameterTypes,
           "Ljava/lang/Class;",
           TargetInstanceProxy.class.getName());
   invokeMethodHandler(file, code, methodInfo, false, DEFAULT_METHOD_RESOLVER);
   code.addCheckcast("java/lang/Class");
   // now we have the class on the stack
   code.addLdc(methodName);
   // now we need to load the parameter types into an array
   code.addIconst(parameterTypes.length);
   code.addAnewarray("java.lang.Class");
   for (int i = 0; i < parameterTypes.length; ++i) {
     code.add(Opcode.DUP); // duplicate the array reference
     code.addIconst(i);
     // now load the class object
     String type = parameterTypes[i];
     BytecodeUtils.pushClassType(code, type);
     // and store it in the array
     code.add(Opcode.AASTORE);
   }
   code.addInvokevirtual(
       "java.lang.Class",
       "getDeclaredMethod",
       "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
 }
예제 #3
0
 public void atCastExpr(CastExpr expr) throws CompileError {
   String cname = resolveClassName(expr.getClassName());
   String toClass = checkCastExpr(expr, cname);
   int srcType = exprType;
   exprType = expr.getType();
   arrayDim = expr.getArrayDim();
   className = cname;
   if (toClass == null) atNumCastExpr(srcType, exprType); // built-in type
   else bytecode.addCheckcast(toClass);
 }
예제 #4
0
 /**
  * calls _initMH on the method handler and then stores the result in the methodHandler field as
  * then new methodHandler
  */
 private Bytecode createMethodHandlerInitializerBody(ClassFile proxyClassType) {
   Bytecode b = new Bytecode(proxyClassType.getConstPool(), 1, 2);
   b.add(Opcode.ALOAD_0);
   StaticMethodInformation methodInfo =
       new StaticMethodInformation(
           "_initMH", new Class[] {Object.class}, void.class, proxyClassType.getName());
   invokeMethodHandler(proxyClassType, b, methodInfo, false, DEFAULT_METHOD_RESOLVER);
   b.addCheckcast("javassist/util/proxy/MethodHandler");
   b.addPutfield(
       proxyClassType.getName(),
       "methodHandler",
       DescriptorUtils.classToStringRepresentation(MethodHandler.class));
   b.add(Opcode.RETURN);
   log.trace("Created MH initializer body for decorator proxy:  " + getBeanType());
   return b;
 }
  /**
   * Calls methodHandler.invoke with a null method parameter in order to get the underlying
   * instance. The invocation is then forwarded to this instance with generated bytecode.
   */
  protected Bytecode createForwardingMethodBody(ClassFile file, MethodInformation methodInfo)
      throws NotFoundException {
    Method method = methodInfo.getMethod();
    // we can only use bytecode based invocation for some methods
    // at the moment we restrict it solely to public methods with public
    // return and parameter types
    boolean bytecodeInvocationAllowed =
        Modifier.isPublic(method.getModifiers())
            && Modifier.isPublic(method.getReturnType().getModifiers());
    for (Class<?> paramType : method.getParameterTypes()) {
      if (!Modifier.isPublic(paramType.getModifiers())) {
        bytecodeInvocationAllowed = false;
        break;
      }
    }
    if (!bytecodeInvocationAllowed) {
      return createInterceptorBody(file, methodInfo);
    }
    Bytecode b = new Bytecode(file.getConstPool());
    int localCount = MethodUtils.calculateMaxLocals(method) + 1;

    // create a new interceptor invocation context whenever we invoke a method on a client proxy
    // we use a try-catch block in order to make sure that endInterceptorContext() is invoked
    // regardless whether
    // the method has succeeded or not
    int start = b.currentPc();
    b.addInvokestatic(
        "org.jboss.weld.bean.proxy.InterceptionDecorationContext",
        "startInterceptorContext",
        "()V");

    b.add(Opcode.ALOAD_0);
    b.addGetfield(
        file.getName(),
        "methodHandler",
        DescriptorUtils.classToStringRepresentation(MethodHandler.class));
    // pass null arguments to methodHandler.invoke
    b.add(Opcode.ALOAD_0);
    b.add(Opcode.ACONST_NULL);
    b.add(Opcode.ACONST_NULL);
    b.add(Opcode.ACONST_NULL);

    // now we have all our arguments on the stack
    // lets invoke the method
    b.addInvokeinterface(
        MethodHandler.class.getName(),
        "invoke",
        "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
        5);

    b.addCheckcast(methodInfo.getDeclaringClass());

    // now we should have the target bean instance on top of the stack
    // we need to dup it so we still have it to compare to the return value
    b.add(Opcode.DUP);

    // lets create the method invocation
    String methodDescriptor = methodInfo.getDescriptor();
    BytecodeUtils.loadParameters(b, methodDescriptor);
    if (method.getDeclaringClass().isInterface()) {
      b.addInvokeinterface(
          methodInfo.getDeclaringClass(),
          methodInfo.getName(),
          methodDescriptor,
          method.getParameterTypes().length + 1);
    } else {
      b.addInvokevirtual(methodInfo.getDeclaringClass(), methodInfo.getName(), methodDescriptor);
    }

    // end the interceptor context, everything was fine
    b.addInvokestatic(
        "org.jboss.weld.bean.proxy.InterceptionDecorationContext", "endInterceptorContext", "()V");

    // jump over the catch block
    b.addOpcode(Opcode.GOTO);
    JumpMarker gotoEnd = JumpUtils.addJumpInstruction(b);

    // create catch block
    b.addExceptionHandler(start, b.currentPc(), b.currentPc(), 0);
    b.addInvokestatic(
        "org.jboss.weld.bean.proxy.InterceptionDecorationContext", "endInterceptorContext", "()V");
    b.add(Opcode.ATHROW);

    // update the correct address to jump over the catch block
    gotoEnd.mark();

    // if this method returns a primitive we just return
    if (method.getReturnType().isPrimitive()) {
      BytecodeUtils.addReturnInstruction(b, methodInfo.getReturnType());
    } else {
      // otherwise we have to check that the proxy is not returning 'this;
      // now we need to check if the proxy has return 'this' and if so return
      // an
      // instance of the proxy.
      // currently we have result, beanInstance on the stack.
      b.add(Opcode.DUP_X1);
      // now we have result, beanInstance, result
      // we need to compare result and beanInstance

      // first we need to build up the inner conditional that just returns
      // the
      // result
      b.add(Opcode.IF_ACMPEQ);
      JumpMarker returnInstruction = JumpUtils.addJumpInstruction(b);
      BytecodeUtils.addReturnInstruction(b, methodInfo.getReturnType());
      returnInstruction.mark();

      // now add the case where the proxy returns 'this';
      b.add(Opcode.ALOAD_0);
      b.addCheckcast(methodInfo.getMethod().getReturnType().getName());
      BytecodeUtils.addReturnInstruction(b, methodInfo.getReturnType());
    }
    if (b.getMaxLocals() < localCount) {
      b.setMaxLocals(localCount);
    }
    return b;
  }