Mega Code Archive

 
Categories / Java / Reflection
 

Provides a set of static methods that extend the Java metaobject

/* Java Reflection in Action Ira R. Forman and Nate Forman ISBN 1932394184 Publisher: Manning Publications Co. */ /* Copyright 2002 -- Ira R. Forman and Nate Forman */ /**  * This class provides a set of static methods that extend the Java metaobject  * protocol.  *   * @author: Ira R. Forman  */ import java.lang.reflect.*; import java.util.*; abstract public class Mopex {   /**    * Returns a syntactically correct name for a class object. If the class    * object represents an array, the proper number of square bracket pairs are    * appended to the component type.    *     * @return java.lang.String    * @param cls    *            java.lang.Class    */   //start extract classNameToString   public static String getTypeName(Class cls) {     if (!cls.isArray()) {       return cls.getName();     } else {       return getTypeName(cls.getComponentType()) + "[]";     }   }   //stop extract classNameToString   /**    * Returns an array of the superclasses of cls.    *     * @return java.lang.Class[]    * @param cls    *            java.lang.Class    */   //start extract getSuperclasses   public static Class[] getSuperclasses(Class cls) {     int i = 0;     for (Class x = cls.getSuperclass(); x != null; x = x.getSuperclass())       i++;     Class[] result = new Class[i];     i = 0;     for (Class x = cls.getSuperclass(); x != null; x = x.getSuperclass())       result[i++] = x;     return result;   }   //stop extract getSuperclasses   /**    * Returns an array of the instance variablies of the the specified class.    * An instance variable is defined to be a non-static field that is declared    * by the class or inherited.    *     * @return java.lang.Field[]    * @param cls    *            java.lang.Class    */   //start extract getInstanceVariables   public static Field[] getInstanceVariables(Class cls) {     List accum = new LinkedList();     while (cls != null) {       Field[] fields = cls.getDeclaredFields();       for (int i = 0; i < fields.length; i++) {         if (!Modifier.isStatic(fields[i].getModifiers())) {           accum.add(fields[i]);         }       }       cls = cls.getSuperclass();     }     Field[] retvalue = new Field[accum.size()];     return (Field[]) accum.toArray(retvalue);   }   //stop extract getInstanceVariables   /**    * Returns an array of fields that are the declared instance variables of    * cls. An instance variable is a field that is not static.    *     * @return java.lang.reflect.Field[]    * @param cls    *            java.lang.Class    */   //start extract getDeclaredIVS   public static Field[] getDeclaredIVs(Class cls) {     Field[] fields = cls.getDeclaredFields();     // Count the IVs     int numberOfIVs = 0;     for (int i = 0; i < fields.length; i++) {       if (!Modifier.isStatic(fields[i].getModifiers()))         numberOfIVs++;     }     Field[] declaredIVs = new Field[numberOfIVs];     // Populate declaredIVs     int j = 0;     for (int i = 0; i < fields.length; i++) {       if (!Modifier.isStatic(fields[i].getModifiers()))         declaredIVs[j++] = fields[i];     }     return declaredIVs;   }   //stop extract getDeclaredIVS   /**    * Return an array of the supported instance variables of this class. A    * supported instance variable is not static and is either declared or    * inherited from a superclass.    *     * @return java.lang.reflect.Field[]    * @param cls    *            java.lang.Class    */   //start extract getSupportedIVS   public static Field[] getSupportedIVs(Class cls) {     if (cls == null) {       return new Field[0];     } else {       Field[] inheritedIVs = getSupportedIVs(cls.getSuperclass());       Field[] declaredIVs = getDeclaredIVs(cls);       Field[] supportedIVs = new Field[declaredIVs.length           + inheritedIVs.length];       for (int i = 0; i < declaredIVs.length; i++) {         supportedIVs[i] = declaredIVs[i];       }       for (int i = 0; i < inheritedIVs.length; i++) {         supportedIVs[i + declaredIVs.length] = inheritedIVs[i];       }       return supportedIVs;     }   }   //stop extract getSupportedIVS   /**    * Returns an array of the methods that are not static.    *     * @return java.lang.reflect.Method[]    * @param cls    *            java.lang.Class    */   //start extract getInstanceMethods   public static Method[] getInstanceMethods(Class cls) {     List instanceMethods = new ArrayList();     for (Class c = cls; c != null; c = c.getSuperclass()) {       Method[] methods = c.getDeclaredMethods();       for (int i = 0; i < methods.length; i++)         if (!Modifier.isStatic(methods[i].getModifiers()))           instanceMethods.add(methods[i]);     }     Method[] ims = new Method[instanceMethods.size()];     for (int j = 0; j < instanceMethods.size(); j++)       ims[j] = (Method) instanceMethods.get(j);     return ims;   }   //stop extract getInstanceMethods   /**    * Returns an array of methods to which instances of this class respond.    *     * @return java.lang.reflect.Method[]    * @param cls    *            java.lang.Class    */   //start extract getSupportedMethods   public static Method[] getSupportedMethods(Class cls) {     return getSupportedMethods(cls, null);   }   //stop extract getSupportedMethods   /**    * This method retrieves the modifiers of a Method without the unwanted    * modifiers specified in the second parameter. Because this method uses    * bitwise operations, multiple unwanted modifiers may be specified by    * bitwise or.    *     * @return int    * @param m    *            java.lang.Method    * @param unwantedModifiers    *            int    */   //start extract getModifiersWithout   public static int getModifiersWithout(Method m, int unwantedModifiers) {     int mods = m.getModifiers();     return (mods ^ unwantedModifiers) & mods;   }   //stop extract getModifiersWithout   /**    * Returns a Method that has the signature specified by the calling    * parameters.    *     * @return Method    * @param cls    *            java.lang.Class    * @param name    *            String    * @param paramTypes    *            java.lang.Class[]    */   //start extract getSupportedMethod   public static Method getSupportedMethod(Class cls, String name,       Class[] paramTypes) throws NoSuchMethodException {     if (cls == null) {       throw new NoSuchMethodException();     }     try {       return cls.getDeclaredMethod(name, paramTypes);     } catch (NoSuchMethodException ex) {       return getSupportedMethod(cls.getSuperclass(), name, paramTypes);     }   }   //stop extract getSupportedMethod   /**    * Returns a Method array of the methods to which instances of the specified    * respond except for those methods defined in the class specifed by limit    * or any of its superclasses. Note that limit is usually used to eliminate    * them methods defined by java.lang.Object.    *     * @return Method[]    * @param cls    *            java.lang.Class    * @param limit    *            java.lang.Class    */   //start extract getSupportedMethods   public static Method[] getSupportedMethods(Class cls, Class limit) {     Vector supportedMethods = new Vector();     for (Class c = cls; c != limit; c = c.getSuperclass()) {       Method[] methods = c.getDeclaredMethods();       for (int i = 0; i < methods.length; i++) {         boolean found = false;         for (int j = 0; j < supportedMethods.size(); j++)           if (equalSignatures(methods[i], (Method) supportedMethods               .elementAt(j))) {             found = true;             break;           }         if (!found)           supportedMethods.add(methods[i]);       }     }     Method[] mArray = new Method[supportedMethods.size()];     for (int k = 0; k < mArray.length; k++)       mArray[k] = (Method) supportedMethods.elementAt(k);     return mArray;   }   //stop extract getSupportedMethods   /**    * This field is initialized with a method object for the equalSignatures    * method. This is an optimization in that selectMethods can use this field    * instead of calling getMethod each time it is called.    */   //start extract equalSignaturesMethod   static private Method equalSignaturesMethod;   static {     Class[] fpl = { Method.class, Method.class };     try {       equalSignaturesMethod = Mopex.class.getMethod("equalSignatures",           fpl);     } catch (NoSuchMethodException e) {       throw new RuntimeException(e);     }   }   //stop extract equalSignaturesMethod   /**    * Determines if the signatures of two method objects are equal. In Java, a    * signature comprises the method name and the array of of formal parameter    * types. For two signatures to be equal, the method names must be the same    * and the formal parameters must be of the same type (in the same order).    *     * @return boolean    * @param m1    *            java.lang.Method    * @param m2    *            java.lang.Method    */   //start extract equalSignatures   public static boolean equalSignatures(Method m1, Method m2) {     if (!m1.getName().equals(m2.getName()))       return false;     if (!Arrays.equals(m1.getParameterTypes(), m2.getParameterTypes()))       return false;     return true;   }   //stop extract equalSignatures   /**    * Return a string that represents the signature of the specified method.    *     * @return String    * @param m    *            java.lang.Method    */   //start extract signatureToString   public static String signatureToString(Method m) {     return m.getName() + "("         + formalParametersToString(m.getParameterTypes()) + ")";   }   //stop extract signatureToString   /**    * Returns a string that can be used as a formal parameter list for a method    * that has the parameter types of the specified array.    *     * @return String    * @param pts    *            java.lang.Class[]    */   //start extract formalParametersToString   public static String formalParametersToString(Class[] pts) {     String result = "";     for (int i = 0; i < pts.length; i++) {       result += getTypeName(pts[i]) + " p" + i;       if (i < pts.length - 1)         result += ",";     }     return result;   }   //stop extract formalParametersToString   /**    * Returns a string that is an actual parameter list that matches the formal    * parameter list produced by formalParametersToString.    *     * @return String    * @param pts    *            java.lang.Class[]    */   //start extract actualParametersToString   public static String actualParametersToString(Class[] pts) {     String result = "";     for (int i = 0; i < pts.length; i++) {       result += "p" + i;       if (i < pts.length - 1)         result += ",";     }     return result;   }   //stop extract actualParametersToString   /**    * Returns a String that represents the header for a constructor.    *     * @return String    * @param c    *            java.lang.Constructor    */   //start extract constructorHeaderToString   public static String headerToString(Constructor c) {     String mods = Modifier.toString(c.getModifiers());     if (mods.length() == 0)       return headerSuffixToString(c);     else       return mods + " " + headerSuffixToString(c);   }   //stop extract constructorHeaderToString   /**    * Returns a String that represents the header suffix for a constructor. The    * term "header suffix" is not a standard Java term. We use it to mean the    * Java header without the modifiers.    *     * @return String    * @param c    *            java.lang.Constructor    */   //start extract constructorHeaderToString   public static String headerSuffixToString(Constructor c) {     String header = signatureToString(c);     Class[] eTypes = c.getExceptionTypes();     if (eTypes.length != 0)       header += " throws " + classArrayToString(eTypes);     return header;   }   //stop extract constructorHeaderToString   /**    * Returns a String that represents the signature for a constructor.    *     * @return String    * @param c    *            java.lang.Constructor    */   //start extract constructorHeaderToString   public static String signatureToString(Constructor c) {     return c.getName() + "("         + formalParametersToString(c.getParameterTypes()) + ")";   }   //stop extract constructorHeaderToString   /**    * Returns a String that represents the header of a method.    *     * @return String    * @param m    *            java.lang.Method    */   //start extract headerToString   public static String headerToString(Method m) {     String mods = Modifier.toString(m.getModifiers());     if (mods.length() == 0)       return headerSuffixToString(m);     else       return mods + " " + headerSuffixToString(m);   }   //stop extract headerToString   /**    * Returns a String that represents the suffix of the header of a method.    * The suffix of a header is not a standard Java term. We use the term to    * mean the Java header without the method modifiers.    *     * @return String    * @param m    *            java.lang.Method    */   //start extract headerToString   public static String headerSuffixToString(Method m) {     String header = getTypeName(m.getReturnType()) + " "         + signatureToString(m);     Class[] eTypes = m.getExceptionTypes();     if (eTypes.length != 0) {       header += " throws " + classArrayToString(eTypes);     }     return header;   }   //stop extract headerToString   /**    * Returns a String that is a comma separated list of the typenames of the    * classes in the array pts.    *     * @return String    * @param pts    *            java.lang.Class[]    */   //start extract classArrayToString   public static String classArrayToString(Class[] pts) {     String result = "";     for (int i = 0; i < pts.length; i++) {       result += getTypeName(pts[i]);       if (i < pts.length - 1)         result += ",";     }     return result;   }   //stop extract classArrayToString   /**    * Turns true if and only if the header suffixes of the two specified    * methods are equal. The header suffix is defined to be the signature, the    * return type, and the exception types.    *     * @return boolean    * @param m1    *            java.lang.Method    * @param m2    *            java.lang.Method    */   public static boolean equalsHeaderSuffixes(Method m1, Method m2) {     if (m1.getReturnType() != m2.getReturnType())       return false;     if (!Arrays.equals(m1.getExceptionTypes(), m2.getExceptionTypes()))       return false;     return equalSignatures(m1, m2);   }   /**    * Creates constructor with the signature of c and a new name. It adds some    * code after generating a super statement to call c. This method is used    * when generating a subclass of class that declared c.    *     * @return String    * @param c    *            java.lang.Constructor    * @param name    *            String    * @param code    *            String    */   //start extract createRenamedConstructor   public static String createRenamedConstructor(Constructor c, String name,       String code) {     Class[] pta = c.getParameterTypes();     String fpl = formalParametersToString(pta);     String apl = actualParametersToString(pta);     Class[] eTypes = c.getExceptionTypes();     String result = name + "(" + fpl + ")\n";     if (eTypes.length != 0)       result += "    throws " + classArrayToString(eTypes) + "\n";     result += "{\n    super(" + apl + ");\n" + code + "}\n";     return result;   }   //stop extract createRenamedConstructor   /**    * Returns a String that is formatted as a Java method declaration having    * the same header as the specified method but with the code parameter    * substituted for the method body.    *     * @return String    * @param m    *            java.lang.Method    * @param code    *            String    */   //start extract createReplacementMethod   public static String createReplacementMethod(Method m, String code) {     Class[] pta = m.getParameterTypes();     String fpl = formalParametersToString(pta);     Class[] eTypes = m.getExceptionTypes();     String result = m.getName() + "(" + fpl + ")\n";     if (eTypes.length != 0)       result += "    throws " + classArrayToString(eTypes) + "\n";     result += "{\n" + code + "}\n";     return result;   }   //stop extract createReplacementMethod   /**    * Returns a string for a cooperative override of the method m. That is, The    * string has the same return type and signature as m but the body has a    * super call that is sandwiched between the strings code1 and code2.    *     * @return String    * @param m    *            java.lang.Method    * @param code1    *            String    * @param code2    *            String    */   //start extract createCooperativeWrapper   public static String createCooperativeWrapper(Method m, String code1,       String code2) {     Class[] pta = m.getParameterTypes();     Class retType = m.getReturnType();     String fpl = formalParametersToString(pta);     String apl = actualParametersToString(pta);     Class[] eTypes = m.getExceptionTypes();     String result = retType.getName() + " " + m.getName() + "(" + fpl         + ")\n";     if (eTypes.length != 0)       result += "    throws " + classArrayToString(eTypes) + "\n";     result += "{\n" + code1 + "    ";     if (retType != void.class)       result += retType.getName() + " cooperativeReturnValue = ";     result += "super." + m.getName() + "(" + apl + ");\n";     result += code2;     if (retType != void.class)       result += "    return cooperativeReturnValue;\n";     result += "}\n";     return result;   }   /**    * Returns the method object for the unique method named mName. If no such    * method exists, a null is returned. If there is more than one such method,    * a runtime exception is thrown.    *     * @return Method    * @param cls    *            java.lang.Class    * @param mName    *            String    */   public static Method getUniquelyNamedMethod(Class cls, String mName) {     Method result = null;     Method[] mArray = cls.getDeclaredMethods();     for (int i = 0; i < mArray.length; i++)       if (mName.equals(mArray[i].getName())) {         if (result == null)           result = mArray[i];         else           throw new RuntimeException("name is not unique");       }     return result;   }   /**    * Finds the first (from the bottom of the inheritance hierarchy) field with    * the specified name. Note that Class.getField returns only public fields.    *     * @return Field    * @param cls    *            java.lang.Class    * @param name    *            String    */   //start extract findField   public static Field findField(Class cls, String name)       throws NoSuchFieldException {     if (cls != null) {       try {         return cls.getDeclaredField(name);       } catch (NoSuchFieldException e) {         return findField(cls.getSuperclass(), name);       }     } else {       throw new NoSuchFieldException();     }   } }