Class ReflectionSupport


  • public class ReflectionSupport
    extends Object
    This class provides static helper methods to use reflection to check for and invoke methods on objects. It is intended for use in test cases, and makes it easier to write test cases that compile successfully but fail at run-time if the class under test fails to provide required methods (or provides them with the wrong signature). For Web-CAT users, this makes it possible to get partial scores, even when some methods are not even provided in the class under test.

    Consider a situation where you are writing a test case that invokes the doIt() method on a given object. You might do it like this:

      MyType result = receiver.doIt(param1, param2);  // returns a value
      // ...
      receiver.doSomethingElse();  // a void method with no parameters
      

    The first line passes two parameters to doIt() and stores the return value in a local variable called result. All this would be fine if the class under test actually provides a method called doIt() with the appropriate signature and return type. Otherwise, you would get a compile-time error. But on Web-CAT a compilation error in a test suite would give a resulting score of zero--no successful compilation, no partial credit. The story is similar with the second line, which simply calls a void method on the class under test.

    What if, instead, you wanted to write test cases that checked for specific methods, and either succeeded or failed depending on whether the method was present? You can use the methods in this class to write such test cases. So instead of writing the call above, you could do this:

      // At the top of your test class
      import static net.sf.webcat.ReflectionSupport.*;
    
      // ...
    
      // For a method that returns a result:
      MyType result = invoke(receiver, MyType.class, "doIt", param1, param2);
    
      // Or for a void method:
      invoke(receiver, "doSomethingElse");
      

    The syntax is simple and straight forward. The overloaded invoke method can be used on functions (methods that return a value) or procedures (void methods that return nothing). For methods that return a value, you specify the type of the return value as the second parameter. If you omit the return type, then it is assumed to be "void". You specify the name of the method as a string, and then a variable length set of arguments.

    If you are calling a method that is returning a primitive type, be sure to use the corresponding wrapper class as the expected return value:

      // Instead of boolean answer = receiver.equals(anotherObject);
      Boolean answer = invoke(receiver, Boolean.class, "equals", anotherObject);
    
      // Or in an assert, using auto-unboxing:
      assertTrue(invoke(receiver, Boolean.class, "equals", anotherObject));
      

    Any errors that occur during reflection, such as failing to find the required method, failing to find a method with the required signature, finding a method that is not public, etc., are converted into appropriate test case errors with meaningful diagnostic hints for the student. Any exceptions are wrapped in a RuntimeException and need not be explicitly caught by the caller (they will turn into test case failures as well).

    • Method Detail

      • getClassForName

        public static Class<?> getClassForName​(String className)
        Dynamically look up a class by name, with appropriate hints if the class cannot be found.
        Parameters:
        className - The type of object to create
        Returns:
        The corresponding Class object
      • getMatchingConstructor

        public static Constructor<?> getMatchingConstructor​(Class<?> c,
                                                            Class<?>... params)
        Look up a constructor by parameter profile, finding the constructor that will accept the given list of parameters (not requiring an exact match on parameter types). It turns any errors into test case failures with appropriate hint messages. Assumes the intended constructor should be public, and fails with an appropriate hint if it is not. Note that this method does not handle variable argument lists in the target constructor for which it is searching.
        Parameters:
        c - The type of object to create
        params - The constructor's parameter profile
        Returns:
        The corresponding Constructor object
      • getMatchingConstructor

        public static Constructor<?> getMatchingConstructor​(Class<?> c,
                                                            int mandatoryModifiers,
                                                            int disallowedModifiers,
                                                            Class<?>... params)
        Look up a constructor by parameter profile, finding the constructor that will accept the given list of parameters (not requiring an exact match on parameter types). It turns any errors into test case failures with appropriate hint messages. Assumes the intended constructor should be public, and fails with an appropriate hint if it is not. Note that this method does not handle variable argument lists in the target constructor for which it is searching.
        Parameters:
        c - The type of object to create
        mandatoryModifiers - specifies the expected modifier (any bit pattern contained in java.lang.reflect.Modifiers.constructorModifiers() ). 0 will switch off checking of mandatory modifiers.
        disallowedModifiers - specifies the set of disallowed modifiers (any bit pattern contained in java.lang.reflect.Modifiers.constructorModifiers() ). 0 will switch off checking of disallowed modifiers.
        params - The constructor's parameter profile
        Returns:
        The corresponding Constructor object
      • create

        public static <T> T create​(Constructor<T> constructor,
                                   Object... params)
        Just like Constructor.newInstance(Object...), but converts any thrown exceptions into RuntimeExceptions. Note that this method allows to invoke constructors that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Type Parameters:
        T - The generic parameter T is deduced from the provided constructor
        Parameters:
        constructor - The constructor to invoke
        params - The parameters to pass to the constructor
        Returns:
        The newly created object
      • create

        public static <T> T create​(Class<T> returnType,
                                   Object... params)
        Dynamically look up and invoke a class constructor for the target class, with appropriate hints if any failures happen along the way. Note that this method allows to invoke constructors that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Type Parameters:
        T - The generic parameter T is deduced from the returnType
        Parameters:
        returnType - The type of object to create.
        params - The parameters to pass to the constructor
        Returns:
        The newly created object
      • create

        public static Object create​(String className,
                                    Object... params)
        Dynamically look up and invoke a class constructor for the target class, with appropriate hints if any failures happen along the way. Note that this method allows to invoke constructors that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Parameters:
        className - The type of object to create
        params - The parameters to pass to the constructor
        Returns:
        The newly created object
      • createEx

        public static Object createEx​(Constructor<?> constructor,
                                      Object... params)
                               throws Exception
        Just like create(Constructor, Object...), but unwraps any InvocationTargetExceptions and throws the true cause. This version is provided when you want to write test cases where you are intending to check for Exceptions as expected results. Note that this method allows to invoke constructors that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Parameters:
        constructor - The constructor to invoke
        params - The parameters to pass to the constructor
        Returns:
        The newly created object
        Throws:
        Exception - if the underlying method throws one
      • createEx

        public static <T> T createEx​(Class<T> returnType,
                                     Object... params)
                              throws Exception
        Just like create(Class, Object...), but unwraps any InvocationTargetExceptions and throws the true cause. This version is provided when you want to write test cases where you are intending to check for Exceptions as expected results. Note that this method allows to invoke constructors that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Type Parameters:
        T - The generic parameter T is deduced from the returnType
        Parameters:
        returnType - The type of object to create.
        params - The parameters to pass to the constructor
        Returns:
        The newly created object
        Throws:
        Exception - if the underlying method throws one
      • createEx

        public static Object createEx​(String className,
                                      Object... params)
                               throws Exception
        Just like create(String, Object...), but unwraps any InvocationTargetExceptions and throws the true cause. This version is provided when you want to write test cases where you are intending to check for Exceptions as expected results. Note that this method allows to invoke constructors that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Parameters:
        className - The type of object to create
        params - The parameters to pass to the constructor
        Returns:
        The newly created object
        Throws:
        Exception - if the underlying method throws one
      • getMethod

        public static Method getMethod​(Class<?> c,
                                       String name,
                                       Class<?>... params)
        Look up a method by name and parameter profile, turning any errors into test case failures with appropriate hint messages. Only looks up methods that are declared in the specified class, not inherited methods. Assumes the intended method should be public, and fails with an appropriate hint if it is not.
        Parameters:
        c - The type of the receiver
        name - The method name
        params - The method's parameter profile
        Returns:
        The corresponding Method object
      • getMatchingMethod

        public static Method getMatchingMethod​(Class<?> c,
                                               String name,
                                               Class<?>... params)
        Look up a method by name and parameter profile, finding the method that will accept the given list of parameters (not requiring an exact match on parameter types). It turns any errors into test case failures with appropriate hint messages. Only looks up methods that are declared in the specified class, not inherited methods. Assumes the intended method should be public, and fails with an appropriate hint if it is not. Note that this method does not handle variable argument lists in the target method for which it is searching.
        Parameters:
        c - The type of the receiver
        name - The method name
        params - The method's parameter profile
        Returns:
        The corresponding Method object
      • getMatchingMethod

        public static Method getMatchingMethod​(Class<?> c,
                                               String name,
                                               int mandatoryModifiers,
                                               int disallowedModifiers,
                                               Class<?>... params)
        Look up a method by name and parameter profile, finding the method that will accept the given list of parameters (not requiring an exact match on parameter types). It turns any errors into test case failures with appropriate hint messages. Only looks up methods that are declared in the specified class, not inherited methods. Assumes the intended method should be public, and fails with an appropriate hint if it is not. Note that this method does not handle variable argument lists in the target method for which it is searching.
        Parameters:
        c - The type of the receiver
        name - The method name
        mandatoryModifiers - specifies the expected modifier (any bit pattern contained in java.lang.reflect.Modifiers.methodModifiers() ). 0 will switch off checking of mandatory modifiers.
        disallowedModifiers - specifies the set of disallowed modifiers (any bit pattern contained in java.lang.reflect.Modifiers.methodModifiers() ). 0 will switch off checking of disallowed modifiers.
        params - The method's parameter profile
        Returns:
        The corresponding Method object
      • invoke

        public static <T> T invoke​(Object receiver,
                                   Class<T> returnType,
                                   String methodName,
                                   Object... params)
        Dynamically look up and invoke a method on a target object, with appropriate hints if any failures happen along the way. Note that this method allows to invoke methods that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Type Parameters:
        T - The generic parameter T is deduced from the returnType
        Parameters:
        receiver - The object to invoke the method on
        returnType - The expected type of the method's return value. Use null (or void.class) if the method that is looked up is a void method.
        methodName - The name of the method to invoke
        params - The parameters to pass to the method
        Returns:
        The results from invoking the given method
      • invokeStatic

        public static <T> T invokeStatic​(Class<?> targetClass,
                                         Class<T> returnType,
                                         String methodName,
                                         Object... params)
        Dynamically look up and invoke a static method on a target class, with appropriate hints if any failures happen along the way. Note that this method allows to invoke methods that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Type Parameters:
        T - The generic parameter T is deduced from the returnType
        Parameters:
        targetClass - The class to invoke the method on
        returnType - The expected type of the method's return value. Use null (or void.class) if the method that is looked up is a void method.
        methodName - The name of the method to invoke
        params - The parameters to pass to the method
        Returns:
        The results from invoking the given method
      • invoke

        public static void invoke​(Object receiver,
                                  String methodName,
                                  Object... params)
        Dynamically look up and invoke a method on a target object, with appropriate hints if any failures happen along the way. This version is intended for calling "void" methods that have no return value. Note that this method allows to invoke methods that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Parameters:
        receiver - The object to invoke the method on
        methodName - The name of the method to invoke
        params - The parameters to pass to the method
      • invoke

        public static Object invoke​(Object receiver,
                                    Method method,
                                    Object... params)
        Just like Method.invoke(Object, Object...), but converts any thrown exceptions into RuntimeExceptions. Note that this method allows to invoke methods that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Parameters:
        receiver - The object to invoke the method on
        method - The method to invoke
        params - The parameters to pass to the method
        Returns:
        The result from the method
      • invokeEx

        public static <T> T invokeEx​(Object receiver,
                                     Class<T> returnType,
                                     String methodName,
                                     Object... params)
                              throws Exception
        Just like invoke(Object, Class, String, Object...), but unwraps any InvocationTargetExceptions and throws the true cause. This version is provided when you want to write test cases where you are intending to check for Exceptions as expected results. Note that this method allows to invoke methods that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Type Parameters:
        T - The generic parameter T is deduced from the returnType
        Parameters:
        receiver - The object to invoke the method on
        returnType - The expected type of the method's return value. Use null (or void.class) if the method that is looked up is a void method.
        methodName - The name of the method to invoke
        params - The parameters to pass to the method
        Returns:
        The results from invoking the given method
        Throws:
        Exception - if the underlying method throws one
      • invokeEx

        public static void invokeEx​(Object receiver,
                                    String methodName,
                                    Object... params)
                             throws Exception
        Just like invoke(Object, String, Object...), but unwraps any InvocationTargetExceptions and throws the true cause. This version is provided when you want to write test cases where you are intending to check for Exceptions as expected results. Note that this method allows to invoke methods that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Parameters:
        receiver - The object to invoke the method on
        methodName - The name of the method to invoke
        params - The parameters to pass to the method
        Throws:
        Exception - if the underlying method throws one
      • invokeEx

        public static Object invokeEx​(Object receiver,
                                      Method method,
                                      Object... params)
                               throws Exception
        Just like Method.invoke(Object, Object...), but unwraps any InvocationTargetExceptions and throws the true cause. This version is provided when you want to write test cases where you are intending to check for Exceptions as expected results. Note that this method allows to invoke methods that are not visible to the ReflectionSupport class (e. g. package internal classes inside the Grader's package with methods that realize a sample solution). This method will check, whether the caller lives in the same package as the target method. If so, the target method will be invoked. Since you don't want submissions to call this method (because that would easily allow a submission to execute your sample solution), you never should grant submissions the permission to reflect on classes and methods.
        Parameters:
        receiver - The object to invoke the method on
        method - The method to invoke
        params - The parameters to pass to the method
        Returns:
        The result from the method
        Throws:
        Exception - if the underlying method throws one
      • getField

        public static Field getField​(Class<?> receiverClass,
                                     Object receiver,
                                     Class<?> type,
                                     String fieldName)
        Look up a field by name, receiver class, and type, finding the field that will accept the given type (not requiring an exact match on type). Any errors are thrown as instances of ReflectionSupport.ReflectionError. It looks up fields that are declared in the specified class, as well as inherited classes. It sets up accessibility if the field is not public.
        Parameters:
        receiverClass - The class of the receiver
        receiver - the receiver (may be null, if the field is static)
        type - The type of this field
        fieldName - The name of the field
        Returns:
        The corresponding Field
      • get

        public static <T> T get​(Object receiver,
                                Class<T> type,
                                String fieldName)
        Get the value of a field. The field is looked up a field by name, receiver object and type, finding the field that will accept the given type (not requiring an exact match on type). It turns any errors into ReflectionErrors with appropriate hint messages.
        Type Parameters:
        T - The generic parameter T is deduced from the returnType
        Parameters:
        receiver - The object containing the field
        type - The type of this field
        fieldName - The name of the field
        Returns:
        The value corresponding Field
      • get

        public static <T> T get​(Class<?> receiverClass,
                                Object receiver,
                                Class<T> type,
                                String fieldName)
        Get the value of a field. The field is looked up a field by name, receiver object and type, finding the field that will accept the given type (not requiring an exact match on type). It turns any errors into ReflectionErrors with appropriate hint messages. Note that the field must be a static field.
        Type Parameters:
        T - The generic parameter T is deduced from the returnType
        Parameters:
        receiverClass - The class of the receiver
        receiver - the receiver (may be null in case of a static field)
        type - The type of this field
        fieldName - The name of the field
        Returns:
        The value corresponding Field
      • set

        public static void set​(Object receiver,
                               String fieldName,
                               Object value)
        Sets value of a field.
        Parameters:
        receiver - The object of the receiver
        fieldName - The name of the field
        value - The value to set in the field
      • set

        public static void set​(Object receiver,
                               String fieldName,
                               Object value,
                               Class<?> fieldType)
        Sets value of a field.
        Parameters:
        receiver - The object of the receiver
        fieldName - The name of the field
        value - The value to set in the field
        fieldType - the type of the field (either value.getClass() or a primitive type)
      • set

        public static void set​(Class<?> receiverClass,
                               Object receiver,
                               String fieldName,
                               Object value)
        Sets value of a field.
        Parameters:
        receiverClass - The class of the receiver
        receiver - the receiver (may be null in case of a static field)
        fieldName - The name of the field
        value - The value will be set in the field
      • setInt

        public static void setInt​(Class<?> receiverClass,
                                  Object receiver,
                                  String fieldName,
                                  int value)
        Sets value of a field.
        Parameters:
        receiverClass - The class of the receiver
        receiver - the receiver (may be null in case of a static field)
        fieldName - The name of the field
        value - The value will be set in the field
      • setField

        public static void setField​(Class<?> receiverClass,
                                    Object receiver,
                                    String fieldName,
                                    Object value,
                                    Class<?> fieldType)
        Sets value of a field.
        Parameters:
        receiverClass - The class of the receiver
        receiver - the receiver (may be null in case of a static field)
        fieldName - The name of the field
        value - The value will be set in the field
        fieldType - the type of the field (either value.getClass() or a primitive type)
      • simpleClassName

        public static String simpleClassName​(Class<?> aClass)
        Returns the name of the given class without any package prefix. If the argument is an array type, square brackets are added to the name as appropriate. This method isuseful in generating diagnostic messages or feedback.
        Parameters:
        aClass - The class to generate a name for
        Returns:
        The class' name, without the package part, e.g., "String" instead of "java.lang.String"
      • simpleClassNameUsingPrimitives

        public static String simpleClassNameUsingPrimitives​(Class<?> aClass)
        Returns the name of the given class without any package prefix. If the argument is an array type, square brackets are added to the name as appropriate. This method is useful in generating diagnostic messages or feedback.
        Parameters:
        aClass - The class to generate a name for
        Returns:
        The class' name, without the package part, e.g., "String" instead of "java.lang.String"
      • simpleMethodName

        public static String simpleMethodName​(String name,
                                              Class<?>... params)
        Constructs a printable version of a method's name, given the method name and its parameter type(s), if any. Useful in generating diagnostic messages or feedback.
        Parameters:
        name - The method name
        params - The method's parameter type(s), in order
        Returns:
        A printable version of the method name, like "myMethod()" or "yourMethod(String, int)"
      • simpleArgumentList

        public static String simpleArgumentList​(Class<?>... params)
        Constructs a printable version of a method's argument list, including the parentheses, given the method's parameter type(s), if any.
        Parameters:
        params - The method's parameter type(s), in order
        Returns:
        A printable version of the argument list built using simpleClassName(Class), like "(String, int)"
      • simpleMethodName

        public static String simpleMethodName​(Method method)
        Constructs a printable version of a method's name. Unlike Method.toString(), this one uses simpleClassName(Class) so package info is eliminated from the types in the resulting string. It also omits exception information, unlike Method.toString().
        Parameters:
        method - The method to print
        Returns:
        A printable version of the method name, like "public void MyClass.myMethod()" or "public String YourClass.yourMethod(String, int)"
      • actualMatchesFormal

        public static boolean actualMatchesFormal​(Class<?> actual,
                                                  Class<?> formal)
        Determine whether an actual argument type matches a formal argument type. This uses Class.isAssignableFrom(Class), but gives the correct results for primitive types vs. wrapper types.
        Parameters:
        actual - The type of the actual parameter
        formal - The type of the formal parameter
        Returns:
        True if the actual value can be passed into a parameter declared using the formal type
      • canAutoBoxFromActualToFormal

        public static boolean canAutoBoxFromActualToFormal​(Class<?> actual,
                                                           Class<?> formal)
        Determine whether it is appropriate to attempt to "auto-box" an actual argument of type actual into a formal parameter type formal.
        Parameters:
        actual - The type of the actual value.
        formal - The type of the formal parameter.
        Returns:
        True if it is appropriate to auto-box the actual into the type of the formal.