    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.jexl3.internal.introspection;
    018
    019import java.lang.reflect.Constructor;
    020import java.lang.reflect.Method;
    021
    022import java.util.Arrays;
    023import java.util.HashMap;
    024import java.util.Iterator;
    025import java.util.LinkedList;
    026import java.util.List;
    027import java.util.Map;
    028
    029/**
    030 * A method key usable by the introspector cache.
    031 * <p>
    032 * This stores a method (or class) name and parameters.
    033 * </p>
    034 * <p>
    035 * This replaces the original key scheme which used to build the key
    036 * by concatenating the method name and parameters class names as one string
    037 * with the exception that primitive types were converted to their object class equivalents.
    038 * </p>
    039 * <p>
    040 * The key is still based on the same information, it is just wrapped in an object instead.
    041 * Primitive type classes are converted to they object equivalent to make a key;
    042 * int foo(int) and int foo(Integer) do generate the same key.
    043 * </p>
    044 * A key can be constructed either from arguments (array of objects) or from parameters
    045 * (array of class).
    046 * Roughly 3x faster than string key to access the map and uses less memory.
    047 */
    048public final class MethodKey {
    049    /** The initial size of the primitive conversion map. */
    050    private static final int PRIMITIVE_SIZE = 11;
    051    /** The hash code. */
    052    private final int hashCode;
    053    /** The method name. */
    054    private final String method;
    055    /** The parameters. */
    056    private final Class<?>[] params;
    057    /** A marker for empty parameter list. */
    058    private static final Class<?>[] NOARGS = new Class<?>[0];
    059    /** The hash code constants. */
    060    private static final int HASH = 37;
    061
    062    /**
    063     * Creates a key from a method name and a set of arguments.
    064     * @param aMethod the method to generate the key from
    065     * @param args    the intended method arguments
    066     */
    067    public MethodKey(final String aMethod, final Object[] args) {
    068        // !! keep this in sync with the other ctor (hash code) !!
    069        this.method = aMethod;
    070        int hash = this.method.hashCode();
    071        final int size;
    072        // CSOFF: InnerAssignment
    073        if (args != null && (size = args.length) > 0) {
    074            this.params = new Class<?>[size];
    075            for (int p = 0; p < size; ++p) {
    076                final Object arg = args[p];
    077                // null arguments use void as Void.class as marker
    078                final Class<?> parm = arg == null ? Void.class : arg.getClass();
    079                hash = (HASH * hash) + parm.hashCode();
    080                this.params[p] = parm;
    081            }
    082        } else {
    083            this.params = NOARGS;
    084        }
    085        this.hashCode = hash;
    086    }
    087
    088    /**
    089     * Creates a key from a method.
    090     * @param aMethod the method to generate the key from.
    091     */
    092    MethodKey(final Method aMethod) {
    093        this(aMethod.getName(), aMethod.getParameterTypes());
    094    }
    095
    096    /**
    097     * Creates a key from a constructor.
    098     * @param aCtor the constructor to generate the key from.
    099     */
    100    MethodKey(final Constructor<?> aCtor) {
    101        this(aCtor.getDeclaringClass().getName(), aCtor.getParameterTypes());
    102    }
    103
    104    /**
    105     * Creates a key from a method name and a set of parameters.
    106     * @param aMethod the method to generate the key from
    107     * @param args    the intended method parameters
    108     */
    109    MethodKey(final String aMethod, final Class<?>[] args) {
    110        // !! keep this in sync with the other ctor (hash code) !!
    111        this.method = aMethod.intern();
    112        int hash = this.method.hashCode();
    113        final int size;
    114        // CSOFF: InnerAssignment
    115        if (args != null && (size = args.length) > 0) {
    116            this.params = new Class<?>[size];
    117            for (int p = 0; p < size; ++p) {
    118                final Class<?> parm = primitiveClass(args[p]);
    119                hash = (HASH * hash) + parm.hashCode();
    120                this.params[p] = parm;
    121            }
    122        } else {
    123            this.params = NOARGS;
    124        }
    125        this.hashCode = hash;
    126    }
    127
    128    /**
    129     * Gets this key's method name.
    130     * @return the method name
    131     */
    132    String getMethod() {
    133        return method;
    134    }
    135
    136    /**
    137     * Gets this key's method parameter classes.
    138     * @return the parameters
    139     */
    140    Class<?>[] getParameters() {
    141        return params;
    142    }
    143
    144    @Override
    145    public int hashCode() {
    146        return hashCode;
    147    }
    148
    149    @Override
    150    public boolean equals(final Object obj) {
    151        if (obj instanceof MethodKey) {
    152            final MethodKey key = (MethodKey) obj;
    153            return method.equals(key.method) && Arrays.equals(params, key.params);
    154        }
    155        return false;
    156    }
    157
    158    @Override
    159    public String toString() {
    160        final StringBuilder builder = new StringBuilder(method);
    161        for (final Class<?> c : params) {
    162            builder.append(c == Void.class ? "null" : c.getName());
    163        }
    164        return builder.toString();
    165    }
    166
    167    /**
    168     * Outputs a human readable debug representation of this key.
    169     * @return method(p0, p1, ...)
    170     */
    171    public String debugString() {
    172        final StringBuilder builder = new StringBuilder(method);
    173        builder.append('(');
    174        for (int i = 0; i < params.length; i++) {
    175            if (i > 0) {
    176                builder.append(", ");
    177            }
    178            builder.append(Void.class == params[i] ? "null" : params[i].getName());
    179        }
    180        builder.append(')');
    181        return builder.toString();
    182    }
    183
    184    /**
    185     * Checks whether a method accepts a variable number of arguments.
    186     * <p>May be due to a subtle bug in some JVMs, if a varargs method is an override, depending on (may be) the
    187     * class introspection order, the isVarargs flag on the method itself will be false.
    188     * To circumvent the potential problem, fetch the method with the same signature from the super-classes,
    189     * - which will be different if override  -and get the varargs flag from it.
    190     * @param method the method to check for varargs
    191     * @return true if declared varargs, false otherwise
    192     */
    193    public static boolean isVarArgs(final Method method) {
    194        if (method == null) {
    195            return false;
    196        }
    197        if (method.isVarArgs()) {
    198            return true;
    199        }
    200        // before climbing up the hierarchy, verify that the last parameter is an array
    201        final Class<?>[] ptypes = method.getParameterTypes();
    202        if (ptypes.length == 0 || ptypes[ptypes.length - 1].getComponentType() == null) {
    203            return false;
    204        }
    205        final String mname = method.getName();
    206        // if this is an override, was it actually declared as varargs?
    207        Class<?> clazz = method.getDeclaringClass();
    208        do {
    209            try {
    210                final Method m = clazz.getMethod(mname, ptypes);
    211                if (m.isVarArgs()) {
    212                    return true;
    213                }
    214            } catch (final NoSuchMethodException xignore) {
    215                // this should not happen...
    216            }
    217            clazz = clazz.getSuperclass();
    218        } while(clazz != null);
    219        return false;
    220    }
    221
    222    /**
    223     * Gets the most specific method that is applicable to the parameters of this key.
    224     * @param methods a list of methods.
    225     * @return the most specific method.
    226     * @throws MethodKey.AmbiguousException if there is more than one.
    227     */
    228    public Method getMostSpecificMethod(final Method[] methods) {
    229        return METHODS.getMostSpecific(this, methods);
    230    }
    231
    232    /**
    233     * Gets the most specific constructor that is applicable to the parameters of this key.
    234     * @param methods a list of constructors.
    235     * @return the most specific constructor.
    236     * @throws MethodKey.AmbiguousException if there is more than one.
    237     */
    238    public Constructor<?> getMostSpecificConstructor(final Constructor<?>[] methods) {
    239        return CONSTRUCTORS.getMostSpecific(this, methods);
    240    }
    241
    242    /**
    243     * Determines whether a type represented by a class object is
    244     * convertible to another type represented by a class object using a
    245     * method invocation conversion, treating object types of primitive
    246     * types as if they were primitive types (that is, a Boolean actual
    247     * parameter type matches boolean primitive formal type). This behavior
    248     * is because this method is used to determine applicable methods for
    249     * an actual parameter list, and primitive types are represented by
    250     * their object duals in reflective method calls.
    251     *
    252     * @param formal         the formal parameter type to which the actual
    253     *                       parameter type should be convertible
    254     * @param actual         the actual parameter type.
    255     * @param possibleVarArg whether or not we're dealing with the last parameter
    256     *                       in the method declaration
    257     * @return true if either formal type is assignable from actual type,
    258     *         or formal is a primitive type and actual is its corresponding object
    259     *         type or an object type of a primitive type that can be converted to
    260     *         the formal type.
    261     */
    262    public static boolean isInvocationConvertible(final Class<?> formal,
    263                                                  final Class<?> actual,
    264                                                  final boolean possibleVarArg) {
    265        return isInvocationConvertible(formal, actual, false, possibleVarArg);
    266    }
    267
    268    /**
    269     * Determines whether a type represented by a class object is
    270     * convertible to another type represented by a class object using a
    271     * method invocation conversion, without matching object and primitive
    272     * types. This method is used to determine the more specific type when
    273     * comparing signatures of methods.
    274     *
    275     * @param formal         the formal parameter type to which the actual
    276     *                       parameter type should be convertible
    277     * @param actual         the actual parameter type.
    278     * @param possibleVarArg whether or not we're dealing with the last parameter
    279     *                       in the method declaration
    280     * @return true if either formal type is assignable from actual type,
    281     *         or formal and actual are both primitive types and actual can be
    282     *         subject to widening conversion to formal.
    283     */
    284    public static boolean isStrictInvocationConvertible(final Class<?> formal,
    285                                                        final Class<?> actual,
    286                                                        final boolean possibleVarArg) {
    287        return isInvocationConvertible(formal, actual, true, possibleVarArg);
    288    }
    289
    290    /** Converts a primitive type to its corresponding class.
    291     * <p>
    292     * If the argument type is primitive then we want to convert our
    293     * primitive type signature to the corresponding Object type so
    294     * introspection for methods with primitive types will work
    295     * correctly.
    296     * </p>
    297     * @param parm a may-be primitive type class
    298     * @return the equivalent object class
    299     */
    300    static Class<?> primitiveClass(final Class<?> parm) {
    301        // it was marginally faster to get from the map than call isPrimitive...
    302        //if (!parm.isPrimitive()) return parm;
    303        final Class<?>[] prim = CONVERTIBLES.get(parm);
    304        return prim == null ? parm : prim[0];
    305    }
    306
    307    /**
    308     * Helper to build class arrays.
    309     * @param args the classes
    310     * @return the array
    311     */
    312    private static Class<?>[] asArray(final Class<?>... args) {
    313        return args;
    314    }
    315
    316    /**
    317     * Maps from primitive types to invocation compatible classes.
    318     * <p>Considering the key as a parameter type, the value is the list of argument classes that are invocation
    319     *   compatible with the parameter. Example is Long is invocation convertible to long.
    320     */
    321    private static final Map<Class<?>, Class<?>[]> CONVERTIBLES;
    322    static {
    323        CONVERTIBLES = new HashMap<Class<?>, Class<?>[]>(PRIMITIVE_SIZE);
    324        CONVERTIBLES.put(Boolean.TYPE,
    325                asArray(Boolean.class));
    326        CONVERTIBLES.put(Character.TYPE,
    327                asArray(Character.class));
    328        CONVERTIBLES.put(Byte.TYPE,
    329                asArray(Byte.class));
    330        CONVERTIBLES.put(Short.TYPE,
    331                asArray(Short.class, Byte.class));
    332        CONVERTIBLES.put(Integer.TYPE,
    333                asArray(Integer.class, Short.class, Byte.class));
    334        CONVERTIBLES.put(Long.TYPE,
    335                asArray(Long.class, Integer.class, Short.class, Byte.class));
    336        CONVERTIBLES.put(Float.TYPE,
    337                asArray(Float.class, Long.class, Integer.class, Short.class, Byte.class));
    338        CONVERTIBLES.put(Double.TYPE,
    339            asArray(Double.class, Float.class, Long.class, Integer.class, Short.class, Byte.class));
    340    }
    341
    342    /**
    343     * Maps from primitive types to invocation compatible primitive types.
    344     * <p>Considering the key as a parameter type, the value is the list of argument types that are invocation
    345     * compatible with the parameter. Example is 'int' is invocation convertible to 'long'.
    346     */
    347    private static final Map<Class<?>, Class<?>[]> STRICT_CONVERTIBLES;
    348    static {
    349        STRICT_CONVERTIBLES = new HashMap<Class<?>, Class<?>[]>(PRIMITIVE_SIZE);
    350        STRICT_CONVERTIBLES.put(Short.TYPE,
    351                asArray(Byte.TYPE));
    352        STRICT_CONVERTIBLES.put(Integer.TYPE,
    353                asArray(Short.TYPE, Byte.TYPE));
    354        STRICT_CONVERTIBLES.put(Long.TYPE,
    355                asArray(Integer.TYPE, Short.TYPE, Byte.TYPE));
    356        STRICT_CONVERTIBLES.put(Float.TYPE,
    357                asArray(Long.TYPE, Integer.TYPE, Short.TYPE, Byte.TYPE));
    358        STRICT_CONVERTIBLES.put(Double.TYPE,
    359                asArray(Float.TYPE, Long.TYPE, Integer.TYPE, Short.TYPE, Byte.TYPE));
    360    }
    361
    362    /**
    363     * Determines parameter-argument invocation compatibility.
    364     *
    365     * @param formal         the formal parameter type
    366     * @param actual         the argument type
    367     * @param strict         whether the check is strict or not
    368     * @param possibleVarArg whether or not we're dealing with the last parameter in the method declaration
    369     * @return true if compatible, false otherwise
    370     */
    371    private static boolean isInvocationConvertible(
    372            final Class<?> formal, Class<?> actual, final boolean strict, final boolean possibleVarArg) {
    373        /* if it's a null, it means the arg was null */
    374        if (actual == null && !formal.isPrimitive()) {
    375            return true;
    376        }
    377        /* system asssignable, both sides must be array or not */
    378        if (actual != null && formal.isAssignableFrom(actual) && actual.isArray() == formal.isArray()) {
    379            return true;
    380        }
    381        /* catch all... */
    382        if (!strict && formal == Object.class) {
    383            return true;
    384        }
    385        /* Primitive conversion check. */
    386        if (formal.isPrimitive()) {
    387            final Class<?>[] clist = strict ? STRICT_CONVERTIBLES.get(formal) : CONVERTIBLES.get(formal);
    388            if (clist != null) {
    389                for (final Class<?> aClass : clist) {
    390                    if (actual == aClass) {
    391                        return true;
    392                    }
    393                }
    394            }
    395            return false;
    396        }
    397        /* Check for vararg conversion. */
    398        if (possibleVarArg && formal.isArray()) {
    399            if (actual != null && actual.isArray()) {
    400                actual = actual.getComponentType();
    401            }
    402            return isInvocationConvertible(formal.getComponentType(), actual, strict, false);
    403        }
    404        return false;
    405    }
    406
    407    /**
    408     * whether a method/ctor is more specific than a previously compared one.
    409     */
    410    private static final int MORE_SPECIFIC = 0;
    411    /**
    412     * whether a method/ctor is less specific than a previously compared one.
    413     */
    414    private static final int LESS_SPECIFIC = 1;
    415    /**
    416     * A method/ctor doesn't match a previously compared one.
    417     */
    418    private static final int INCOMPARABLE = 2;
    419
    420    /**
    421     * Simple distinguishable exception, used when
    422     * we run across ambiguous overloading. Caught
    423     * by the introspector.
    424     */
    425    public static class AmbiguousException extends RuntimeException {
    426        /** Version Id for serializable. */
    427        private static final long serialVersionUID = -201801091655L;
    428        /** Whether this exception should be considered severe. */
    429        private final boolean severe;
    430
    431        /**
    432         * A severe or not ambiguous exception.
    433         * @param flag logging flag
    434         */
    435        AmbiguousException(final boolean flag) {
    436            this.severe = flag;
    437        }
    438
    439        /**
    440         * Whether this exception is considered severe or benign.
    441         * <p>Note that this is meant in the context of an ambiguous exception; benign cases can only be triggered
    442         * by null arguments often related to runtime problems (not simply on overload signatures).
    443         * @return true if severe, false if benign.
    444         */
    445        public boolean isSevere() {
    446            return severe;
    447        }
    448    }
    449
    450    /**
    451     * Utility for parameters matching.
    452     * @param <T> Method or Constructor
    453     */
    454    private abstract static class Parameters<T> {
    455        /**
    456         * Extract the parameter types from its applicable argument.
    457         * @param app a method or constructor
    458         * @return the parameters
    459         */
    460        protected abstract Class<?>[] getParameterTypes(T app);
    461
    462        /**
    463         * Whether a constructor or method handles varargs.
    464         * @param app the constructor or method
    465         * @return true if varargs, false otherwise
    466         */
    467        protected abstract boolean isVarArgs(T app);
    468
    469        // CSOFF: RedundantThrows
    470        /**
    471         * Gets the most specific method that is applicable to actual argument types.<p>
    472         * Attempts to find the most specific applicable method using the
    473         * algorithm described in the JLS section 15.12.2 (with the exception that it can't
    474         * distinguish a primitive type argument from an object type argument, since in reflection
    475         * primitive type arguments are represented by their object counterparts, so for an argument of
    476         * type (say) java.lang.Integer, it will not be able to decide between a method that takes int and a
    477         * method that takes java.lang.Integer as a parameter.
    478         * </p>
    479         * <p>
    480         * This turns out to be a relatively rare case where this is needed - however, functionality
    481         * like this is needed.
    482         * </p>
    483         *
    484         * @param key a method key, esp its parameters
    485         * @param methods a list of methods
    486         * @return the most specific method.
    487         * @throws MethodKey.AmbiguousException if there is more than one.
    488         */
    489        private T getMostSpecific(final MethodKey key, final T[] methods) {
    490            final Class<?>[] args = key.params;
    491            final LinkedList<T> applicables = getApplicables(methods, args);
    492            if (applicables.isEmpty()) {
    493                return null;
    494            }
    495
    496            if (applicables.size() == 1) {
    497                return applicables.getFirst();
    498            }
    499
    500            /*
    501             * This list will contain the maximally specific methods. Hopefully at
    502             * the end of the below loop, the list will contain exactly one method,
    503             * (the most specific method) otherwise we have ambiguity.
    504             */
    505            final LinkedList<T> maximals = new LinkedList<T>();
    506            for (final T app : applicables) {
    507                final Class<?>[] parms = getParameterTypes(app);
    508                boolean lessSpecific = false;
    509                final Iterator<T> maximal = maximals.iterator();
    510                while(!lessSpecific && maximal.hasNext()) {
    511                    final T max = maximal.next();
    512                    switch (moreSpecific(args, parms, getParameterTypes(max))) {
    513                        case MORE_SPECIFIC:
    514                            /*
    515                            * This method is more specific than the previously
    516                            * known maximally specific, so remove the old maximum.
    517                            */
    518                            maximal.remove();
    519                            break;
    520
    521                        case LESS_SPECIFIC:
    522                            /*
    523                            * This method is less specific than some of the
    524                            * currently known maximally specific methods, so we
    525                            * won't add it into the set of maximally specific
    526                            * methods
    527                            */
    528
    529                            lessSpecific = true;
    530                            break;
    531                        default:
    532                            // nothing do do
    533                    }
    534                }
    535
    536                if (!lessSpecific) {
    537                    maximals.addLast(app);
    538                }
    539            }
    540            // if we have more than one maximally specific method, this call is ambiguous...
    541            if (maximals.size() > 1) {
    542                throw ambiguousException(args, applicables);
    543            }
    544            return maximals.getFirst();
    545        } // CSON: RedundantThrows
    546
    547        /**
    548         * Creates an ambiguous exception.
    549         * <p>
    550         * This method computes the severity of the ambiguity. The only <em>non-severe</em> case is when there is
    551         * at least one null argument and at most one applicable method or constructor has a corresponding 'Object'
    552         * parameter.
    553         * We thus consider that ambiguity is benign in presence of null arguments but in the case where
    554         * the corresponding parameter is of type Object in more than one applicable overloads.
    555         * <p>
    556         * Rephrasing:
    557         * <ul>
    558         *  <li>If all arguments are valid instances - no null argument -, ambiguity is severe.</li>
    559         *  <li>If there is at least one null argument, the ambiguity is severe if more than one method has a
    560         *  corresponding parameter of class 'Object'.</li>
    561         * </ul>
    562         *
    563         * @param classes the argument args
    564         * @param applicables the list of applicable methods or constructors
    565         * @return an ambiguous exception
    566         */
    567        private AmbiguousException ambiguousException (final Class<?>[] classes, final List<T> applicables) {
    568            boolean severe = false;
    569            int instanceArgCount = 0; // count the number of valid instances, aka not null
    570            for(int c = 0; c < classes.length; ++c) {
    571                final Class<?> argClazz = classes[c];
    572                if (Void.class.equals(argClazz)) {
    573                    // count the number of methods for which the current arg maps to an Object parameter
    574                    int objectParmCount = 0;
    575                    for (final T app : applicables) {
    576                        final Class<?>[] parmClasses = getParameterTypes(app);
    577                        final Class<?> parmClass =  parmClasses[c];
    578                        if (Object.class.equals(parmClass) && (objectParmCount++ == 2)) {
    579                            severe = true;
    580                            break;
    581                        }
    582                    }
    583                } else {
    584                    instanceArgCount += 1;
    585                }
    586            }
    587            return new AmbiguousException(severe || instanceArgCount == classes.length);
    588        }
    589
    590        /**
    591         * Determines which method signature (represented by a class array) is more
    592         * specific. This defines a partial ordering on the method signatures.
    593         *
    594         * @param a the arguments signature
    595         * @param c1 first method signature to compare
    596         * @param c2 second method signature to compare
    597         * @return MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if
    598         *         c1 is less specific than c2, INCOMPARABLE if they are incomparable.
    599         */
    600         private int moreSpecific(final Class<?>[] a, final Class<?>[] c1, final Class<?>[] c2) {
    601            // compare lengths to handle comparisons where the size of the arrays
    602            // doesn't match, but the methods are both applicable due to the fact
    603            // that one is a varargs method
    604            if (c1.length > a.length) {
    605                return LESS_SPECIFIC;
    606            }
    607            if (c2.length > a.length) {
    608                return MORE_SPECIFIC;
    609            }
    610            if (c1.length > c2.length) {
    611                return MORE_SPECIFIC;
    612            }
    613            if (c2.length > c1.length) {
    614                return LESS_SPECIFIC;
    615            }
    616            // same length, keep ultimate param offset for vararg checks
    617            final int length = c1.length;
    618            final int ultimate = c1.length - 1;
    619
    620             // ok, move on and compare those of equal lengths
    621             for (int i = 0; i < length; ++i) {
    622                 if (c1[i] != c2[i]) {
    623                     final boolean last = (i == ultimate);
    624                     // argument is null, prefer an Object param
    625                     if (a[i] == Void.class) {
    626                         if (c1[i] == Object.class && c2[i] != Object.class) {
    627                             return MORE_SPECIFIC;
    628                         }
    629                         if (c1[i] != Object.class && c2[i] == Object.class) {
    630                             return LESS_SPECIFIC;
    631                         }
    632                     }
    633                     // prefer primitive on non null arg, non primitive otherwise
    634                     boolean c1s = isPrimitive(c1[i], last);
    635                     boolean c2s = isPrimitive(c2[i], last);
    636                     if (c1s != c2s) {
    637                        return (c1s == (a[i] != Void.class))? MORE_SPECIFIC : LESS_SPECIFIC;
    638                     }
    639                     // if c2 can be converted to c1 but not the opposite,
    640                     // c1 is more specific than c2
    641                     c1s = isStrictConvertible(c2[i], c1[i], last);
    642                     c2s = isStrictConvertible(c1[i], c2[i], last);
    643                     if (c1s != c2s) {
    644                         return c1s ? MORE_SPECIFIC : LESS_SPECIFIC;
    645                     }
    646                 }
    647             }
    648            // Incomparable due to non-related arguments (i.e.foo(Runnable) vs. foo(Serializable))
    649            return INCOMPARABLE;
    650        }
    651
    652        /**
    653         * Checks whether a parameter class is a primitive.
    654         * @param c              the parameter class
    655         * @param possibleVarArg true if this is the last parameter which can be a primitive array (vararg call)
    656         * @return true if primitive, false otherwise
    657         */
    658        private boolean isPrimitive(final Class<?> c, final boolean possibleVarArg) {
    659            if (c != null) {
    660                if (c.isPrimitive()) {
    661                    return true;
    662                }
    663                if (possibleVarArg) {
    664                    final Class<?> t = c.getComponentType();
    665                    return t != null && t.isPrimitive();
    666                }
    667            }
    668            return false;
    669        }
    670
    671        /**
    672         * Returns all methods that are applicable to actual argument types.
    673         *
    674         * @param methods list of all candidate methods
    675         * @param classes the actual types of the arguments
    676         * @return a list that contains only applicable methods (number of
    677         *         formal and actual arguments matches, and argument types are assignable
    678         *         to formal types through a method invocation conversion).
    679         */
    680        private LinkedList<T> getApplicables(final T[] methods, final Class<?>[] classes) {
    681            final LinkedList<T> list = new LinkedList<T>();
    682            for (final T method : methods) {
    683                if (isApplicable(method, classes)) {
    684                    list.add(method);
    685                }
    686            }
    687            return list;
    688        }
    689
    690        /**
    691         * Returns true if the supplied method is applicable to actual
    692         * argument types.
    693         *
    694         * @param method  method that will be called
    695         * @param actuals arguments signature for method
    696         * @return true if method is applicable to arguments
    697         */
    698        private boolean isApplicable(final T method, final Class<?>[] actuals) {
    699            final Class<?>[] formals = getParameterTypes(method);
    700            // if same number or args or
    701            // there's just one more methodArg than class arg
    702            // and the last methodArg is an array, then treat it as a vararg
    703            if (formals.length == actuals.length) {
    704                // this will properly match when the last methodArg
    705                // is an array/varargs and the last class is the type of array
    706                // (e.g. String when the method is expecting String...)
    707                for (int i = 0; i < actuals.length; ++i) {
    708                    if (!isConvertible(formals[i], actuals[i], false)) {
    709                        // if we're on the last arg and the method expects an array
    710                        if (i == actuals.length - 1 && formals[i].isArray()) {
    711                            // check to see if the last arg is convertible
    712                            // to the array's component type
    713                            return isConvertible(formals[i], actuals[i], true);
    714                        }
    715                        return false;
    716                    }
    717                }
    718                return true;
    719            }
    720
    721            // number of formal and actual differ, method must be vararg
    722            if (!isVarArgs(method)) {
    723                return false;
    724            }
    725
    726            // less arguments than method parameters: vararg is null
    727            if (formals.length > actuals.length) {
    728                // only one parameter, the last (ie vararg) can be missing
    729                if (formals.length - actuals.length > 1) {
    730                    return false;
    731                }
    732                // check that all present args match up to the method parms
    733                for (int i = 0; i < actuals.length; ++i) {
    734                    if (!isConvertible(formals[i], actuals[i], false)) {
    735                        return false;
    736                    }
    737                }
    738                return true;
    739            }
    740
    741            // more arguments given than the method accepts; check for varargs
    742            if (formals.length > 0 && actuals.length > 0) {
    743                // check that they all match up to the last method arg
    744                for (int i = 0; i < formals.length - 1; ++i) {
    745                    if (!isConvertible(formals[i], actuals[i], false)) {
    746                        return false;
    747                    }
    748                }
    749                // check that all remaining arguments are convertible to the vararg type
    750                // (last parm is an array since method is vararg)
    751                final Class<?> vararg = formals[formals.length - 1].getComponentType();
    752                for (int i = formals.length - 1; i < actuals.length; ++i) {
    753                    if (!isConvertible(vararg, actuals[i], false)) {
    754                        return false;
    755                    }
    756                }
    757                return true;
    758            }
    759            // no match
    760            return false;
    761        }
    762
    763        /**
    764         * @see #isInvocationConvertible(Class, Class, boolean)
    765         * @param formal         the formal parameter type to which the actual
    766         *                       parameter type should be convertible
    767         * @param actual         the actual parameter type.
    768         * @param possibleVarArg whether or not we're dealing with the last parameter
    769         *                       in the method declaration
    770         * @return see isMethodInvocationConvertible.
    771         */
    772        private boolean isConvertible(final Class<?> formal, final Class<?> actual, final boolean possibleVarArg) {
    773            // if we see Void.class, the argument was null
    774            return isInvocationConvertible(formal, actual.equals(Void.class) ? null : actual, possibleVarArg);
    775        }
    776
    777        /**
    778         * @see #isStrictInvocationConvertible(Class, Class, boolean)
    779         * @param formal         the formal parameter type to which the actual
    780         *                       parameter type should be convertible
    781         * @param actual         the actual parameter type.
    782         * @param possibleVarArg whether or not we're dealing with the last parameter
    783         *                       in the method declaration
    784         * @return see isStrictMethodInvocationConvertible.
    785         */
    786        private boolean isStrictConvertible(final Class<?> formal, final Class<?> actual,
    787                final boolean possibleVarArg) {
    788            // if we see Void.class, the argument was null
    789            return isStrictInvocationConvertible(formal, actual.equals(Void.class) ? null : actual, possibleVarArg);
    790        }
    791    }
    792
    793    /**
    794     * The parameter matching service for methods.
    795     */
    796    private static final Parameters<Method> METHODS = new Parameters<Method>() {
    797        @Override
    798        protected Class<?>[] getParameterTypes(final Method app) {
    799            return app.getParameterTypes();
    800        }
    801
    802        @Override
    803        public boolean isVarArgs(final Method app) {
    804            return MethodKey.isVarArgs(app);
    805        }
    806
    807    };
    808
    809    /**
    810     * The parameter matching service for constructors.
    811     */
    812    private static final Parameters<Constructor<?>> CONSTRUCTORS = new Parameters<Constructor<?>>() {
    813        @Override
    814        protected Class<?>[] getParameterTypes(final Constructor<?> app) {
    815            return app.getParameterTypes();
    816        }
    817
    818        @Override
    819        public boolean isVarArgs(final Constructor<?> app) {
    820            return app.isVarArgs();
    821        }
    822
    823    };
    824}