Package net.sourceforge.javautil.bytecode.api

Source Code of net.sourceforge.javautil.bytecode.api.BytecodeResolutionPool

package net.sourceforge.javautil.bytecode.api;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import bsh.Modifiers;

import net.sourceforge.javautil.bytecode.BytecodeException;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable.ClassType;
import net.sourceforge.javautil.bytecode.api.TypeMemberAccess.Scope;
import net.sourceforge.javautil.bytecode.api.type.AbstractType;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeConstructor;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeContextMethod;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod.ArgumentMatch;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.MethodInvocation;

/**
* A pool in which {@link IBytecodeResolvable}'s are grouped for resolution.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class BytecodeResolutionPool {

  /**
   * @param clazz The clazz
   * @return The related enum class type
   */
  public static ClassType getClassTypeFor (Class<?> clazz) {
    if (clazz.isInterface()) return ClassType.Interface;
    if (clazz.isEnum()) return ClassType.Enum;
    if (clazz.isAnnotation()) return ClassType.Annotation;
    return ClassType.Class;
  }

  protected final ClassLoader parentLoader;
 
  protected Map<String, IBytecodeResolvable> resolved = new HashMap<String, IBytecodeResolvable>();
 
  public BytecodeResolutionPool(ClassLoader parentLoader) {
    this.parentLoader = parentLoader;
  }
 
  /**
   * @param className The className association to clear
   */
  public void clear (String className) {
    this.resolved.remove(className);
  }
 
  /**
   * @param className The class name to check for
   * @return True if the class by this name has already been resolved
   */
  public boolean isResolved (String className) {
    return resolved.containsKey(className);
  }

  /**
   * @param type The type to add to this pool
   */
  public void add (AbstractType type) {
    if (resolved.containsKey(type.getName())) {
      throw new BytecodeException("This pool already has a class by the name of: " + type.getName());
    }
   
    this.resolved.put(type.getName(), type);
  }
 
  /**
   * @param types The types to resolve
   * @return The array of resolved types
   */
  public IBytecodeResolvable[] resolve (TypeDescriptor... types) {
    IBytecodeResolvable[] resolved = new IBytecodeResolvable[types.length];
    for (int r=0; r<resolved.length; r++) {
      resolved[r] = resolve(types[r].getClassName());
    }
    return resolved;
  }
 
  /**
   * @param classNames The name of the classes to resolve
   * @return The resolved array of classes
   */
  public IBytecodeResolvable[] resolve (String... classNames) {
    IBytecodeResolvable[] resolved = new IBytecodeResolvable[classNames.length];
    for (int r=0; r<resolved.length; r++) {
      resolved[r] = resolve(classNames[r]);
    }
    return resolved;
  }

  /**
   * @param clazz The class for which to get a linkable wrapper
   * @return The linkable wrapper
   */
  public IBytecodeResolvable resolve (String className) {
    IBytecodeResolvable resolved = this.resolved.get(className);
    if (resolved == null) {
      try {
        Class clazz = null;
       
        if ("boolean".equals(className)) clazz = boolean.class;
        else if ("int".equals(className)) clazz = int.class;
        else if ("byte".equals(className)) clazz = byte.class;
        else if ("short".equals(className)) clazz = short.class;
        else if ("long".equals(className)) clazz = long.class;
        else if ("float".equals(className)) clazz = float.class;
        else if ("double".equals(className)) clazz = double.class;
        else if ("char".equals(className)) clazz = char.class;
        else clazz = Class.forName(className, false, parentLoader);
       
        this.resolved.put(className, resolved = new Linkable(clazz));
      } catch (ClassNotFoundException e) {
        throw new BytecodeException("Could not resolve class: " + className, e);
      }
    }
    return resolved;
  }
 
  /**
   * The wrapper for {@link Class}'s to be dealt with as {@link IBytecodeResolvable}'s.
   *
   * @author elponderador
   * @author $Author$
   * @version $Id$
   */
  public class Linkable extends BytecodeResolvableAbstract {
   
    protected final Class<?> clazz;
    protected final IBytecodeResolvable superType;
    protected final TypeMemberAccess access;
   
    protected final Map<String, MethodWrapper> wrappers = new HashMap<String, MethodWrapper>();
   
    public Linkable(Class clazz) {
      super(getClassTypeFor(clazz), TypeDescriptor.getFor(clazz));
      this.clazz = clazz;
      this.access = TypeMemberAccess.getFor(clazz.getModifiers());
      this.superType = clazz.getSuperclass() == null ? null : resolve(clazz.getSuperclass().getName());
    }

    /**
     * @return The clazz wrapped by this resolvable impl
     */
    public Class<?> getWrapped() { return clazz; }

    public Set<BytecodeAnnotationDeclared> getDeclaredAnnotations() {
      return BytecodeAnnotationDeclared.getAnnotations(BytecodeResolutionPool.this, clazz);
    }

    public Scope getAccessScope() { return access.getScope(); }

    public boolean isFinal() { return access.isFinal(); }

    public boolean isStatic() { return access.isStatic(); }

    public boolean isAbstract() { return access.isAbstract(); }

    public Set<IBytecodeConstructor> getDeclaredConstructors() {
      Set<IBytecodeConstructor> constructors = new LinkedHashSet<IBytecodeConstructor>();
     
      for (Constructor constructor : clazz.getDeclaredConstructors()) {
        constructors.add(new ConstructorWrapper(constructor));
      }
     
      return constructors;
    }

    public Set<IBytecodeField> getDeclaredFields() {
      Set<IBytecodeField> fields = new LinkedHashSet<IBytecodeField>();
     
      for (Field field : clazz.getDeclaredFields()) {
        fields.add(new BytecodeFieldDeclared(BytecodeResolutionPool.this, this, field));
      }
     
      return fields;
    }

    public Set<IBytecodeMethod> getDeclaredMethods() {
      Set<IBytecodeMethod> methods = new LinkedHashSet<IBytecodeMethod>();
     
      for (Method method : clazz.getDeclaredMethods()) {
        methods.add(new MethodWrapper(method));
      }
     
      return methods;
    }

    public IBytecodeField getField(BytecodeResolutionPool pool, String name) {
      try {
        Field field = clazz.getDeclaredField(name);
        return new BytecodeFieldDeclared(pool, this, field);
      } catch (SecurityException e) {
        throw new BytecodeException("Could not access field: " + name, e);
      } catch (NoSuchFieldException e) {
        if (this.superType != null) {
          return this.getSuperType().getField(pool, name);
        } else {
          throw new RuntimeException(e);
        }
      }
    }

    public IBytecodeConstructor findConstructor(BytecodeResolutionPool pool, TypeDescriptor... types) {
      ConstructorWrapper cw = null;
     
      for (Constructor constructor : clazz.getConstructors()) {
        ConstructorWrapper wrapper = new ConstructorWrapper(constructor);
        ArgumentMatch am = wrapper.compareArguments(pool, types);
        if (am == ArgumentMatch.FUNCTIONAL && cw == null) cw = wrapper;
        else if (am == ArgumentMatch.EXACT) { cw = wrapper; break; }
      }
     
      return cw;
    }

    public IBytecodeMethod findMethod(BytecodeResolutionPool pool, String name, TypeDescriptor... types) {
      MethodWrapper mw = null;
     
      try {
        Class[] parameterTypes = new Class[types.length];
        for (int i=0; i<types.length; i++) {
          parameterTypes[i] = Class.forName(types[i].getClassName());
        }
        return new MethodWrapper( clazz.getMethod(name, parameterTypes) );
      }
      catch (ClassNotFoundException e) {}
      catch (NoSuchMethodException e) {}

      Class sc = clazz;
      ArgumentMatch am = null;
      while (sc != null) {
        Method[] methods = sc.isInterface() ? sc.getMethods() : sc.getDeclaredMethods();
        for (Method method : methods) {
          if (!method.getName().equals(name)) continue;
          MethodWrapper wrapper = new MethodWrapper(method);
          am = wrapper.compareArguments(pool, types);
          if (am == ArgumentMatch.FUNCTIONAL && mw == null) mw = wrapper;
          else if (am == ArgumentMatch.EXACT) {
            mw = wrapper;
            if (!method.isBridge()) break;
          }
        }
        if (am == ArgumentMatch.EXACT) break;
        sc = sc.getSuperclass();
      }
     
      return mw;
    }

    public boolean isInstanceof(BytecodeResolutionPool pool, IBytecodeResolvable resolvable) {
      return resolvable instanceof Linkable ? ((Linkable)resolvable).clazz.isAssignableFrom(clazz) : false;
    }

    public IBytecodeResolvable getSuperType() {
      return superType;
    }
   
    /**
     * This will wrap a constructor for integration with {@link IBytecodeConstructor} API.
     *
     * @author elponderador
     * @author $Author$
     * @version $Id$
     */
    public class ConstructorWrapper extends BytecodeMemberDeclared implements IBytecodeConstructor {
     
      protected final Constructor constructor;
      protected final MethodDescriptor descriptor;
      protected final TypeMemberAccess access;

      public ConstructorWrapper(Constructor constructor) {
        super(BytecodeResolutionPool.this, constructor);
        this.constructor = constructor;
        this.descriptor = new MethodDescriptor(constructor.isVarArgs(), TypeDescriptor.VOID, TypeDescriptor.getFor(constructor.getExceptionTypes()), TypeDescriptor.getFor(constructor.getParameterTypes()));
        this.access = TypeMemberAccess.getFor(constructor.getModifiers());
      }

      public boolean isVarArgs() { return constructor.isVarArgs(); }

      public IBytecodeResolvable getDeclaringType() { return Linkable.this; }

      public MethodDescriptor getDescriptor() { return this.descriptor; }

      public String getName() { return "<init>"; }

      public TypeMemberAccess getAccess() { return this.access; }
     
      public ArgumentMatch compareArguments (BytecodeResolutionPool pool, TypeDescriptor... types) {
        return Util.compareArguments(pool, this, types);
      }
     
    }

    /**
     * A wrapper for a class method.
     *
     * @author elponderador
     * @author $Author$
     * @version $Id$
     */
    public class MethodWrapper extends BytecodeMemberDeclared implements IBytecodeMethod {
     
      protected final Method method;
      protected final MethodDescriptor descriptor;
      protected final TypeMemberAccess access;

      public MethodWrapper(Method method) {
        super(BytecodeResolutionPool.this, method);
        this.method = method;
        this.descriptor = new MethodDescriptor(method);
        this.access = TypeMemberAccess.getFor(method.getModifiers());
      }

      public boolean isVarArgs() { return descriptor.isVarArgs(); }

      public IBytecodeResolvable getDeclaringType() { return Linkable.this; }

      public MethodDescriptor getDescriptor() { return this.descriptor; }

      public String getName() { return method.getName(); }

      public TypeMemberAccess getAccess() { return this.access; }
     
      public ArgumentMatch compareArguments (BytecodeResolutionPool pool, TypeDescriptor... types) {
        return Util.compareArguments(pool, this, types);
      }
     
    }
   
  } 
}
TOP

Related Classes of net.sourceforge.javautil.bytecode.api.BytecodeResolutionPool

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.