@SuppressWarnings("null")
    private static Wrapper findWrapper(Class<?> clazz, List<Wrapper> wrappers,
            String name, Class<?>[] paramTypes, Object[] paramValues) {

        Map<Wrapper,MatchResult> candidates = new HashMap<>();

        int paramCount;
        if (paramTypes == null) {
            paramCount = 0;
        } else {
            paramCount = paramTypes.length;
        }

        for (Wrapper w : wrappers) {
            Class<?>[] mParamTypes = w.getParameterTypes();
            int mParamCount;
            if (mParamTypes == null) {
                mParamCount = 0;
            } else {
                mParamCount = mParamTypes.length;
            }

            // Check the number of parameters
            if (!(paramCount == mParamCount ||
                    (w.isVarArgs() && paramCount >= mParamCount))) {
                // Method has wrong number of parameters
                continue;
            }

            // Check the parameters match
            int exactMatch = 0;
            int assignableMatch = 0;
            int coercibleMatch = 0;
            boolean noMatch = false;
            for (int i = 0; i < mParamCount; i++) {
                // Can't be null
                if (mParamTypes[i].equals(paramTypes[i])) {
                    exactMatch++;
                } else if (i == (mParamCount - 1) && w.isVarArgs()) {
                    Class<?> varType = mParamTypes[i].getComponentType();
                    for (int j = i; j < paramCount; j++) {
                        if (isAssignableFrom(paramTypes[j], varType)) {
                            assignableMatch++;
                        } else {
                            if (paramValues == null) {
                                noMatch = true;
                                break;
                            } else {
                                if (isCoercibleFrom(paramValues[j], varType)) {
                                    coercibleMatch++;
                                } else {
                                    noMatch = true;
                                    break;
                                }
                            }
                        }
                        // Don't treat a varArgs match as an exact match, it can
                        // lead to a varArgs method matching when the result
                        // should be ambiguous
                    }
                } else if (isAssignableFrom(paramTypes[i], mParamTypes[i])) {
                    assignableMatch++;
                } else {
                    if (paramValues == null) {
                        noMatch = true;
                        break;
                    } else {
                        if (isCoercibleFrom(paramValues[i], mParamTypes[i])) {
                            coercibleMatch++;
                        } else {
                            noMatch = true;
                            break;
                        }
                    }
                }
            }
            if (noMatch) {
                continue;
            }

            // If a method is found where every parameter matches exactly,
            // return it
            if (exactMatch == paramCount) {
                return w;
            }

            candidates.put(w, new MatchResult(
                    exactMatch, assignableMatch, coercibleMatch, w.isBridge()));
        }

        // Look for the method that has the highest number of parameters where
        // the type matches exactly
        MatchResult bestMatch = new MatchResult(0, 0, 0, false);
        Wrapper match = null;
        boolean multiple = false;
        for (Map.Entry<Wrapper, MatchResult> entry : candidates.entrySet()) {
            int cmp = entry.getValue().compareTo(bestMatch);
            if (cmp > 0 || match == null) {
                bestMatch = entry.getValue();
                match = entry.getKey();
                multiple = false;
            } else if (cmp == 0) {
                multiple = true;
            }
        }
        if (multiple) {
            if (bestMatch.getExact() == paramCount - 1) {
                // Only one parameter is not an exact match - try using the
                // super class
                match = resolveAmbiguousWrapper(candidates.keySet(), paramTypes);
            } else {
                match = null;
            }

            if (match == null) {
                // If multiple methods have the same matching number of parameters
                // the match is ambiguous so throw an exception
                throw new MethodNotFoundException(message(
                        null, "util.method.ambiguous", clazz, name,
                        paramString(paramTypes)));
                }
        }

        // Handle case where no match at all was found
        if (match == null) {
            throw new MethodNotFoundException(message(
                        null, "util.method.notfound", clazz, name,
                        paramString(paramTypes)));
        }

        return match;
    }
@ SuppressWarnings ( "null" ) private static Wrapper findWrapper ( Class < ? > clazz , List < Wrapper > wrappers , String name , Class < ? > [ ] paramTypes , Object [ ] paramValues ) { Map < Wrapper , MatchResult > candidates = new HashMap < > ( ) ; int paramCount ; if ( paramTypes == null ) { paramCount = 0 ; } else { paramCount = paramTypes . length ; } for ( Wrapper w : wrappers ) { Class < ? > [ ] mParamTypes = w . getParameterTypes ( ) ; int mParamCount ; if ( mParamTypes == null ) { mParamCount = 0 ; } else { mParamCount = mParamTypes . length ; } if ( ! ( paramCount == mParamCount || ( w . isVarArgs ( ) && paramCount >= mParamCount ) ) ) { continue ; } int exactMatch = 0 ; int assignableMatch = 0 ; int coercibleMatch = 0 ; boolean noMatch = false ; for ( int i = 0 ; i < mParamCount ; i ++ ) { if ( mParamTypes [ i ] . equals ( paramTypes [ i ] ) ) { exactMatch ++ ; } else if ( i == ( mParamCount - 1 ) && w . isVarArgs ( ) ) { Class < ? > varType = mParamTypes [ i ] . getComponentType ( ) ; for ( int j = i ; j < paramCount ; j ++ ) { if ( isAssignableFrom ( paramTypes [ j ] , varType ) ) { assignableMatch ++ ; } else { if ( paramValues == null ) { noMatch = true ; break ; } else { if ( isCoercibleFrom ( paramValues [ j ] , varType ) ) { coercibleMatch ++ ; } else { noMatch = true ; break ; } } } } } else if ( isAssignableFrom ( paramTypes [ i ] , mParamTypes [ i ] ) ) { assignableMatch ++ ; } else { if ( paramValues == null ) { noMatch = true ; break ; } else { if ( isCoercibleFrom ( paramValues [ i ] , mParamTypes [ i ] ) ) { coercibleMatch ++ ; } else { noMatch = true ; break ; } } } } if ( noMatch ) { continue ; } if ( exactMatch == paramCount ) { return w ; } candidates . put ( w , new MatchResult ( exactMatch , assignableMatch , coercibleMatch , w . isBridge ( ) ) ) ; } MatchResult bestMatch = new MatchResult ( 0 , 0 , 0 , false ) ; Wrapper match = null ; boolean multiple = false ; for ( Map . Entry < Wrapper , MatchResult > entry : candidates . entrySet ( ) ) { int cmp = entry . getValue ( ) . compareTo ( bestMatch ) ; if ( cmp > 0 || match == null ) { bestMatch = entry . getValue ( ) ; match = entry . getKey ( ) ; multiple = false ; } else if ( cmp == 0 ) { multiple = true ; } } if ( multiple ) { if ( bestMatch . getExact ( ) == paramCount - 1 ) { match = resolveAmbiguousWrapper ( candidates . keySet ( ) , paramTypes ) ; } else { match = null ; } if ( match == null ) { throw new MethodNotFoundException ( message ( null , "util.method.ambiguous" , clazz , name , paramString ( paramTypes ) ) ) ; } } if ( match == null ) { throw new MethodNotFoundException ( message ( null , "util.method.notfound" , clazz , name , paramString ( paramTypes ) ) ) ; } return match ; }
/*
This method duplicates code in org.apache.el.util.ReflectionUtil. When
making changes keep the code in sync.