获取匹配的可访问方法
/* ** DroidPlugin Project ** ** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com> ** ** This file is part of DroidPlugin. ** ** DroidPlugin is free software: you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation, either ** version 3 of the License, or (at your option) any later version. ** ** DroidPlugin is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with DroidPlugin. If not, see <http://www.gnu.org/licenses/lgpl.txt> ** **/ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /* 来自 *时 代 J a v a 公 众 号 - N o w J a v a . c o m*/ import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; public class Main{ private static Map<String, Method> sMethodCache = new HashMap<String, Method>(); private static Method getMatchingAccessibleMethod(final Class<?> cls, final String methodName, final Class<?>... parameterTypes) { String key = getKey(cls, methodName, parameterTypes); Method cachedMethod; synchronized (sMethodCache) { /* 时 代 J a v a - nowjava.com 提供 */ cachedMethod = sMethodCache.get(key); } if (cachedMethod != null) { if (!cachedMethod.isAccessible()) { cachedMethod.setAccessible(true); } return cachedMethod; } try { final Method method = cls.getMethod(methodName, parameterTypes); MemberUtils.setAccessibleWorkaround(method); synchronized (sMethodCache) { sMethodCache.put(key, method); } return method; } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception } // search through all methods Method bestMatch = null; final Method[] methods = cls.getMethods(); for (final Method method : methods) { // compare name and parameters if (method.getName().equals(methodName) && MemberUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) { // get accessible version of method final Method accessibleMethod = getAccessibleMethod(method); if (accessibleMethod != null && (bestMatch == null || MemberUtils .compareParameterTypes(accessibleMethod .getParameterTypes(), bestMatch .getParameterTypes(), parameterTypes) < 0)) { bestMatch = accessibleMethod; } } } if (bestMatch != null) { MemberUtils.setAccessibleWorkaround(bestMatch); } synchronized (sMethodCache) { sMethodCache.put(key, bestMatch); } return bestMatch; } private static String getKey(final Class<?> cls, final String methodName, final Class<?>... parameterTypes) { StringBuilder sb = new StringBuilder(); sb.append(cls.toString()).append("#").append(methodName); if (parameterTypes != null && parameterTypes.length > 0) { for (Class<?> parameterType : parameterTypes) { sb.append(parameterType.toString()).append("#"); } } else { sb.append(Void.class.toString()); } return sb.toString(); } private static boolean isAccessible(final Class<?> type) { Class<?> cls = type; while (cls != null) { if (!Modifier.isPublic(cls.getModifiers())) { return false; } cls = cls.getEnclosingClass(); } return true; } private static Method getAccessibleMethod(Method method) { if (!MemberUtils.isAccessible(method)) { return null; } // If the declaring class is public, we are done final Class<?> cls = method.getDeclaringClass(); if (Modifier.isPublic(cls.getModifiers())) { return method; } final String methodName = method.getName(); final Class<?>[] parameterTypes = method.getParameterTypes(); // Check the implemented interfaces and subinterfaces method = getAccessibleMethodFromInterfaceNest(cls, methodName, parameterTypes); // Check the superclass chain if (method == null) { method = getAccessibleMethodFromSuperclass(cls, methodName, parameterTypes); } return method; } public static Method getAccessibleMethod(final Class<?> cls, final String methodName, final Class<?>... parameterTypes) throws NoSuchMethodException { String key = getKey(cls, methodName, parameterTypes); Method method; synchronized (sMethodCache) { method = sMethodCache.get(key); } if (method != null) { if (!method.isAccessible()) { method.setAccessible(true); } return method; } Method accessibleMethod = getAccessibleMethod(cls.getMethod( methodName, parameterTypes)); synchronized (sMethodCache) { sMethodCache.put(key, accessibleMethod); } return accessibleMethod; } private static Method getAccessibleMethodFromInterfaceNest( Class<?> cls, final String methodName, final Class<?>... parameterTypes) { // Search up the superclass chain for (; cls != null; cls = cls.getSuperclass()) { // Check the implemented interfaces of the parent class final Class<?>[] interfaces = cls.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { // Is this interface public? if (!Modifier.isPublic(interfaces[i].getModifiers())) { continue; } // Does the method exist on this interface? try { return interfaces[i].getDeclaredMethod(methodName, parameterTypes); } catch (final NoSuchMethodException e) {