Class MethodKey


  • public final class MethodKey
    extends java.lang.Object
    A method key usable by the introspector cache.

    This stores a method (or class) name and parameters.

    This replaces the original key scheme which used to build the key by concatenating the method name and parameters class names as one string with the exception that primitive types were converted to their object class equivalents.

    The key is still based on the same information, it is just wrapped in an object instead. Primitive type classes are converted to they object equivalent to make a key; int foo(int) and int foo(Integer) do generate the same key.

    A key can be constructed either from arguments (array of objects) or from parameters (array of class). Roughly 3x faster than string key to access the map and uses less memory.
    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class Description
      static class  MethodKey.AmbiguousException
      Simple distinguishable exception, used when we run across ambiguous overloading.
    • Field Summary

      Fields 
      Modifier and Type Field Description
      private static java.util.Map<java.lang.Class<?>,​java.lang.Class<?>[]> CONVERTIBLES
      Maps from primitive types to invocation compatible classes.
      private static int HASH
      The hash code constants.
      private int hashCode
      The hash code.
      private static int INCOMPARABLE
      A method/ctor doesn't match a previously compared one.
      private static int LESS_SPECIFIC
      whether a method/ctor is less specific than a previously compared one.
      private java.lang.String method
      The method name.
      private static int MORE_SPECIFIC
      whether a method/ctor is more specific than a previously compared one.
      private static java.lang.Class<?>[] NOARGS
      A marker for empty parameter list.
      private java.lang.Class<?>[] params
      The parameters.
      private static int PRIMITIVE_SIZE
      The initial size of the primitive conversion map.
      private static java.util.Map<java.lang.Class<?>,​java.lang.Class<?>[]> STRICT_CONVERTIBLES
      Maps from primitive types to invocation compatible primitive types.
    • Constructor Summary

      Constructors 
      Constructor Description
      MethodKey​(java.lang.reflect.Executable aMethod)
      Creates a key from a method.
      MethodKey​(java.lang.String aMethod, java.lang.Class<?>[] args)
      Creates a key from a method name and a set of parameters.
      MethodKey​(java.lang.String aMethod, java.lang.Object[] args)
      Creates a key from a method name and a set of arguments.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      private static <T extends java.lang.reflect.Executable>
      MethodKey.AmbiguousException
      ambiguousException​(java.lang.Class<?>[] classes, java.lang.Iterable<T> applicables)
      Creates an ambiguous exception.
      private static java.lang.Class<?>[] asArray​(java.lang.Class<?>... args)
      Helper to build class arrays.
      java.lang.String debugString()
      Outputs a human-readable debug representation of this key.
      boolean equals​(java.lang.Object obj)  
      private static <T extends java.lang.reflect.Executable>
      java.util.Deque<T>
      getApplicables​(T[] methods, java.lang.Class<?>[] classes)
      Returns all methods that are applicable to actual argument types.
      (package private) java.lang.String getMethod()
      Gets this key's method name.
      private <T extends java.lang.reflect.Executable>
      T
      getMostSpecific​(T[] methods)
      Gets the most specific method that is applicable to actual argument types.
      java.lang.reflect.Constructor<?> getMostSpecificConstructor​(java.lang.reflect.Constructor<?>[] methods)
      Gets the most specific constructor that is applicable to the parameters of this key.
      java.lang.reflect.Method getMostSpecificMethod​(java.lang.reflect.Method[] methods)
      Gets the most specific method that is applicable to the parameters of this key.
      (package private) java.lang.Class<?>[] getParameters()
      Gets this key's method parameter classes.
      int hashCode()  
      private static <T extends java.lang.reflect.Executable>
      boolean
      isApplicable​(T method, java.lang.Class<?>[] actuals)
      Returns true if the supplied method is applicable to actual argument types.
      private static boolean isConvertible​(java.lang.Class<?> formal, java.lang.Class<?> actual, boolean possibleVarArg)  
      static boolean isInvocationConvertible​(java.lang.Class<?> formal, java.lang.Class<?> actual, boolean possibleVarArg)
      Determines whether a type represented by a class object is convertible to another type represented by a class object using a method invocation conversion, treating object types of primitive types as if they were primitive types (that is, a Boolean actual parameter type matches boolean primitive formal type).
      private static boolean isInvocationConvertible​(java.lang.Class<?> formal, java.lang.Class<?> type, boolean strict, boolean possibleVarArg)
      Determines parameter-argument invocation compatibility.
      private static boolean isPrimitive​(java.lang.Class<?> c, boolean possibleVarArg)
      Checks whether a parameter class is a primitive.
      private static boolean isStrictConvertible​(java.lang.Class<?> formal, java.lang.Class<?> actual, boolean possibleVarArg)  
      static boolean isStrictInvocationConvertible​(java.lang.Class<?> formal, java.lang.Class<?> actual, boolean possibleVarArg)
      Determines whether a type represented by a class object is convertible to another type represented by a class object using a method invocation conversion, without matching object and primitive types.
      static boolean isVarArgs​(java.lang.reflect.Executable method)
      Checks whether a method accepts a variable number of arguments.
      private static int moreSpecific​(java.lang.Class<?>[] a, java.lang.Class<?>[] c1, java.lang.Class<?>[] c2)
      Determines which method signature (represented by a class array) is more specific.
      (package private) static java.lang.Class<?> primitiveClass​(java.lang.Class<?> parm)
      Converts a primitive type to its corresponding class.
      java.lang.String toString()  
      • Methods inherited from class java.lang.Object

        clone, finalize, getClass, notify, notifyAll, wait, wait, wait
    • Field Detail

      • PRIMITIVE_SIZE

        private static final int PRIMITIVE_SIZE
        The initial size of the primitive conversion map.
        See Also:
        Constant Field Values
      • NOARGS

        private static final java.lang.Class<?>[] NOARGS
        A marker for empty parameter list.
      • CONVERTIBLES

        private static final java.util.Map<java.lang.Class<?>,​java.lang.Class<?>[]> CONVERTIBLES
        Maps from primitive types to invocation compatible classes.

        Considering the key as a parameter type, the value is the list of argument classes that are invocation compatible with the parameter. Example is Long is invocation convertible to long.

      • STRICT_CONVERTIBLES

        private static final java.util.Map<java.lang.Class<?>,​java.lang.Class<?>[]> STRICT_CONVERTIBLES
        Maps from primitive types to invocation compatible primitive types.

        Considering the key as a parameter type, the value is the list of argument types that are invocation compatible with the parameter. Example is 'int' is invocation convertible to 'long'.

      • MORE_SPECIFIC

        private static final int MORE_SPECIFIC
        whether a method/ctor is more specific than a previously compared one.
        See Also:
        Constant Field Values
      • LESS_SPECIFIC

        private static final int LESS_SPECIFIC
        whether a method/ctor is less specific than a previously compared one.
        See Also:
        Constant Field Values
      • INCOMPARABLE

        private static final int INCOMPARABLE
        A method/ctor doesn't match a previously compared one.
        See Also:
        Constant Field Values
      • hashCode

        private final int hashCode
        The hash code.
      • method

        private final java.lang.String method
        The method name.
      • params

        private final java.lang.Class<?>[] params
        The parameters.
    • Constructor Detail

      • MethodKey

        MethodKey​(java.lang.reflect.Executable aMethod)
        Creates a key from a method.
        Parameters:
        aMethod - the method to generate the key from.
      • MethodKey

        MethodKey​(java.lang.String aMethod,
                  java.lang.Class<?>[] args)
        Creates a key from a method name and a set of parameters.
        Parameters:
        aMethod - the method to generate the key from, class name for constructors
        args - the intended method parameters
      • MethodKey

        public MethodKey​(java.lang.String aMethod,
                         java.lang.Object[] args)
        Creates a key from a method name and a set of arguments.
        Parameters:
        aMethod - the method to generate the key from
        args - the intended method arguments
    • Method Detail

      • ambiguousException

        private static <T extends java.lang.reflect.Executable> MethodKey.AmbiguousException ambiguousException​(java.lang.Class<?>[] classes,
                                                                                                                java.lang.Iterable<T> applicables)
        Creates an ambiguous exception.

        This method computes the severity of the ambiguity. The only non-severe case is when there is at least one null argument and at most one applicable method or constructor has a corresponding 'Object' parameter. We thus consider that ambiguity is benign in presence of null arguments but severe in the case where the corresponding parameter is of type Object in more than one applicable overloads.

        Rephrasing:

        • If all arguments are valid instances - no null argument -, ambiguity is severe.
        • If there is at least one null argument, the ambiguity is severe if more than one method has a corresponding parameter of class 'Object'.
        Parameters:
        classes - the argument args
        applicables - the list of applicable methods or constructors
        Returns:
        an ambiguous exception
      • asArray

        private static java.lang.Class<?>[] asArray​(java.lang.Class<?>... args)
        Helper to build class arrays.
        Parameters:
        args - the classes
        Returns:
        the array
      • getApplicables

        private static <T extends java.lang.reflect.Executable> java.util.Deque<T> getApplicables​(T[] methods,
                                                                                                  java.lang.Class<?>[] classes)
        Returns all methods that are applicable to actual argument types.
        Parameters:
        methods - list of all candidate methods
        classes - the actual types of the arguments
        Returns:
        a list that contains only applicable methods (number of formal and actual arguments matches, and argument types are assignable to formal types through a method invocation conversion).
      • isApplicable

        private static <T extends java.lang.reflect.Executable> boolean isApplicable​(T method,
                                                                                     java.lang.Class<?>[] actuals)
        Returns true if the supplied method is applicable to actual argument types.
        Parameters:
        method - method that will be called
        actuals - arguments signature for method
        Returns:
        true if method is applicable to arguments
      • isConvertible

        private static boolean isConvertible​(java.lang.Class<?> formal,
                                             java.lang.Class<?> actual,
                                             boolean possibleVarArg)
        Parameters:
        formal - the formal parameter type to which the actual parameter type should be convertible
        actual - the actual parameter type.
        possibleVarArg - whether we're dealing with the last parameter in the method declaration
        Returns:
        see isMethodInvocationConvertible.
        See Also:
        isInvocationConvertible(Class, Class, boolean)
      • isInvocationConvertible

        public static boolean isInvocationConvertible​(java.lang.Class<?> formal,
                                                      java.lang.Class<?> actual,
                                                      boolean possibleVarArg)
        Determines whether a type represented by a class object is convertible to another type represented by a class object using a method invocation conversion, treating object types of primitive types as if they were primitive types (that is, a Boolean actual parameter type matches boolean primitive formal type). This behavior is because this method is used to determine applicable methods for an actual parameter list, and primitive types are represented by their object duals in reflective method calls.
        Parameters:
        formal - the formal parameter type to which the actual parameter type should be convertible
        actual - the actual parameter type.
        possibleVarArg - whether we're dealing with the last parameter in the method declaration
        Returns:
        true if either formal type is assignable from actual type, or formal is a primitive type and actual is its corresponding object type or an object-type of a primitive type that can be converted to the formal type.
      • isInvocationConvertible

        private static boolean isInvocationConvertible​(java.lang.Class<?> formal,
                                                       java.lang.Class<?> type,
                                                       boolean strict,
                                                       boolean possibleVarArg)
        Determines parameter-argument invocation compatibility.
        Parameters:
        formal - the formal parameter type
        type - the argument type
        strict - whether the check is strict or not
        possibleVarArg - whether we're dealing with the last parameter in the method declaration
        Returns:
        true if compatible, false otherwise
      • isPrimitive

        private static boolean isPrimitive​(java.lang.Class<?> c,
                                           boolean possibleVarArg)
        Checks whether a parameter class is a primitive.
        Parameters:
        c - the parameter class
        possibleVarArg - true if this is the last parameter which can be a primitive array (vararg call)
        Returns:
        true if primitive, false otherwise
      • isStrictConvertible

        private static boolean isStrictConvertible​(java.lang.Class<?> formal,
                                                   java.lang.Class<?> actual,
                                                   boolean possibleVarArg)
        Parameters:
        formal - the formal parameter type to which the actual parameter type should be convertible
        actual - the actual parameter type.
        possibleVarArg - whether we're dealing with the last parameter in the method declaration
        Returns:
        see isStrictMethodInvocationConvertible.
        See Also:
        isStrictInvocationConvertible(Class, Class, boolean)
      • isStrictInvocationConvertible

        public static boolean isStrictInvocationConvertible​(java.lang.Class<?> formal,
                                                            java.lang.Class<?> actual,
                                                            boolean possibleVarArg)
        Determines whether a type represented by a class object is convertible to another type represented by a class object using a method invocation conversion, without matching object and primitive types. This method is used to determine the more specific type when comparing signatures of methods.
        Parameters:
        formal - the formal parameter type to which the actual parameter type should be convertible
        actual - the actual parameter type.
        possibleVarArg - whether not we're dealing with the last parameter in the method declaration
        Returns:
        true if either formal type is assignable from actual type, or formal and actual are both primitive types and actual can be subject to widening conversion to formal.
      • isVarArgs

        public static boolean isVarArgs​(java.lang.reflect.Executable method)
        Checks whether a method accepts a variable number of arguments.

        May be due to a subtle bug in some JVMs, if a varargs method is an override, depending on (perhaps) the class introspection order, the isVarargs flag on the method itself will be false. To circumvent the potential problem, fetch the method with the same signature from the super-classes, - which will be different if override -and get the varargs flag from it.

        Parameters:
        method - the method or constructor to check for varargs
        Returns:
        true if declared varargs, false otherwise
      • moreSpecific

        private static int moreSpecific​(java.lang.Class<?>[] a,
                                        java.lang.Class<?>[] c1,
                                        java.lang.Class<?>[] c2)
        Determines which method signature (represented by a class array) is more specific. This defines a partial ordering on the method signatures.
        Parameters:
        a - the arguments signature
        c1 - first method signature to compare
        c2 - second method signature to compare
        Returns:
        MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if c1 is less specific than c2, INCOMPARABLE if they are incomparable.
      • primitiveClass

        static java.lang.Class<?> primitiveClass​(java.lang.Class<?> parm)
        Converts a primitive type to its corresponding class.

        If the argument type is primitive then we want to convert our primitive type signature to the corresponding Object type so introspection for methods with primitive types will work correctly.

        Parameters:
        parm - a may-be primitive type class
        Returns:
        the equivalent object class
      • debugString

        public java.lang.String debugString()
        Outputs a human-readable debug representation of this key.
        Returns:
        method(p0, p1, ...)
      • equals

        public boolean equals​(java.lang.Object obj)
        Overrides:
        equals in class java.lang.Object
      • getMethod

        java.lang.String getMethod()
        Gets this key's method name.
        Returns:
        the method name
      • getMostSpecific

        private <T extends java.lang.reflect.Executable> T getMostSpecific​(T[] methods)
        Gets the most specific method that is applicable to actual argument types.

        Attempts to find the most specific applicable method using the algorithm described in the JLS section 15.12.2 (with the exception that it can't distinguish a primitive type argument from an object type argument, since in reflection primitive type arguments are represented by their object counterparts, so for an argument of type (say) java.lang.Integer, it will not be able to decide between a method that takes int and a method that takes java.lang.Integer as a parameter.

        This turns out to be a relatively rare case where this is needed - however, functionality like this is needed.

        Parameters:
        methods - a list of methods
        Returns:
        the most specific method.
        Throws:
        MethodKey.AmbiguousException - if there is more than one.
      • getMostSpecificConstructor

        public java.lang.reflect.Constructor<?> getMostSpecificConstructor​(java.lang.reflect.Constructor<?>[] methods)
        Gets the most specific constructor that is applicable to the parameters of this key.
        Parameters:
        methods - a list of constructors.
        Returns:
        the most specific constructor.
        Throws:
        MethodKey.AmbiguousException - if there is more than one.
      • getMostSpecificMethod

        public java.lang.reflect.Method getMostSpecificMethod​(java.lang.reflect.Method[] methods)
        Gets the most specific method that is applicable to the parameters of this key.
        Parameters:
        methods - a list of methods.
        Returns:
        the most specific method.
        Throws:
        MethodKey.AmbiguousException - if there is more than one.
      • getParameters

        java.lang.Class<?>[] getParameters()
        Gets this key's method parameter classes.
        Returns:
        the parameters
      • hashCode

        public int hashCode()
        Overrides:
        hashCode in class java.lang.Object
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object