Package org.apache.aries.proxy.impl.weaving

Source Code of org.apache.aries.proxy.impl.weaving.MethodCopyingClassAdapter$CopyingMethodAdapter

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.aries.proxy.impl.weaving;

import java.util.Map;
import java.util.Set;

import org.apache.aries.proxy.FinalModifierException;
import org.apache.aries.proxy.UnableToProxyException;
import org.apache.aries.proxy.impl.NLS;
import org.apache.aries.proxy.impl.common.AbstractWovenProxyAdapter;
import org.apache.aries.proxy.impl.common.TypeMethod;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.EmptyVisitor;
import org.objectweb.asm.commons.Method;

/**
* This class is used to copy methods from a super-class into a sub-class, but
* then delegate up to the super-class implementation. We expect to be called
* with {@link ClassReader#SKIP_CODE}. This class is used when we can't weave
* all the way up the Class hierarchy and need to override methods on the first
* subclass we can weave.
*/
final class MethodCopyingClassAdapter extends EmptyVisitor implements Opcodes {
  /** The sub-class visitor to write to */
  private final ClassVisitor cv;
  /** The super-class to copy from */
  private final Class<?> superToCopy;
  /** Is the sub-class in the same package as the super */
  private final boolean samePackage;
  /** The ASM {@link Type} of the sub-class */
  private final Type overridingClassType;
  /**
   * The Set of {@link Method}s that exist in the sub-class. This set must be
   * live so modifications will be reflected in the parent and prevent clashes
   */
  private final Set<Method> knownMethods;
  /**
   * The map of field names to methods being added
   */
  private final Map<String, TypeMethod> transformedMethods;
 
  public MethodCopyingClassAdapter(ClassVisitor cv, Class<?> superToCopy,
      Type overridingClassType, Set<Method> knownMethods,
      Map<String, TypeMethod> transformedMethods) {
    this.cv = cv;
    this.superToCopy = superToCopy;
    this.overridingClassType = overridingClassType;
    this.knownMethods = knownMethods;
    this.transformedMethods = transformedMethods;
   
    String overridingClassName = overridingClassType.getClassName();
    int lastIndex1 = superToCopy.getName().lastIndexOf('.');
    int lastIndex2 = overridingClassName.lastIndexOf('.');
   
    samePackage = (lastIndex1 == lastIndex2) &&
       superToCopy.getName().substring(0, (lastIndex1 == -1)? 1 : lastIndex1)
       .equals(overridingClassName.substring(0, (lastIndex2 == -1)? 1 : lastIndex2));
  }
 
  @Override
  public final MethodVisitor visitMethod(final int access, String name, String desc,
      String sig, String[] exceptions) {
   
    MethodVisitor mv = null;
    //As in WovenProxyAdapter, we only care about "real" methods.
    if (!!!name.equals("<init>") && !!!name.equals("<clinit>")
        && (access & (ACC_STATIC | ACC_PRIVATE | ACC_SYNTHETIC | ACC_ABSTRACT
            | ACC_NATIVE | ACC_BRIDGE)) == 0) {

      // identify the target method parameters and return type
      Method currentTransformMethod = new Method(name, desc);
      // We don't want to duplicate a method we already overrode!
      if(!!!knownMethods.add(currentTransformMethod))
        return null;
     
      // found a method we should weave
      // We can't override a final method
      if((access & ACC_FINAL) != 0)
        throw new RuntimeException(new FinalModifierException(
            superToCopy, name));
      // We can't call up to a package protected method if we aren't in the same
      // package
      if((access & (ACC_PUBLIC | ACC_PROTECTED | ACC_PRIVATE)) == 0) {
        if(!!!samePackage)
          throw new RuntimeException(NLS.MESSAGES.getMessage("method.from.superclass.is.hidden", name, superToCopy.getName(), overridingClassType.getClassName()),
                                     new UnableToProxyException(superToCopy));
      }
      //Safe to copy a call to this method!
      Type superType = Type.getType(superToCopy);
     
      // identify the target method parameters and return type
      String methodStaticFieldName = "methodField" + AbstractWovenProxyAdapter.getSanitizedUUIDString();
      transformedMethods.put(methodStaticFieldName, new TypeMethod(
          superType, currentTransformMethod))
     
      //Remember we need to copy the fake method *and* weave it, use a
      //WovenProxyMethodAdapter as well as a CopyingMethodAdapter
      mv = new CopyingMethodAdapter(new WovenProxyMethodAdapter(cv.visitMethod(
          access, name, desc, sig, exceptions), access, name, desc, exceptions,
          methodStaticFieldName, currentTransformMethod, overridingClassType),
          superType, currentTransformMethod);
    }
   
    return mv;
  }
 
  /**
   * This class is used to prevent any method body being copied, instead replacing
   * the body with a call to the super-types implementation. The original annotations
   * attributes etc are all copied.
   */
  private static final class CopyingMethodAdapter extends EmptyVisitor {
    /** The visitor to delegate to */
    private final MethodVisitor mv;
    /** The type that declares this method (not the one that will override it) */
    private final Type superType;
    /** The method we are weaving */
    private final Method currentTransformMethod;
   
    public CopyingMethodAdapter(MethodVisitor mv, Type superType,
        Method currentTransformMethod) {
      this.mv = mv;
      this.superType = superType;
      this.currentTransformMethod = currentTransformMethod;
    }

    @Override
    public final AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
      return mv.visitAnnotation(arg0, arg1);
    }

    @Override
    public final AnnotationVisitor visitAnnotationDefault() {
      return mv.visitAnnotationDefault();
    }

    @Override
    public final AnnotationVisitor visitParameterAnnotation(int arg0, String arg1,
        boolean arg2) {
      return mv.visitParameterAnnotation(arg0, arg1, arg2);
    }
   
    @Override
    public final void visitAttribute(Attribute attr) {
      mv.visitAttribute(attr);
    }

    /**
     * We skip code for speed when processing super-classes, this means we
     * need to manually drive some methods here!
     */
    @Override
    public final void visitEnd() {
      mv.visitCode();
      writeBody();
      mv.visitMaxs(currentTransformMethod.getArgumentTypes().length + 1, 0);
      mv.visitEnd();
    }
   
    /**
     * This method loads this, any args, then invokes the super version of this
     */
    private final void writeBody() {
      mv.visitVarInsn(ALOAD, 0);
     
      int nargs = currentTransformMethod.getArgumentTypes().length;
     
      for(int i = 1 ; i <= nargs ; i++) {
        switch(currentTransformMethod.
               getArgumentTypes()[i - 1].getSort()) {
          case (Type.BOOLEAN) :
          case (Type.BYTE) :
          case (Type.CHAR) :
          case (Type.SHORT) :
          case (Type.INT) :
            mv.visitVarInsn(ILOAD, i);
            break;
          case (Type.FLOAT) :
            mv.visitVarInsn(FLOAD, i);
            break;
          case (Type.DOUBLE) :
            mv.visitVarInsn(DLOAD, i);
            break;
          case (Type.LONG) :
            mv.visitVarInsn(LLOAD, i);
            break;
          default :
            mv.visitVarInsn(ALOAD, i);
        }
      }
     
      mv.visitMethodInsn(INVOKESPECIAL, superType.getInternalName(),
          currentTransformMethod.getName(), currentTransformMethod.getDescriptor());
     
      switch(currentTransformMethod.getReturnType().getSort()) {
        case (Type.BOOLEAN) :
        case (Type.BYTE) :
        case (Type.CHAR) :
        case (Type.SHORT) :
        case (Type.INT) :
          mv.visitInsn(IRETURN);
          break;
        case (Type.VOID) :
          mv.visitInsn(RETURN);
          break;
        case (Type.FLOAT) :
          mv.visitInsn(FRETURN);
          break;
        case (Type.DOUBLE) :
          mv.visitInsn(DRETURN);
          break;
        case (Type.LONG) :
          mv.visitInsn(LRETURN);
          break;
        default :
          mv.visitInsn(ARETURN);
      }
    }
  }
}
TOP

Related Classes of org.apache.aries.proxy.impl.weaving.MethodCopyingClassAdapter$CopyingMethodAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.