public void visit()

in proxy/proxy-impl/src/main/java/org/apache/aries/proxy/impl/gen/ProxySubclassAdapter.java [100:311]


  public void visit(int version, int access, String name, String signature, String superName,
      String[] interfaces)
  {
    LOGGER.debug(Constants.LOG_ENTRY, "visit", new Object[] { version, access, name,
        signature, superName, interfaces });

    // store the superclass binary name
    this.superclassBinaryName = name.replaceAll("/", "\\.");

    try {
      this.superclassClass = Class.forName(superclassBinaryName, false, loader);
    } catch (ClassNotFoundException cnfe) {
      throw new TypeNotPresentException(superclassBinaryName, cnfe);
    }


    // keep the same access and signature as the superclass (unless it's abstract)
    // remove all the superclass interfaces because they will be inherited
    // from the superclass anyway
    if((access & ACC_ABSTRACT) != 0) {
      //If the super was abstract the subclass should not be!
      access &= ~ACC_ABSTRACT;
    }
    cv.visit(ProxyUtils.getWeavingJavaVersion(), access, newClassName, signature, name, null);

    // add a private field for the invocation handler
    // this isn't static in case we have multiple instances of the same
    // proxy
    cv.visitField(ACC_PRIVATE, IH_FIELD, Type.getDescriptor(InvocationHandler.class), null, null);

    // create a static adapter for generating a static initialiser method in
    // the generated subclass
    staticAdapter = new GeneratorAdapter(ACC_STATIC,
        new Method("<clinit>", Type.VOID_TYPE, NO_ARGS), null, null, cv);

    // add a zero args constructor method
    Method m = new Method("<init>", Type.VOID_TYPE, NO_ARGS);
    GeneratorAdapter methodAdapter = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cv);
    // loadthis
    methodAdapter.loadThis();
    // List the constructors in the superclass.
    Constructor<?>[] constructors = superclassClass.getDeclaredConstructors();
    // Check that we've got at least one constructor, and get the 1st one in the list.
    if (constructors.length > 0) {
      // We now need to construct the proxy class as though it is going to invoke the superclasses constructor.
      // We do this because we can no longer call the java.lang.Object() zero arg constructor as the JVM now throws a VerifyError.
      // So what we do is build up the calling of the superclasses constructor using nulls and default values. This means that the 
      // class bytes can be verified by the JVM, and then in the ProxySubclassGenerator, we load the class without invoking the 
      // constructor. 
      Method constructor = Method.getMethod(constructors[0]);      
      Type[] argTypes = constructor.getArgumentTypes();
      if (argTypes.length == 0) {
        methodAdapter.invokeConstructor(Type.getType(superclassClass), new Method("<init>", Type.VOID_TYPE, NO_ARGS));
      } else {
        for (Type type : argTypes) {
          switch (type.getSort())
          {
            case Type.ARRAY:
              // We need to process any array or multidimentional arrays.
              String elementDesc = type.getElementType().getDescriptor();
              String typeDesc = type.getDescriptor();
              
              // Iterate over the number of arrays and load 0 for each one. Keep a count of the number of 
              // arrays as we will need to run different code fo multi dimentional arrays.
              int index = 0;
              while (! elementDesc.equals(typeDesc)) {
                typeDesc = typeDesc.substring(1);
                methodAdapter.visitInsn(Opcodes.ICONST_0);
                index++;
              }
              // If we're just a single array, then call the newArray method, otherwise use the MultiANewArray instruction.
              if (index == 1) {
                methodAdapter.newArray(type.getElementType());
              } else {
                methodAdapter.visitMultiANewArrayInsn(type.getDescriptor(), index);
              }
              break;
            case Type.BOOLEAN:
              methodAdapter.push(true);
              break;
            case Type.BYTE:
              methodAdapter.push(Type.VOID_TYPE);
              break;
            case Type.CHAR:
              methodAdapter.push(Type.VOID_TYPE);
              break;
            case Type.DOUBLE:
              methodAdapter.push(0.0);
              break;
            case Type.FLOAT:
              methodAdapter.push(0.0f);
              break;
            case Type.INT:
              methodAdapter.push(0);
              break;
            case Type.LONG:
              methodAdapter.push(0l);
              break;
            case Type.SHORT:
              methodAdapter.push(0);
              break;
            default:
            case Type.OBJECT:
              methodAdapter.visitInsn(Opcodes.ACONST_NULL);
              break;
          }
        }
        
        methodAdapter.invokeConstructor(Type.getType(superclassClass), new Method("<init>", Type.VOID_TYPE, argTypes));
      }
    }
    methodAdapter.returnValue();
    methodAdapter.endMethod();

    // add a method for getting the invocation handler
    Method setter = new Method("setInvocationHandler", Type.VOID_TYPE, new Type[] { IH_TYPE });
    m = new Method("getInvocationHandler", IH_TYPE, NO_ARGS);
    methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, m, null, null, cv);
    // load this to get the field
    methodAdapter.loadThis();
    // get the ih field and return
    methodAdapter.getField(newClassType, IH_FIELD, IH_TYPE);
    methodAdapter.returnValue();
    methodAdapter.endMethod();

    // add a method for setting the invocation handler
    methodAdapter = new GeneratorAdapter(ACC_PUBLIC | ACC_FINAL, setter, null, null, cv);
    // load this to put the field
    methodAdapter.loadThis();
    // load the method arguments (i.e. the invocation handler) to the stack
    methodAdapter.loadArgs();
    // set the ih field using the method argument
    methodAdapter.putField(newClassType, IH_FIELD, IH_TYPE);
    methodAdapter.returnValue();
    methodAdapter.endMethod();

    // loop through the class hierarchy to get any needed methods off the
    // supertypes
    // start by finding the methods declared on the class of interest (the
    // superclass of our dynamic subclass)
    java.lang.reflect.Method[] observedMethods = superclassClass.getDeclaredMethods();
    // add the methods to a set of observedMethods
    ProxySubclassMethodHashSet<String> setOfObservedMethods = new ProxySubclassMethodHashSet<String>(
        observedMethods.length);
    setOfObservedMethods.addMethodArray(observedMethods);
    // get the next superclass in the hierarchy
    Class<?> nextSuperClass = superclassClass.getSuperclass();
    while (nextSuperClass != null) {
      // set the fields for the current class
      setCurrentAnalysisClassFields(nextSuperClass);

      // add a static field and static initializer code to the generated
      // subclass
      // for each of the superclasses in the hierarchy
      addClassStaticField(currentlyAnalysedClassName);

      LOGGER.debug("Class currently being analysed: {} {}", currentlyAnalysedClassName,
          currentlyAnalysedClass);

      // now find the methods declared on the current class and add them
      // to a set of foundMethods
      java.lang.reflect.Method[] foundMethods = currentlyAnalysedClass.getDeclaredMethods();
      ProxySubclassMethodHashSet<String> setOfFoundMethods = new ProxySubclassMethodHashSet<String>(
          foundMethods.length);
      setOfFoundMethods.addMethodArray(foundMethods);
      // remove from the set of foundMethods any methods we saw on a
      // subclass
      // because we want to use the lowest level declaration of a method
      setOfFoundMethods.removeAll(setOfObservedMethods);
      try {
        // read the current class and use a
        // ProxySubclassHierarchyAdapter
        // to process only methods on that class that are in the list
        ClassLoader loader = currentlyAnalysedClass.getClassLoader();
        if (loader == null) {
          loader = this.loader;
        }
        InputStream is = loader.getResourceAsStream(currentlyAnalysedClass
                                                    .getName().replaceAll("\\.", "/")
                                                    + ".class");
        if (is == null) {
              //use SystemModuleClassLoader as fallback
              ClassLoader classLoader = new SystemModuleClassLoader();
              is = classLoader.getResourceAsStream(currentlyAnalysedClass
                                              .getName().replaceAll("\\.", "/")
                                              + ".class");
        }
        ClassReader cr = new ClassReader(is);
        ClassVisitor hierarchyAdapter = new ProxySubclassHierarchyAdapter(this, setOfFoundMethods);
        cr.accept(hierarchyAdapter, ClassReader.SKIP_DEBUG);
      } catch (IOException e) {
        throw new TypeNotPresentException(currentlyAnalysedClassName, e);
      }
      // now add the foundMethods to the overall list of observed methods
      setOfObservedMethods.addAll(setOfFoundMethods);
      // get the next class up in the hierarchy and go again
      nextSuperClass = currentlyAnalysedClass.getSuperclass();
    }

    // we've finished looking at the superclass hierarchy
    // set the fields for the immediate superclass of our dynamic subclass
    setCurrentAnalysisClassFields(superclassClass);

    // add the class static field
    addClassStaticField(currentlyAnalysedClassName);
    // we do the lowest class last because we are already visiting the class
    // when in this adapter code
    // now we are ready to visit all the methods on the lowest class
    // which will happen by the ASM ClassVisitor implemented in this adapter

    LOGGER.debug(Constants.LOG_EXIT, "visit");
  }