📄 methodutils.java
字号:
/* * Copyright 2004,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.bsf.util;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.Enumeration;import java.util.Vector;/** * This file is a collection of reflection utilities for dealing with * methods and constructors. * * @author Sanjiva Weerawarana * @author Joseph Kesselman */public class MethodUtils { /** Internal Class for getEntryPoint(). Implements 15.11.2.2 MORE SPECIFIC rules. Retains a list of methods (already known to match the arguments). As each method is added, we check against past entries to determine which if any is "more specific" -- defined as having _all_ its arguments (not just a preponderance) be method-convertable into those of another. If such a relationship is found, the more-specific method is retained and the less-specific method is discarded. At the end, if this has yielded a single winner it is considered the Most Specific Method and hence the one that should be invoked. Otherwise, a NoSuchMethodException is thrown. PERFORMANCE VERSUS ARCHITECTURE: Arguably, this should "have-a" Vector. But the code is 6% smaller, and possibly faster, if we code it as "is-a" Vector. Since it's an inner class, nobody's likely to abuse the privilage. Note: "Static" in the case of an inner class means "Does not reference instance data in the outer class", and is required since our caller is a static method. */ private static class MoreSpecific extends Vector { /** Submit an entry-point to the list. May be discarded if a past entry is more specific, or may cause others to be discarded it if is more specific. newEntry: Method or Constructor under consideration. */ void addItem (Object newEntry) { if(size()==0) addElement(newEntry); else { Class[] newargs=entryGetParameterTypes(newEntry); boolean keep=true; for (Enumeration e = elements(); keep & e.hasMoreElements() ; ) { Object oldEntry=e.nextElement(); // CAVEAT: Implicit references to enclosing class! Class[] oldargs=entryGetParameterTypes(oldEntry); if(areMethodConvertable(oldargs,newargs)) removeElement(oldEntry); // New more specific; discard old else if(areMethodConvertable(newargs,oldargs)) keep=false; // Old more specific; discard new // Else they're tied. Keep both and hope someone beats both. } if(keep) addElement(newEntry); } } /** Obtain the single Most Specific entry-point. If there is no clear winner, or if the list is empty, throw NoSuchMethodException. Arguments describe the call we were hoping to resolve. They are used to throw a nice verbose exception if something goes wrong. */ Object getMostSpecific(Class targetClass,String methodName, Class[] argTypes,boolean isStaticReference) throws NoSuchMethodException { if(size()==1) return firstElement(); if(size()>1) { StringBuffer buf=new StringBuffer(); Enumeration e=elements(); buf.append(e.nextElement()); while(e.hasMoreElements()) buf.append(" and ").append(e.nextElement()); throw new NoSuchMethodException (callToString(targetClass, methodName, argTypes, isStaticReference)+ " is ambiguous. It matches "+ buf.toString()); } return null; } } /** Convenience method: Test an entire parameter-list/argument-list pair for isMethodConvertable(), qv. */ static private boolean areMethodConvertable(Class[] parms,Class[] args) { if(parms.length!=args.length) return false; for(int i=0;i<parms.length;++i) if(!isMethodConvertable(parms[i],args[i])) return false; return true; } /** Internal subroutine for getEntryPoint(): Format arguments as a string describing the function being searched for. Used in verbose exceptions. */ private static String callToString(Class targetClass,String methodName, Class[] argTypes,boolean isStaticReference) { StringBuffer buf = new StringBuffer(); if(isStaticReference) buf.append("static "); buf.append(StringUtils.getClassName(targetClass)); if(methodName!=null) buf.append(".").append(methodName); buf.append("("); if (argTypes != null && argTypes.length>0) { if(false) { // ????? Sanjiva has an ArrayToString method. Using it would // save a few bytes, at cost of giving up some reusability. } else { buf.append(StringUtils.getClassName(argTypes[0])); for (int i = 1; i < argTypes.length; i++) { buf.append(",").append(StringUtils.getClassName(argTypes[i])); } } } else buf.append("[none]"); buf.append(")"); return buf.toString(); } /** Utility function: obtain common data from either Method or Constructor. (In lieu of an EntryPoint interface.) */ static int entryGetModifiers(Object entry) { return (entry instanceof Method) ? ((Method)entry).getModifiers() : ((Constructor)entry).getModifiers(); } // The common lookup code would be much easier if Method and // Constructor shared an "EntryPoint" Interface. Unfortunately, even // though their APIs are almost identical, they don't. These calls // are a workaround... at the cost of additional runtime overhead // and some extra bytecodes. // // (A JDK bug report has been submitted requesting that they add the // Interface; it would be easy, harmless, and useful.) /** Utility function: obtain common data from either Method or Constructor. (In lieu of an EntryPoint interface.) */ static String entryGetName(Object entry) { return (entry instanceof Method) ? ((Method)entry).getName() : ((Constructor)entry).getName(); } /** Utility function: obtain common data from either Method or Constructor. (In lieu of an EntryPoint interface.) */ static Class[] entryGetParameterTypes(Object entry) { return (entry instanceof Method) ? ((Method)entry).getParameterTypes() : ((Constructor)entry).getParameterTypes(); } /** Utility function: obtain common data from either Method or Constructor. (In lieu of an EntryPoint interface.) */ static String entryToString(Object entry) { return (entry instanceof Method) ? ((Method)entry).toString() : ((Constructor)entry).toString(); } ////////////////////////////////////////////////////////////////////////// /** Class.getConstructor() finds only the entry point (if any) _exactly_ matching the specified argument types. Our implmentation can decide between several imperfect matches, using the same search algorithm as the Java compiler. Note that all constructors are static by definition, so isStaticReference is true. @exception NoSuchMethodException if constructor not found. */ static public Constructor getConstructor(Class targetClass, Class[] argTypes) throws SecurityException, NoSuchMethodException { return (Constructor) getEntryPoint(targetClass,null,argTypes,true); } ////////////////////////////////////////////////////////////////////////// /** * Search for entry point, per Java Language Spec 1.0 * as amended, verified by comparison against compiler behavior. * * @param targetClass Class object for the class to be queried. * @param methodName Name of method to invoke, or null for constructor. * Only Public methods will be accepted. * @param argTypes Classes of intended arguments. Note that primitives * must be specified via their TYPE equivalents, * rather than as their wrapper classes -- Integer.TYPE * rather than Integer. "null" may be passed in as an * indication that you intend to invoke the method with * a literal null argument and therefore can accept * any object type in this position. * @param isStaticReference If true, and if the target is a Class object, * only static methods will be accepted as valid matches. * * @return a Method or Constructor of the appropriate signature * * @exception SecurityException if security violation * @exception NoSuchMethodException if no such method */ static private Object getEntryPoint(Class targetClass, String methodName, Class[] argTypes, boolean isStaticReference) throws SecurityException, NoSuchMethodException { // 15.11.1: OBTAIN STARTING CLASS FOR SEARCH Object m=null; // 15.11.2 DETERMINE ARGUMENT SIGNATURE // (Passed in as argTypes array.)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -