Path: blob/master/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java
41161 views
/*1* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package com.sun.beans.finder;2526import com.sun.beans.TypeResolver;27import com.sun.beans.util.Cache;2829import java.lang.reflect.Method;30import java.lang.reflect.Modifier;31import java.lang.reflect.ParameterizedType;32import java.lang.reflect.Type;33import java.util.Arrays;3435import static com.sun.beans.util.Cache.Kind.SOFT;36import static sun.reflect.misc.ReflectUtil.isPackageAccessible;3738/**39* This utility class provides {@code static} methods40* to find a public method with specified name and parameter types41* in specified class.42*43* @since 1.744*45* @author Sergey A. Malenkov46*/47public final class MethodFinder extends AbstractFinder<Method> {48private static final Cache<Signature, Method> CACHE = new Cache<Signature, Method>(SOFT, SOFT) {49@Override50public Method create(Signature signature) {51try {52MethodFinder finder = new MethodFinder(signature.getName(), signature.getArgs());53return findAccessibleMethod(finder.find(signature.getType().getMethods()));54}55catch (Exception exception) {56throw new SignatureException(exception);57}58}59};6061/**62* Finds public method (static or non-static)63* that is accessible from public class.64*65* @param type the class that can have method66* @param name the name of method to find67* @param args parameter types that is used to find method68* @return object that represents found method69* @throws NoSuchMethodException if method could not be found70* or some methods are found71*/72public static Method findMethod(Class<?> type, String name, Class<?>...args) throws NoSuchMethodException {73if (name == null) {74throw new IllegalArgumentException("Method name is not set");75}76PrimitiveWrapperMap.replacePrimitivesWithWrappers(args);77Signature signature = new Signature(type, name, args);7879try {80Method method = CACHE.get(signature);81return (method == null) || isPackageAccessible(method.getDeclaringClass()) ? method : CACHE.create(signature);82}83catch (SignatureException exception) {84throw exception.toNoSuchMethodException("Method '" + name + "' is not found");85}86}8788/**89* Finds public non-static method90* that is accessible from public class.91*92* @param type the class that can have method93* @param name the name of method to find94* @param args parameter types that is used to find method95* @return object that represents found method96* @throws NoSuchMethodException if method could not be found97* or some methods are found98*/99public static Method findInstanceMethod(Class<?> type, String name, Class<?>... args) throws NoSuchMethodException {100Method method = findMethod(type, name, args);101if (Modifier.isStatic(method.getModifiers())) {102throw new NoSuchMethodException("Method '" + name + "' is static");103}104return method;105}106107/**108* Finds public static method109* that is accessible from public class.110*111* @param type the class that can have method112* @param name the name of method to find113* @param args parameter types that is used to find method114* @return object that represents found method115* @throws NoSuchMethodException if method could not be found116* or some methods are found117*/118public static Method findStaticMethod(Class<?> type, String name, Class<?>...args) throws NoSuchMethodException {119Method method = findMethod(type, name, args);120if (!Modifier.isStatic(method.getModifiers())) {121throw new NoSuchMethodException("Method '" + name + "' is not static");122}123return method;124}125126/**127* Finds method that is accessible from public class or interface through class hierarchy.128*129* @param method object that represents found method130* @return object that represents accessible method131* @throws NoSuchMethodException if method is not accessible or is not found132* in specified superclass or interface133*/134public static Method findAccessibleMethod(Method method) throws NoSuchMethodException {135Class<?> type = method.getDeclaringClass();136137if (!FinderUtils.isExported(type)) {138throw new NoSuchMethodException("Method '" + method.getName() + "' is not accessible");139}140if (Modifier.isPublic(type.getModifiers()) && isPackageAccessible(type)) {141return method;142}143if (Modifier.isStatic(method.getModifiers())) {144throw new NoSuchMethodException("Method '" + method.getName() + "' is not accessible");145}146for (Type generic : type.getGenericInterfaces()) {147try {148return findAccessibleMethod(method, generic);149}150catch (NoSuchMethodException exception) {151// try to find in superclass or another interface152}153}154return findAccessibleMethod(method, type.getGenericSuperclass());155}156157/**158* Finds method that accessible from specified class.159*160* @param method object that represents found method161* @param generic generic type that is used to find accessible method162* @return object that represents accessible method163* @throws NoSuchMethodException if method is not accessible or is not found164* in specified superclass or interface165*/166private static Method findAccessibleMethod(Method method, Type generic) throws NoSuchMethodException {167String name = method.getName();168Class<?>[] params = method.getParameterTypes();169if (generic instanceof Class) {170Class<?> type = (Class<?>) generic;171return findAccessibleMethod(type.getMethod(name, params));172}173if (generic instanceof ParameterizedType) {174ParameterizedType pt = (ParameterizedType) generic;175Class<?> type = (Class<?>) pt.getRawType();176for (Method m : type.getMethods()) {177if (m.getName().equals(name)) {178Class<?>[] pts = m.getParameterTypes();179if (pts.length == params.length) {180if (Arrays.equals(params, pts)) {181return findAccessibleMethod(m);182}183Type[] gpts = m.getGenericParameterTypes();184if (params.length == gpts.length) {185if (Arrays.equals(params, TypeResolver.erase(TypeResolver.resolve(pt, gpts)))) {186return findAccessibleMethod(m);187}188}189}190}191}192}193throw new NoSuchMethodException("Method '" + name + "' is not accessible");194}195196197private final String name;198199/**200* Creates method finder with specified array of parameter types.201*202* @param name the name of method to find203* @param args the array of parameter types204*/205private MethodFinder(String name, Class<?>[] args) {206super(args);207this.name = name;208}209210/**211* Checks validness of the method.212* The valid method should be public and213* should have the specified name.214*215* @param method the object that represents method216* @return {@code true} if the method is valid,217* {@code false} otherwise218*/219@Override220protected boolean isValid(Method method) {221return super.isValid(method) && method.getName().equals(this.name);222}223}224225226