Package jodd.proxetta.asm

Source Code of jodd.proxetta.asm.TargetClassInfoReader

// Copyright (c) 2003-2014, Jodd Team (jodd.org). All Rights Reserved.

package jodd.proxetta.asm;

import jodd.asm.AsmUtil;
import jodd.asm5.MethodVisitor;
import jodd.asm5.ClassReader;
import jodd.asm5.AnnotationVisitor;
import jodd.asm5.signature.SignatureReader;

import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.io.InputStream;
import java.io.IOException;

import static jodd.proxetta.asm.ProxettaAsmUtil.INIT;
import static jodd.proxetta.asm.ProxettaAsmUtil.CLINIT;
import jodd.proxetta.ProxettaException;
import jodd.proxetta.ClassInfo;
import jodd.proxetta.AnnotationInfo;
import jodd.util.ClassLoaderUtil;
import jodd.io.StreamUtil;
import jodd.asm.EmptyClassVisitor;
import jodd.asm.EmptyMethodVisitor;

/**
* Reads info from target class.
*/
@SuppressWarnings({"AnonymousClassVariableHidesContainingMethodVariable"})
public class TargetClassInfoReader extends EmptyClassVisitor implements ClassInfo {

  //protected ClassInfo classInfo;

  protected final Map<String, MethodSignatureVisitor> methodSignatures;
  protected final List<ClassReader> superClassReaders;          // list of all super class readers
  protected final Set<String> allMethodSignatures;
  protected final ClassLoader classLoader;

  public TargetClassInfoReader(ClassLoader classLoader) {
    this.methodSignatures = new HashMap<String, MethodSignatureVisitor>();
    this.superClassReaders = new ArrayList<ClassReader>();
    this.allMethodSignatures = new HashSet<String>();
    this.classLoader = classLoader;
  }


  // ---------------------------------------------------------------- some getters

  /**
   * Returns method signature for some method. If signature is not found, returns <code>null</code>.
   * Founded signatures means that those method can be proxyfied.
   */
  public MethodSignatureVisitor lookupMethodSignatureVisitor(int access, String name, String desc, String className) {
    String key = ProxettaAsmUtil.createMethodSignaturesKey(access, name, desc, className);
    return methodSignatures.get(key);
  }

  /**
   * Returns <code>true</code> if method is marked for proxy.
   */
  public boolean isMarkedForProxy(MethodSignatureVisitor msgin) {
    return allMethodSignatures.contains(msgin.getSignature());
  }

  // ---------------------------------------------------------------- information

  protected String targetPackage;
  protected String targetClassname;
  protected String superName;
  protected String thisReference;
  protected String nextSupername;
  protected String[] superClasses;
  protected int hierarchyLevel;
  protected AnnotationInfo[] annotations;
  protected List<AnnotationInfo> classAnnotations;
  protected boolean isTargetIntreface;
  protected Set<String> nextInterfaces;

  // ---------------------------------------------------------------- class interface

  public String getPackage() {
    return targetPackage;
  }

  public String getClassname() {
    return targetClassname;
  }

  public String getSuperName() {
    return superName;
  }

  public String getReference() {
    return thisReference;
  }

  public String[] getSuperClasses() {
    return superClasses;
  }

  public AnnotationInfo[] getAnnotations() {
    return annotations;
  }

  // ---------------------------------------------------------------- visits


  @Override
  public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
    int lastSlash = name.lastIndexOf('/');
    this.thisReference = name;
    this.superName = superName;
    this.nextSupername = superName;
    this.targetPackage = name.substring(0, lastSlash).replace('/', '.');
    this.targetClassname = name.substring(lastSlash + 1);
    this.hierarchyLevel = 1;

    this.isTargetIntreface = (access & AsmUtil.ACC_INTERFACE) != 0;
    if (this.isTargetIntreface) {
      nextInterfaces = new HashSet<String>();
      if (interfaces != null) {
        for (String inter : interfaces) {
          nextInterfaces.add(inter);
        }
      }
    }
  }


  @Override
  public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
    AnnotationReader ar = new AnnotationReader(desc, visible);
    if (classAnnotations == null) {
      classAnnotations = new ArrayList<AnnotationInfo>();
    }
    classAnnotations.add(ar);
    return ar;
  }

  /**
   * Stores method signature for target method.
   */
  @Override
  public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    if ((access & AsmUtil.ACC_FINAL) != 0) {
      return null// skip finals
    }
    MethodSignatureVisitor msign = createMethodSignature(access, name, desc, signature, thisReference);
    String key = ProxettaAsmUtil.createMethodSignaturesKey(access, name, desc, thisReference);
    methodSignatures.put(key, msign);
    allMethodSignatures.add(msign.getSignature());
    return new MethodAnnotationReader(msign);
  }

  /**
   * Stores signatures for all super public methods not already overridden by target class.
   * All this methods will be accepted for proxyfication.
   */
  @Override
  public void visitEnd() {

    // prepare class annotations
    if (classAnnotations != null) {
      annotations = classAnnotations.toArray(new AnnotationInfo[classAnnotations.size()]);
      classAnnotations = null;
    }


    List<String> superList = new ArrayList<String>();
    // check all public super methods that are not overridden in superclass
    while (nextSupername != null) {
      InputStream inputStream = null;
      ClassReader cr = null;
      try {
        inputStream = ClassLoaderUtil.getClassAsStream(nextSupername, classLoader);
        cr = new ClassReader(inputStream);
      } catch (IOException ioex) {
        throw new ProxettaException("Unable to inspect super class: " + nextSupername, ioex);
      } finally {
        StreamUtil.close(inputStream);
      }
      hierarchyLevel++;
      superList.add(nextSupername);
      superClassReaders.add(cr)// remember the super class reader
      cr.accept(new SuperClassVisitor(), 0);
    }
    superClasses = superList.toArray(new String[superList.size()]);

    // check all interface methods that are not overridden in super-interface
    if (nextInterfaces != null) {
      while (!nextInterfaces.isEmpty()) {
        Iterator<String> iterator = nextInterfaces.iterator();
        String next = iterator.next();
        iterator.remove();

        InputStream inputStream = null;
        ClassReader cr = null;
        try {
          inputStream = ClassLoaderUtil.getClassAsStream(next, classLoader);
          cr = new ClassReader(inputStream);
        } catch (IOException ioex) {
          throw new ProxettaException("Unable to inspect super interface: " + next, ioex);
        } finally {
          StreamUtil.close(inputStream);
        }
        hierarchyLevel++;
        superClassReaders.add(cr);        // remember the super class reader
        cr.accept(new SuperClassVisitor(), 0);
      }
    }

  }


  /**
   * Creates method signature from method name.
   */
  protected MethodSignatureVisitor createMethodSignature(int access, String methodName, String description, String signature, String classname) {
    MethodSignatureVisitor v = new MethodSignatureVisitor(methodName, access, classname, description, signature, this);
    v.hierarchyLevel = this.hierarchyLevel;
    new SignatureReader(signature != null ? signature : description).accept(v);
    return v;
  }


  // ---------------------------------------------------------------- util class

  /**
   * Reads method annotations and stores to method info.
   */
  static class MethodAnnotationReader extends EmptyMethodVisitor {

    final List<AnnotationInfo> methodAnns = new ArrayList<AnnotationInfo>();
    final List<AnnotationInfo>[] methodParamsAnns;

    final MethodSignatureVisitor msign;

    MethodAnnotationReader(MethodSignatureVisitor msign) {
      this.msign = msign;
      this.methodParamsAnns = new ArrayList[msign.getAllArgumentsSize()];
    }

    @Override
    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
      AnnotationReader ar = new AnnotationReader(desc, visible);
      methodAnns.add(ar);
      return ar;
    }

    @Override
    public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
      AnnotationReader ar = new AnnotationReader(desc, visible);
      if (methodParamsAnns[parameter] == null) {
        methodParamsAnns[parameter] = new ArrayList<AnnotationInfo>();
      }

      methodParamsAnns[parameter].add(ar);

      return ar;
    }

    @Override
    public void visitEnd() {
      if (methodAnns.isEmpty() == false) {
        msign.annotations = methodAnns.toArray(new AnnotationInfo[methodAnns.size()]);
      }

      msign.argumentsAnnotation = new AnnotationInfo[methodParamsAnns.length][];

      for (int i = 0; i < methodParamsAnns.length; i++) {
        List<AnnotationInfo> methodParamsAnn = methodParamsAnns[i];

        if (methodParamsAnn != null) {
          msign.argumentsAnnotation[i] = methodParamsAnn.toArray(new AnnotationInfo[methodParamsAnn.size()]);
        }
      }
    }
  }

  // ---------------------------------------------------------------- super class visitor

  private class SuperClassVisitor extends EmptyClassVisitor {

    String declaredClassName;

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
      nextSupername = superName;
      declaredClassName = name;

      // append inner interfaces
      if (nextInterfaces != null) {
        if (interfaces != null) {
          for (String inter : interfaces) {
            nextInterfaces.add(inter);
          }
        }
      }

    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
      if (name.equals(INIT) || name.equals(CLINIT)) {
        return null;
      }
      MethodSignatureVisitor msign = createMethodSignature(access, name, desc, signature, thisReference);
      int acc = msign.getAccessFlags();
      if ((acc & AsmUtil.ACC_PUBLIC) == 0) {     // skip non-public
        return null;
      }
      if ((access & AsmUtil.ACC_FINAL) != 0) {    // skip finals
        return null;
      }
      if (allMethodSignatures.contains(msign.getSignature())) {    // skip overridden method by some in above classes
        return null;
      }

      msign.setDeclaredClassName(declaredClassName);    // indicates it is not a top level class
      String key = ProxettaAsmUtil.createMethodSignaturesKey(access, name, desc, declaredClassName);
      methodSignatures.put(key, msign);
      allMethodSignatures.add(msign.getSignature());
      return new MethodAnnotationReader(msign);
    }
  }

  // ---------------------------------------------------------------- toString


  @Override
  public String toString() {
    return "target: " + this.targetPackage + '.' + this.targetClassname;
  }
}
TOP

Related Classes of jodd.proxetta.asm.TargetClassInfoReader

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.