diff --git a/src/java/com/samskivert/util/MethodFinder.java b/src/java/com/samskivert/util/MethodFinder.java index 0fd88611..2bb373c3 100644 --- a/src/java/com/samskivert/util/MethodFinder.java +++ b/src/java/com/samskivert/util/MethodFinder.java @@ -24,85 +24,72 @@ import java.lang.reflect.*; import java.util.*; /** - * Finds methods and constructors that can be invoked reflectively. - * Attempts to address some of the limitations of the JDK's {@link - * Class#getMethod} and {@link Class#getConstructor}, and other JDK - * reflective facilities. + * Finds methods and constructors that can be invoked reflectively. Attempts to address some of + * the limitations of the JDK's {@link Class#getMethod} and {@link Class#getConstructor}, and other + * JDK reflective facilities. * - *

Because those methods only match exact method signatures, one is - * unable to perform the same method matching that the compiler does at - * compile time (e.g. matching the method foo(Exception) when - * the user wants to call a method named foo with an - * IOException argument) with the basic reflection services. - * This class implements the method resolution process according to the - * same rules used by a Java compiler. These rules are outlined in the - * Java Language Specification, variously in sections 5.1.2, 5.1.4, 5.3, - * and 15.12.2. + *

Because those methods only match exact method signatures, one is unable to perform the same + * method matching that the compiler does at compile time (e.g. matching the method + * foo(Exception) when the user wants to call a method named foo with an + * IOException argument) with the basic reflection services. This class implements + * the method resolution process according to the same rules used by a Java compiler. These rules + * are outlined in the Java Language Specification, variously in sections 5.1.2, 5.1.4, 5.3, and + * 15.12.2. * *

This code was adapted from code provided by Paul Hosler in an - * article for Java Report Online. + * href="http://www.javareport.com/html/from_pages/article.asp?id=4276">an article for Java + * Report Online. */ public class MethodFinder { /** * Constructs a method finder for the supplied class. * - * @param clazz Class in which I will look for methods and - * constructors. + * @param clazz Class in which I will look for methods and constructors. * - * @exception IllegalArgumentException if clazz is null, or represents - * a primitive, or represents an array type. + * @exception IllegalArgumentException if clazz is null, or represents a primitive, or + * represents an array type. */ public MethodFinder (Class clazz) { if (clazz == null) { throw new IllegalArgumentException("null Class parameter"); } - if (clazz.isPrimitive()) { - throw new IllegalArgumentException( - "primitive Class parameter"); + throw new IllegalArgumentException("primitive Class parameter"); } - if (clazz.isArray()) { - throw new IllegalArgumentException( - "array Class parameter"); + throw new IllegalArgumentException("array Class parameter"); } - - this.clazz = clazz; + _clazz = clazz; } public boolean equals (Object o) { - if (this == o) + if (this == o) { return true; - else if (o == null || getClass() != o.getClass()) + } else if (o == null || getClass() != o.getClass()) { return false; - else { + } else { MethodFinder other = (MethodFinder)o; - return clazz.equals(other.clazz); + return _clazz.equals(other._clazz); } } /** - * Returns the most specific public constructor in my target class - * that accepts the number and type of parameters in the given Class - * array in a reflective invocation. + * Returns the most specific public constructor in my target class that accepts the number and + * type of parameters in the given Class array in a reflective invocation. * - *

A null value or Void.TYPE parameterTypes matches a - * corresponding Object or array reference in a constructor's formal - * parameter list, but not a primitive formal parameter. + *

A null value or Void.TYPE parameterTypes matches a corresponding Object or array + * reference in a constructor's formal parameter list, but not a primitive formal parameter. * - * @param parameterTypes array representing the number and types of - * parameters to look for in the constructor's signature. A null - * array is treated as a zero-length array. + * @param parameterTypes array representing the number and types of parameters to look for in + * the constructor's signature. A null array is treated as a zero-length array. * * @return Constructor object satisfying the conditions. * - * @exception NoSuchMethodException if no constructors match the - * criteria, or if the reflective call is ambiguous based on the - * parameter types. + * @exception NoSuchMethodException if no constructors match the criteria, or if the reflective + * call is ambiguous based on the parameter types. */ public Constructor findConstructor (Class[] parameterTypes) throws NoSuchMethodException @@ -114,28 +101,25 @@ public class MethodFinder parameterTypes = new Class[0]; } - return (Constructor)findMemberIn(ctorList, parameterTypes); + return (Constructor)findMemberIn(_ctorList, parameterTypes); } /** - * Returns the most specific public method in my target class that has - * the given name and accepts the number and type of parameters in the - * given Class array in a reflective invocation. + * Returns the most specific public method in my target class that has the given name and + * accepts the number and type of parameters in the given Class array in a reflective + * invocation. * - *

A null value or Void.TYPE in parameterTypes will match a - * corresponding Object or array reference in a method's formal - * parameter list, but not a primitive formal parameter. + *

A null value or Void.TYPE in parameterTypes will match a corresponding Object or array + * reference in a method's formal parameter list, but not a primitive formal parameter. * * @param methodName name of the method to search for. - * @param parameterTypes array representing the number and types of - * parameters to look for in the method's signature. A null array is - * treated as a zero-length array. + * @param parameterTypes array representing the number and types of parameters to look for in + * the method's signature. A null array is treated as a zero-length array. * * @return Method object satisfying the conditions. * - * @exception NoSuchMethodException if no methods match the criteria, - * or if the reflective call is ambiguous based on the parameter - * types, or if methodName is null. + * @exception NoSuchMethodException if no methods match the criteria, or if the reflective call + * is ambiguous based on the parameter types, or if methodName is null. */ public Method findMethod (String methodName, Class[] parameterTypes) throws NoSuchMethodException @@ -143,10 +127,10 @@ public class MethodFinder // make sure the constructor list is loaded maybeLoadMethods(); - List methodList = methodMap.get(methodName); + List methodList = _methodMap.get(methodName); if (methodList == null) { throw new NoSuchMethodException( - "No method named " + clazz.getName() + "." + methodName); + "No method named " + _clazz.getName() + "." + methodName); } if (parameterTypes == null) { @@ -157,9 +141,8 @@ public class MethodFinder } /** - * Like {@link #findMethod(String,Class[])} except that it takes the - * actual arguments that will be passed to the found method and - * creates the array of class objects for you using {@link + * Like {@link #findMethod(String,Class[])} except that it takes the actual arguments that will + * be passed to the found method and creates the array of class objects for you using {@link * ClassUtil#getParameterTypesFrom}. */ public Method findMethod (String methodName, Object[] args) @@ -169,34 +152,31 @@ public class MethodFinder } /** - * Basis of {@link #findConstructor} and {@link #findMethod}. The - * member list fed to this method will be either all {@link - * Constructor} objects or all {@link Method} objects. + * Basis of {@link #findConstructor} and {@link #findMethod}. The member list fed to this + * method will be either all {@link Constructor} objects or all {@link Method} objects. */ - private Member findMemberIn (List memberList, - Class[] parameterTypes) + protected Member findMemberIn (List memberList, Class[] parameterTypes) throws NoSuchMethodException { List matchingMembers = new ArrayList(); for (Iterator it = memberList.iterator(); it.hasNext();) { Member member = it.next(); - Class[] methodParamTypes = paramMap.get(member); + Class[] methodParamTypes = _paramMap.get(member); // check for exactly equal method signature if (Arrays.equals(methodParamTypes, parameterTypes)) { return member; } - if (ClassUtil.compatibleClasses( - methodParamTypes, parameterTypes)) { + if (ClassUtil.compatibleClasses(methodParamTypes, parameterTypes)) { matchingMembers.add(member); } } if (matchingMembers.isEmpty()) { throw new NoSuchMethodException( - "No member in " + clazz.getName() + " matching given args"); + "No member in " + _clazz.getName() + " matching given args"); } if (matchingMembers.size() == 1) { return (Member)matchingMembers.get(0); @@ -206,15 +186,13 @@ public class MethodFinder } /** - * @param memberList a list of members (either all constructors or all - * methods). + * @param memberList a list of members (either all constructors or all methods). * * @return the most specific of all members in the list. * - * @exception NoSuchMethodException if there is an ambiguity as to - * which is most specific. + * @exception NoSuchMethodException if there is an ambiguity as to which is most specific. */ - private Member findMostSpecificMemberIn (List memberList) + protected Member findMostSpecificMemberIn (List memberList) throws NoSuchMethodException { List mostSpecificMembers = new ArrayList(); @@ -228,24 +206,19 @@ public class MethodFinder boolean moreSpecific = true; boolean lessSpecific = false; - // Is member more specific than everyone in the - // most-specific set? + // Is member more specific than everyone in the most-specific set? for (Member moreSpecificMember : mostSpecificMembers) { if (!memberIsMoreSpecific(member, moreSpecificMember)) { - // if the candidate member is not more specific - // than this member, then it's not more specific - // than the entire set, but it may still be - // equivalently specific, so we check that next + // if the candidate member is not more specific than this member, then it's + // not more specific than the entire set, but it may still be equivalently + // specific, so we check that next moreSpecific = false; - // we check for a member of equal specificity by - // checking to see if this most specific member is - // explicitly more specific than the candidate - // member. if it is more specific, the candidate - // member can be chucked, otherwise we need to add - // the candidate member to the most-specific set - lessSpecific = - memberIsMoreSpecific(moreSpecificMember, member); + // we check for a member of equal specificity by checking to see if this + // most specific member is explicitly more specific than the candidate + // member. if it is more specific, the candidate member can be chucked, + // otherwise we need to add the candidate member to the most-specific set + lessSpecific = memberIsMoreSpecific(moreSpecificMember, member); break; } } @@ -264,30 +237,29 @@ public class MethodFinder if (mostSpecificMembers.size() > 1) { throw new NoSuchMethodException( - "Ambiguous request for member in " - + clazz.getName() - + " matching given args" ); + "Ambiguous request for member in " + _clazz.getName() + " matching given args" ); } return (Member)mostSpecificMembers.get(0); } + @Override // from Object public int hashCode () { - return clazz.hashCode(); + return _clazz.hashCode(); } /** * Loads up the data structures for my target class's constructors. */ - private void maybeLoadConstructors () + protected void maybeLoadConstructors () { - if (ctorList == null) { - ctorList = new ArrayList(); - Constructor[] ctors = clazz.getConstructors(); + if (_ctorList == null) { + _ctorList = new ArrayList(); + Constructor[] ctors = _clazz.getConstructors(); for (int i = 0; i < ctors.length; ++i) { - ctorList.add(ctors[i]); - paramMap.put(ctors[i], ctors[i].getParameterTypes()); + _ctorList.add(ctors[i]); + _paramMap.put(ctors[i], ctors[i].getParameterTypes()); } } } @@ -295,32 +267,30 @@ public class MethodFinder /** * Loads up the data structures for my target class's methods. */ - private void maybeLoadMethods () + protected void maybeLoadMethods () { - if (methodMap == null) { - methodMap = new HashMap>(); - Method[] methods = clazz.getMethods(); + if (_methodMap == null) { + _methodMap = new HashMap>(); + Method[] methods = _clazz.getMethods(); for (int i = 0; i < methods.length; ++i) { Method m = methods[i]; String methodName = m.getName(); Class[] paramTypes = m.getParameterTypes(); - List list = methodMap.get(methodName); - + List list = _methodMap.get(methodName); if (list == null) { list = new ArrayList(); - methodMap.put(methodName, list); + _methodMap.put(methodName, list); } - if (!ClassUtil.classIsAccessible(clazz)) { - m = ClassUtil.getAccessibleMethodFrom( - clazz, methodName, paramTypes ); + if (!ClassUtil.classIsAccessible(_clazz)) { + m = ClassUtil.getAccessibleMethodFrom(_clazz, methodName, paramTypes ); } if (m != null) { list.add(m); - paramMap.put(m, paramTypes); + _paramMap.put(m, paramTypes); } } } @@ -330,37 +300,27 @@ public class MethodFinder * @param first a Member. * @param second a Member. * - * @return true if the first Member is more specific than the second, - * false otherwise. Specificity is determined according to the - * procedure in the Java Language Specification, section 15.12.2. + * @return true if the first Member is more specific than the second, false otherwise. + * Specificity is determined according to the procedure in the Java Language Specification, + * section 15.12.2. */ - private boolean memberIsMoreSpecific (Member first, Member second) + protected boolean memberIsMoreSpecific (Member first, Member second) { - Class[] firstParamTypes = paramMap.get(first); - Class[] secondParamTypes = paramMap.get(second); - return ClassUtil.compatibleClasses( - secondParamTypes, firstParamTypes); + Class[] firstParamTypes = _paramMap.get(first); + Class[] secondParamTypes = _paramMap.get(second); + return ClassUtil.compatibleClasses(secondParamTypes, firstParamTypes); } - /** - * The target class to look for methods and constructors in. - */ - private Class clazz; + /** The target class to look for methods and constructors in. */ + protected Class _clazz; - /** - * Mapping from method name to the Methods in the target class with - * that name. - */ - private Map> methodMap = null; + /** Mapping from method name to the Methods in the target class with that name. */ + protected Map> _methodMap = null; - /** - * List of the Constructors in the target class. - */ - private List ctorList = null; + /** List of the Constructors in the target class. */ + protected List _ctorList = null; - /** - * Mapping from a Constructor or Method object to the Class objects - * representing its formal parameters. - */ - private Map paramMap = new HashMap(); + /** Mapping from a Constructor or Method object to the Class objects representing its formal + * parameters. */ + protected Map _paramMap = new HashMap(); }