Package de.petris.dynamicaspects.util

Source Code of de.petris.dynamicaspects.util.Reflection

/*
* Copyright (c) 2004, Marco Petris
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     - Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     - Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     - Neither the name of Marco Petris nor the names of its
*       contributors may be used to endorse or promote products derived from
*       this software without specific prior written permission.
*      
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

package de.petris.dynamicaspects.util;

import java.io.ByteArrayInputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.List;

import org.apache.bcel.Constants;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Utility;
import org.apache.bcel.generic.Type;

import de.petris.dynamicaspects.AspectException;

/**
* This class provides additional reflection utilities, because of the limited
* possibilities of the java reflection api.
*
* @author Marco Petris
*/
public class Reflection {
 
  /**
   * Returns the modifiers of the method defined by the given arguments. The modifiers
   * are returned as a or-connected value, e. g. PUBLIC | FINAL
   *
   * @param className the name of the class containing the method
   * @param methodName the name of the method
   * @param methodSignature the signature of the method in java-internal format
   * @return the or-connected modifier value
   * @see java.lang.reflect.Modifier
   */
  public static int getModifiers(
      String className, String methodName, String methodSignature ) {

    try {
     
      Class targetClass = classForName( className );
     
      // get the classnames of the arguments
      String argClassNames[] =
        Utility.methodSignatureArgumentTypes( methodSignature, false );
     
      // get the classes of the arguments
      Class[] argClasses = new Class[argClassNames.length];

      for
        int classNameIdx= 0;
        classNameIdx<argClassNames.length;
        classNameIdx++ ) {

        argClasses[classNameIdx] =
          classForName( argClassNames[classNameIdx] );
      }
     
      // look up the constructor or method in the class or superclasses
      if( methodName.equals( Constants.CONSTRUCTOR_NAME ) ) {
        return lookUpConstructor(
            targetClass, argClasses ).getModifiers();
      }
      else {
        return lookUpMethod(
            targetClass,
            methodName,
            argClasses ).getModifiers();
      }
    }
    catch( Exception exc ) {
      throw new AspectException(
        "method getModifiers in "
        + Reflection.class.getName()
        + " caused an exception", exc );
    }
  }
 
  /**
   * Looks up the constructor defined by the given parameter types in the given
   * class or superclass. This is a recursive search up the inheritance line.
   *
   * @param target the class containing the constructor
   * @param paramTypes the parameter types of the constructor
   * @return the constructor instance
   */
  private static Constructor lookUpConstructor(
      Class target, Class... paramTypes ) {
   
    try {
      return target.getDeclaredConstructor( paramTypes );
    }
    catch( NoSuchMethodException nme ) {
      // the target class does not declare the method
      // so we look up the method in its super class
      return lookUpConstructor( target.getSuperclass(), paramTypes );
    }
   
  }
 
  /**
   * Looks up the method defined by the given methodname and the given argument types
   * in the given class or superclass. This is a recursive search up the inheritance line.
   *
   * @param target the class containing the method
   * @param methodName the method name
   * @param paramTypes the argument types of the method
   * @return the method instance
   */
  private static Method lookUpMethod(
      Class target, String methodName, Class... paramTypes ) {
 
    try {
      return target.getDeclaredMethod(
          methodName,
          paramTypes );
    }
    catch( NoSuchMethodException nme ) {
      return lookUpMethod(
          target.getSuperclass(), methodName, paramTypes );
    }
   
  }
 
 
  /**
   * Returns a string representation of the given modifiers.
   * The string representation has a defined position for each modifier, i. e. :
   * getModifierString( Modifier.PUBLIC | Modifier.FINAL )
   * <=> public final <=>
   * getModifierString( Modifier.FINAL | Modifier.PUBLIC )
   *
   * @param modifiers the or-connected modifiers
   * @return the string representation of the modifiers
   * @see java.lang.reflect.Modifier
   */
  public static String getModifierString( int modifiers ) {
    return Modifier.toString( modifiers);
  }
 
  /**
   * Returns a string representation of the declaration of the method defined
   * by the arguments.
   * Example: <br>
   * The following arguments <br>
   * Classname: de.petris.dynamicaspects.test.targets.SimpleTarget <br>
   * Methodname: doIt <br>
   * MethodSignature: (DLjava/util/ArrayList;)J <br>
   * become: <br>
     * <code>
   * private long de.petris.dynamicaspects.test.targets.SimpleTarget.doIt(double,java.util.ArrayList)
     * </code><br>
     *
   * @param className the name of the class containing the method
   * @param methodName the name of the method
   * @param methodSignature the signature of the method
   * @return a string representation of the declaration of the method
   */
  public static String getMethodDeclaration(
      String className, String methodName,
      String methodSignature ) {
    return getMethodDeclaration(
      getModifiers( className, methodName, methodSignature ),
      className, methodName, methodSignature, false )
  }
 
  /**
   * Returns a string representation of the declaration of the method defined
   * by the arguments.
   * Example: <br>
   * The following arguments <br>
   * Classname: de.petris.dynamicaspects.test.targets.SimpleTarget <br>
   * Methodname: doIt <br>
   * MethodSignature: (DLjava/util/ArrayList;)J <br>
   * become: <br>
   * <code>
   * private long de.petris.dynamicaspects.test.targets.SimpleTarget.doIt(double,java.util.ArrayList)
   * </code><br>
   * @param className the name of the class containing the method
   * @param methodName the name of the method
   * @param methodSignature the signature of the method
   * @param chopClassName if true the classname is ommitted
   * @return a string representation of the declaration of the method
   */
  public static String getMethodDeclaration(
      String className, String methodName,
      String methodSignature, boolean chopClassName ) {
    return getMethodDeclaration(
      getModifiers( className, methodName, methodSignature ),
      className, methodName, methodSignature, chopClassName )
  }
 
  /**
   * Returns a string representation of the declaration of the method defined
   * by the arguments.
   * Example: <br>
   * The following arguments <br>
   * Modifiers: Modifier.PRIVATE <br>
   * Classname: de.petris.dynamicaspects.test.targets.SimpleTarget <br>
   * Methodname: doIt <br>
   * MethodSignature: (DLjava/util/ArrayList;)J <br>
   * become: <br>
   *
   * private long de.petris.dynamicaspects.test.targets.SimpleTarget.doIt(double,java.util.ArrayList)<br>
   *
   * @param modifiers the modifiers of the method
   * @param className the name of the class containing the method
   * @param methodName the name of the method
   * @param methodSignature the signature of the method
   * @param chopClassName if true the classname is ommitted
   * @return a string representation of the declaration of the method
   */
  public static String getMethodDeclaration(
      int modifiers, String className, String methodName,
      String methodSignature, boolean chopClassName ) {
   
    // get the modifiers string
    StringBuffer buffer =
      new StringBuffer( getModifierString( modifiers ) );
    String conc = "";

    // handle return type
    buffer.append( " " );
    Type returnType = Type.getReturnType( methodSignature );
    buffer.append( returnType.toString() );
    buffer.append( " " );
   
    // handle class name
    if( !chopClassName ) {
      buffer.append( className );
      buffer.append( "." );
    }
   
    // handle method name
    buffer.append( methodName );
   
    // handle arguments
    buffer.append( "(" );
       
    for( Type arg : Type.getArgumentTypes( methodSignature ) ) {
      buffer.append( conc );
      buffer.append( arg );
      conc = ",";
    }
    buffer.append( ")" );
   
    return buffer.toString();
  }
 
  /**
   * Return the dimensions of a class.
   * For example boolean[][] returns 2.
   *
   * @param className the name of the class
   * @return the dimension
   */
  private static int getDimensions( String className ) {
    int dimCounter = 0;
    int index = -1;
    while( (index = className.indexOf('[', index+1 )) != -) {
      dimCounter++;
    }
    return dimCounter;
  }
 
  /**
   * A classForName which handles all classes including primitive types and arrays.
   *
   * @param className the name of the class.
   * @return the instance of the desired class
   */
  public static Class classForName( String className ) {

    try {
      if( className.contains( "[" ) ) {
        return Array.newInstance(
          classForName(
              className.substring(0, className.indexOf('[') ) ),
          new int[getDimensions(className)] ).getClass();
      }
      else if( className.equals("boolean") ) {
        return boolean.class;
      }
      else if( className.equals("int") ) {
        return int.class;
      }
      else if( className.equals("short") ) {
        return short.class;
      }
      else if( className.equals("byte") ) {
        return byte.class;
      }
      else if( className.equals("long") ) {
        return long.class;
      }
      else if( className.equals("double") ) {
        return double.class;
      }
      else if( className.equals("float") ) {
        return float.class;
      }
      else if( className.equals("char") ) {
        return char.class;
      }
      else {
        return Class.forName( className );
      }
    }
    catch( Exception exc ) {
      throw new AspectException(
          "method classForName in "
          + Reflection.class.getName()
          + " caused an exception", exc );
    }
  }
 
  /**
   * Returns a string representation of the given list.
   *
   * @param l the list
   * @return the string representation
   */
  public static String toString( List<Object> l ) {
    StringBuffer buffer = new StringBuffer( "[" );
    String conc = "";
    Iterator<Object> iter = l.iterator();
    while( iter.hasNext() ) {
      buffer.append( conc );
      buffer.append( iter.next() );
      conc = ";";
    }
   
    buffer.append( "]" );
    return buffer.toString();
  }

  /**
   * Tests if the given type is a category 2 type ( see JVM Specification ).
   * long and double return true, all other types return false
   *
   * @param t the type to test
   * @return true for long and double, else false
   */
  public static boolean isCat2Type( Type t ) {
    return ( ( t.equals( Type.LONG ) )
        || ( t.equals( Type.DOUBLE ) ) );
  }
 
  /**
   * Returns an instance of the inner class specified by the given
   * enclosing class and the name of the inner class.
   *
   * @param innerClassName the name of the inner class
   * @param declaringClass the delcaring or enclosing class
   * @return an instance of the desired inner class
   */
  public static Class getInnerClassOf(
      String innerClassName, Class declaringClass ) {

     for( Class innerClass : declaringClass.getDeclaredClasses() ) {
       if( innerClass.getName().substring(
         innerClass.getName().indexOf('$')+1 ).equals(
             innerClassName ) ) {
         return innerClass;
       }
     }
    
     throw new AspectException(
         new ClassNotFoundException( innerClassName ) );
  }
 
  /**
   * Returns a string representation of a class which can be used in regular expressions.
   * boolean[] becomes boolean\\[]
   *
   * @param className the name of the class
   * @return the new string representation for regular exp.
   */
  public static String classNameToPatternString( String className ) {
 
    StringBuffer buf = new StringBuffer( className );
   
    int index = -3;
    while( (index = buf.indexOf("[", index+3 )) != -) {
      buf.insert( index, "\\" );
    }
    return buf.toString();
  }
   
    /**
     * Returns the  JavaClass for a given byte representation of a class and its given classname.
     * @param classfileBuffer the byte representation of the class
     * @param className the name of the class
     * @return the extracted JavaClass object
     */
    public static JavaClass classForByteArray(
            byte[] classfileBuffer, String className ) {
       
        ClassParser cp =
            new ClassParser(
                new ByteArrayInputStream(classfileBuffer),
                className );
   
        try {
            return cp.parse();
        }
        catch( Throwable t ) {
            throw new AspectException(
                    "tried to load class  "
                    + className + " from a byte array ",
                    t );
        }
    }
}
TOP

Related Classes of de.petris.dynamicaspects.util.Reflection

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.