Java Reflection Method Name getMethod(Class klass, String methodName, Class... paramTypes)

Here you can find the source of getMethod(Class klass, String methodName, Class... paramTypes)

Description

get Method

License

LGPL

Declaration

public static Method getMethod(Class<?> klass, String methodName, Class<?>... paramTypes) 

Method Source Code

//package com.java2s;
//License from project: LGPL 

import java.lang.reflect.Method;

import java.util.ArrayList;

import java.util.Iterator;
import java.util.List;

public class Main {
    public static Method getMethod(Class<?> klass, String methodName, Class<?>... paramTypes) {

        List<Method> candidates = new ArrayList<Method>();

        // NOTE: getMethods() includes inherited methods
        outer: for (Method method : klass.getMethods()) {
            if (method.getName().equals(methodName)) {
                Class<?>[] methodParamTypes = method.getParameterTypes();
                if (paramTypes.length == methodParamTypes.length
                        || (method.isVarArgs() && paramTypes.length >= methodParamTypes.length - 1)) {
                    // method has correct name and # of parameters

                    if (method.isVarArgs()) {
                        for (int i = 0; i < methodParamTypes.length - 1; i++) {
                            if (paramTypes[i] != null && !methodParamTypes[i].isAssignableFrom(paramTypes[i])) {
                                continue outer;
                            }/*from   w ww .  j a v a  2  s .  co  m*/
                        }
                        if (methodParamTypes.length == paramTypes.length + 1) {
                            // no param is specified for the optional vararg
                            // spot
                        } else if (methodParamTypes.length == paramTypes.length
                                && methodParamTypes[paramTypes.length - 1]
                                        .isAssignableFrom(paramTypes[paramTypes.length - 1])) {
                            // an array is specified for the last param
                        } else {
                            Class<?> varClass = methodParamTypes[methodParamTypes.length - 1].getComponentType();
                            for (int i = methodParamTypes.length - 1; i < paramTypes.length; i++) {
                                if (paramTypes[i] != null && !varClass.isAssignableFrom(paramTypes[i])) {
                                    continue outer;
                                }
                            }
                        }
                    } else {
                        for (int i = 0; i < methodParamTypes.length; i++) {
                            if (paramTypes[i] != null && !methodParamTypes[i].isAssignableFrom(paramTypes[i])) {
                                continue outer;
                            }
                        }
                    }
                    candidates.add(method);
                }
            }
        }

        if (candidates.size() == 0) {
            return null;
        } else if (candidates.size() == 1) {
            return candidates.get(0);
        } else {
            // There are several possible methods. Choose the most specific.

            // Throw away any var-args options.
            // Non var-args methods always beat var-args methods and we're going
            // to say that if we have two var-args
            // methods, we cannot choose between the two.
            Iterator<Method> itr = candidates.iterator();
            while (itr.hasNext()) {
                Method m = itr.next();
                if (m.isVarArgs()) {
                    // the exception is if an array is actually specified as the
                    // last parameter
                    if (m.getParameterTypes().length != paramTypes.length
                            || !m.getParameterTypes()[paramTypes.length - 1]
                                    .isAssignableFrom(paramTypes[paramTypes.length - 1]))
                        itr.remove();
                }
            }

            // If there are no candidates left, that means we had only var-args
            // methods, which we can't choose
            // between.
            if (candidates.size() == 0)
                return null;

            Method a = candidates.get(0);
            boolean ambiguous = false;

            for (int j = 1; j < candidates.size(); j++) {
                Method b = candidates.get(j);

                Class<?>[] aTypes = a.getParameterTypes();
                Class<?>[] bTypes = b.getParameterTypes();

                int aScore = 0, bScore = 0;
                // increment score if distance is greater for a given parameter
                for (int i = 0; i < aTypes.length; i++) {
                    if (aTypes[i] != null) {
                        int distA = getDist(aTypes[i], paramTypes[i]);
                        int distB = getDist(bTypes[i], paramTypes[i]);
                        if (distA > distB) {
                            bScore++;
                        } else if (distA < distB) {
                            aScore++;
                        } else if (distA == 1000) { // both are interfaces
                            // if one interface extends the other, that
                            // interface is lower in the hierarchy (more
                            // specific) and wins
                            if (!aTypes[i].equals(bTypes[i])) {
                                if (aTypes[i].isAssignableFrom(bTypes[i]))
                                    bScore++;
                                else if (bTypes[i].isAssignableFrom(aTypes[i]))
                                    aScore++;
                            }
                        }
                    }
                }

                // lower score wins
                if (aScore == bScore) {
                    ambiguous = true;
                } else if (bScore > aScore) {
                    a = b; // b wins
                    ambiguous = false;
                }
            }

            if (ambiguous)
                return null;

            return a;
        }
    }

    private static int getDist(Class<?> superClass, Class<?> klass) {
        if (klass.isArray()) {
            if (superClass.isArray()) {
                superClass = superClass.getComponentType();
                klass = klass.getComponentType();
            } else {
                // superClass must be Object. An array fitting into an Object
                // must be more general than an array fitting into an Object[]
                // array.
                return 3000;
            }
        }

        if (superClass.equals(klass))
            return 0;
        if (superClass.equals(Object.class))
            return 2000; // specifying Object is always the most general
        if (superClass.isInterface()) {
            return 1000;
        }

        int dist = 0;
        while (true) {
            dist++;
            klass = klass.getSuperclass();
            if (superClass.equals(klass))
                return dist;
        }
    }
}

Related

  1. getMethod(Class cls, String name, Class... types)
  2. getMethod(Class clss, String name, Class... params)
  3. getMethod(Class clz, String name)
  4. getMethod(Class klass, String methodName)
  5. getMethod(Class klass, String methodName, Class requestClass)
  6. getMethod(Class klass, String name, String name2)
  7. getMethod(Class theClass, String methodName, Class[] paramTypes)
  8. getMethod(Class c, String name, Class... argTypes)
  9. getMethod(Class clazz, String methodName)