📄 classes.java
字号:
j = Strings.skipWhitespaces(signature, k + 1); if (signature.charAt(j) == ')') break; k = Strings.anyOf(signature, ",) \t\n\r", j); k = Strings.skipWhitespaces(signature, k); if (k >= len) throw new IllegalSyntaxException(signature); argTypes.add(signature.substring(j, k).trim()); cc = signature.charAt(k); if (cc != ',' && cc != ')') { //parameter name found k = Strings.anyOf(signature, ",) \t\n\r", j = k); k = Strings.skipWhitespaces(signature, k); argNames.add(signature.substring(j, k).trim()); k = Strings.anyOf(signature, ",)", k); if (k >= len) throw new IllegalSyntaxException(signature); } else { argNames.add(""); //no name specified } } while (signature.charAt(k) == ','); assert argTypes.size() == argNames.size(); //process throws ... String strThrows = "throws"; String tEx = null; j = signature.indexOf(strThrows, k); if (j >= k && j < len) { //got throws k = signature.indexOf(';', j); if (k >= 0) tEx = signature.substring(j + strThrows.length(), k).trim(); else tEx = signature.substring(j + strThrows.length(), len).trim(); } return new MethodInfo(returnType, method, (String[])argTypes.toArray(new String[argTypes.size()]), (String[])argNames.toArray(new String[argNames.size()]), tEx); } /** * Gets the method based on the signature. It also returns the parameter * names to the params list. * * <p>Like {@link #getMethodInPublic(Class, String, Class[])}, it returns * only public method in a public class/interface. * * <p>For example, "find(java.lang.String name)" will return * the method with one String-typed argument and params will hold "name". * The return type is optional (actualy ignored). * * <p>If params is null, the parameter names are not returned and * the signature could be simplified as "find(java.lang.String)". * * <p>A cache mechanism is implemented, so you don't need to cache it * again in the caller. * * @param cls the class to look * @param signature the method signature; the return type is optional * @param params the collection to hold the parameter names returned; * null means no parameter names to return */ public static final Method getMethodBySignature(Class cls, String signature, Collection params) throws NoSuchMethodException, ClassNotFoundException { MethodInfo mi = parseMethod(signature); LinkedList argTypes = new LinkedList(); for (int i = 0; i < mi.argTypes.length; i++) { argTypes.add(forNameByThread(mi.argTypes[i])); if (params != null) params.add(mi.argNames[i]); //param name found } return getMethodInPublic(cls, mi.method, (Class[])argTypes.toArray(new Class[argTypes.size()])); } /** * Gets the method that is declared in a public class/interface. * * <p>Class.getMethod returns a public method but the class itself * might not be public. However, in many cases, that class * also implements a public interface or class. * * <p>This method will search all its public classes to look for * the method that is 'real' public. * * <p>NoSuchMethodException is thrown if no public * class/interface is found to have the method. */ public static final Method getMethodInPublic(Class cls, String name, Class[] argTypes) throws NoSuchMethodException { final Method m = cls.getMethod(name, argTypes); if (Modifier.isPublic(m.getDeclaringClass().getModifiers())) return m; final Class[] clses = cls.getInterfaces(); for (int j = 0; j< clses.length; ++j) try { return getMethodInPublic(clses[j], name, argTypes); } catch (NoSuchMethodException ex) { //ignore it } final Class basecls = cls.getSuperclass(); if (basecls != null) try { return getMethodInPublic(basecls, name, argTypes); } catch (NoSuchMethodException ex) { //ignore it } throw new NoSuchMethodException(cls+": "+name+" "+Objects.toString(argTypes)); } /** Gets one of the close method by specifying the arguments, rather * than the argument types. It actually calls {@link #getCloseMethod}. */ public static final Method getMethodByObject(Class cls, String name, Object[] args) throws NoSuchMethodException { if (args == null) return getMethodInPublic(cls, name, null); final Class[] argTypes = new Class[args.length]; for (int j = 0; j < args.length; ++j) argTypes[j] = args[j] != null ? args[j].getClass(): null; return getCloseMethod(cls, name, argTypes); } /** * Gets one of the close methods -- a close method is a method * with the same name and the compatible argument type. * By compatiable we mean the real method's argument type is * the same as or a superclass of the specified one. * * <p>It might not be the best fit one, unless there is a method * whose argument types are exactly argTypes. * * <p>You might specify the exact number in argTypes. If any of them is * unknwon, use null. Example, in the following, the first argument could * be anything and the second is anything deriving from MyClass:<br> * <code>new Class[] {null, MyClass.class}</code> * * <p>Note: if an argument accepts int, then Integer is considered * as compatible (unlike Class.getMethod). So are long, byte... * * <p>A cache mechanism is implemented, so you don't need to cache it * again in the caller. * * @param cls the class to locate the method * @param name the method name * @param argTypes an array of the argument classes; * null to denote no argument at all (i.e., exact match). * Any argTypes[i] could be null to denote any class. * @return the method * @exception NoSuchMethodException if the method is not found */ public static final Method getCloseMethod(Class cls, String name, Class[] argTypes) throws NoSuchMethodException { if (argTypes == null || argTypes.length == 0) return getMethodInPublic(cls, name, null); final AOInfo aoi = new AOInfo(cls, name, argTypes, 0); Method m; synchronized(_closms) { m = (Method)_closms.get(aoi); } if (m != null) return m; m = myGetCloseMethod(cls, name, argTypes, false); synchronized(_closms) { _closms.put(aoi, m); } return m; } /** * Like {@link #getCloseMethod} to get a 'close' method, but * it look for subclass of the arguement (instead of superclass). * In other words, it looks for the method whose argument type is * the same as or a subclass of the specified one. */ public static final Method getCloseMethodBySubclass(Class cls, String name, Class[] argTypes) throws NoSuchMethodException { if (argTypes == null || argTypes.length == 0) return getMethodInPublic(cls, name, null); final AOInfo aoi = new AOInfo(cls, name, argTypes, B_BY_SUBCLASS); Method m; synchronized(_closms) { m = (Method)_closms.get(aoi); } if (m != null) return m; m = myGetCloseMethod(cls, name, argTypes, true); synchronized(_closms) { _closms.put(aoi, m); } return m; } private static CacheMap _closms = new CacheMap(113).setMaxSize(500).setLifetime(4*60*60*1000); private static final Method myGetCloseMethod(final Class cls, final String name, final Class[] argTypes, final boolean bySubclass) throws NoSuchMethodException { assert D.OFF || argTypes != null: "Caller shall handle null"; for (int j = 0;; ++j) { if (j == argTypes.length) {//all argTypes[j] non-null try { return getMethodInPublic(cls, name, argTypes); } catch (NoSuchMethodException ex) { //ignore it break; } } if (argTypes[j] == null) //specil handling required break; } final Method [] ms = cls.getMethods(); for (int j = 0; j < ms.length; ++j) { if (!ms[j].getName().equals(name)) continue; final Class[] mTypes = ms[j].getParameterTypes(); if (mTypes.length != argTypes.length) continue; //not matched final boolean bPublic = Modifier.isPublic(ms[j].getDeclaringClass().getModifiers()); for (int k = 0;; ++k) { if (k == argTypes.length) { //all matched if (bPublic) return ms[j]; return getMethodInPublic( cls, ms[j].getName(), ms[j].getParameterTypes()); } final Class argType = argTypes[k], mType = mTypes[k]; if (argType == null || (!bySubclass && mType.isAssignableFrom(argType)) || (bySubclass && argType.isAssignableFrom(mType))) continue; //match final Class c = Primitives.toPrimitive(argType); if (c == null || !c.equals(mType)) break; //not match } } throw new NoSuchMethodException(cls+": "+name+" argTypes: "+Objects.toString(argTypes)); } /** Returns all close methods that match the specified condition, or * a zero-length array if none is found. * <p>Unlike {@link #getCloseMethod}, we don't cache the searched result, * and it won't throw any exception. */ public static final Method[] getCloseMethods(Class cls, String name, Class[] argTypes) { if (argTypes == null || argTypes.length == 0) { try { return new Method[] {getMethodInPublic(cls, name, null)}; } catch (NoSuchMethodException ex) { return new Method[0]; } } return myGetCloseMethods(cls, name, argTypes, false); } /** * Like {@link #getCloseMethods} to get all 'close' methods, but * it look for subclass of the arguement (instead of superclass). * In other words, it looks for the method whose argument type is * the same as or a subclass of the specified one. */ public static final Method[] getCloseMethodsBySubclass(Class cls, String name, Class[] argTypes) { if (argTypes == null || argTypes.length == 0) return getCloseMethods(cls, name, null); return myGetCloseMethods(cls, name, argTypes, true); } private static final Method[] myGetCloseMethods(final Class cls, final String name, final Class[] argTypes, final boolean bySubclass) { assert D.OFF || argTypes != null: "Caller shall handle null"; final List mtds = new LinkedList(); final Method [] ms = cls.getMethods(); for (int j = 0; j < ms.length; ++j) { if (!ms[j].getName().equals(name)) continue; final Class[] mTypes = ms[j].getParameterTypes(); if (mTypes.length != argTypes.length) continue; //not matched final boolean bPublic = Modifier.isPublic(ms[j].getDeclaringClass().getModifiers()); for (int k = 0;; ++k) { if (k == argTypes.length) { //all matched if (bPublic) { mtds.add(ms[j]); } else { try { mtds.add(getMethodInPublic( cls, ms[j].getName(), ms[j].getParameterTypes())); } catch (NoSuchMethodException ex) { //ignore; not add } } break; //found; next method } final Class argType = argTypes[k], mType = mTypes[k]; if (argType == null || (!bySubclass && mType.isAssignableFrom(argType)) || (bySubclass && argType.isAssignableFrom(mType))) continue; //match one argument final Class c = Primitives.toPrimitive(argType); if (c == null || !c.equals(mType)) break; //not match; next method } } return (Method[])mtds.toArray(new Method[mtds.size()]); } /** * Search the get method; not imply B_METHODONLY. */ public static final int B_GET=0; //must be 0 /** * Search the set method; not imply B_METHODONLY. */ public static final int B_SET=1; //must be 1 /** * Only search for public methods or fields. */ public static final int B_PUBLIC_ONLY=0x0002; /** * Only search for methods; excluding fields. */ public static final int B_METHOD_ONLY=0x0004; /** Used by {@link #getCloseMethodBySubclass} to distiquish * {@link #getCloseMethod}. */ private static final int B_BY_SUBCLASS = 0x1000; /** * Gets the specified accessible object, either a method or a field, by * searching the specified name. * * <p>The search sequence is: (assume field name is body)><br> * getBody(...)<br> * isBody(...)<br> * body(...)<br> * body * * <p>If B_SET is specified, setBody(...) is searched instead of * getBody(...) and isBody(...). The field is searched only if * argsType.length is 0 or 1. * * <p>Note: it uses {@link #getCloseMethod} to get the method. * * <p>A cache mechanism is implemented, so you don't need to cache it * again in the caller. * * @param cls the class to find * @param name the name of the accessible object * @param argTypes the parameter type of the method to find * @param flags a combination of B_xxx or zero * @return the accessible object; either Field or Method * @exception NoSuchMethodException if neither the set method of * specified field nor the field itself not found * @exception SecurityException if access to the information is denied */ public static final AccessibleObject getAccessibleObject(Class cls, String name, Class[] argTypes, int flags) throws NoSuchMethodException { final AOInfo aoi = new AOInfo(cls, name, argTypes, flags); AccessibleObject ao; synchronized(_acsos) { ao = (AccessibleObject)_acsos.get(aoi); } if (ao != null) return ao; ao = myGetAcsObj(cls, name, argTypes, flags); synchronized(_acsos) { _acsos.put(aoi, ao); } return ao; } private static CacheMap _acsos = new CacheMap(113).setMaxSize(500).setLifetime(4*60*60*1000); private static final AccessibleObject myGetAcsObj(Class cls, String name, Class[] argTypes, int flags) throws NoSuchMethodException { //try public set/get final String decoratedName = toMethodName(name, (flags&B_SET) != 0 ? "set": "get"); try { return getCloseMethod(cls, decoratedName, argTypes); } catch (NoSuchMethodException ex) { //ignore } //try public is String isMethodName = null; if ((flags&B_SET) == 0) try { isMethodName = toMethodName(name, "is"); return getCloseMethod(cls, isMethodName, argTypes); } catch (NoSuchMethodException ex) { //ignore } //try public same try { return getCloseMethod(cls, name, argTypes); } catch (NoSuchMethodException ex) { if ((flags & (B_PUBLIC_ONLY|B_METHOD_ONLY)) ==(B_PUBLIC_ONLY|B_METHOD_ONLY)) throw ex; } if ((flags & B_PUBLIC_ONLY) == 0) { //try any set/get try { return getAnyMethod(cls, decoratedName, argTypes); } catch (NoSuchMethodException ex) { //ignore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -