Search in sources :

Example 1 with SystemModuleClassLoader

use of org.apache.aries.proxy.impl.SystemModuleClassLoader in project aries by apache.

the class AbstractWovenProxyAdapter method readClass.

/**
   * This method will read the bytes for the supplied {@link Class} using the
   * supplied ASM {@link ClassVisitor}, the reader will skip DEBUG, FRAMES and CODE.
   * @param c
   * @param adapter
   * @throws IOException
   */
public static void readClass(Class<?> c, ClassVisitor adapter) throws IOException {
    String className = c.getName().replace(".", "/") + ".class";
    //Load the class bytes and copy methods across
    ClassLoader loader = c.getClassLoader();
    if (loader == null) {
        //system class, use SystemModuleClassLoader as fallback
        loader = new SystemModuleClassLoader();
    }
    ClassReader cReader = new ClassReader(loader.getResourceAsStream(className));
    cReader.accept(adapter, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
}
Also used : SystemModuleClassLoader(org.apache.aries.proxy.impl.SystemModuleClassLoader) SystemModuleClassLoader(org.apache.aries.proxy.impl.SystemModuleClassLoader) ClassReader(org.objectweb.asm.ClassReader)

Example 2 with SystemModuleClassLoader

use of org.apache.aries.proxy.impl.SystemModuleClassLoader in project aries by apache.

the class ProxySubclassAdapter method visit.

/*
   * This method visits the class to generate the new subclass.
   * 
   * The following things happen here: 1. The class is renamed to a dynamic
   * name 2. The existing class name is changed to be the superclass name so
   * that the generated class extends the original class. 3. A private field
   * is added to store an invocation handler 4. A constructor is added that
   * takes an invocation handler as an argument 5. The constructor method
   * instantiates an instance of the superclass 6. The constructor method sets
   * the invocation handler so the invoke method can be called from all the
   * subsequently rewritten methods 7. Add a getInvocationHandler() method 8.
   * store a static Class object of the superclass so we can reflectively find
   * methods later
   */
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);
    }
    // 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");
}
Also used : Constructor(java.lang.reflect.Constructor) InputStream(java.io.InputStream) Method(org.objectweb.asm.commons.Method) ClassVisitor(org.objectweb.asm.ClassVisitor) IOException(java.io.IOException) InvocationHandler(java.lang.reflect.InvocationHandler) Type(org.objectweb.asm.Type) SystemModuleClassLoader(org.apache.aries.proxy.impl.SystemModuleClassLoader) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) SystemModuleClassLoader(org.apache.aries.proxy.impl.SystemModuleClassLoader) ClassReader(org.objectweb.asm.ClassReader)

Aggregations

SystemModuleClassLoader (org.apache.aries.proxy.impl.SystemModuleClassLoader)2 ClassReader (org.objectweb.asm.ClassReader)2 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 Constructor (java.lang.reflect.Constructor)1 InvocationHandler (java.lang.reflect.InvocationHandler)1 ClassVisitor (org.objectweb.asm.ClassVisitor)1 Type (org.objectweb.asm.Type)1 GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)1 Method (org.objectweb.asm.commons.Method)1