Class ReflectionSupport
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).
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic class
A custom error class that represents any error conditions that arise in the reflection-based methods provided by this class.static enum
An enumeration that represents a set of constants for specifying constraints on the visibility of a declaration. -
Method Summary
Modifier and TypeMethodDescriptionstatic boolean
actualMatchesFormal
(Class<?> actual, Class<?> formal) Determine whether an actual argument type matches a formal argument type.static boolean
canAutoBoxFromActualToFormal
(Class<?> actual, Class<?> formal) Determine whether it is appropriate to attempt to "auto-box" an actual argument of typeactual
into a formal parameter typeformal
.static <T> T
Dynamically look up and invoke a class constructor for the target class, with appropriate hints if any failures happen along the way.static <T> T
create
(Constructor<T> constructor, Object... params) Just likeConstructor.newInstance(Object...)
, but converts any thrown exceptions into RuntimeExceptions.static Object
Dynamically look up and invoke a class constructor for the target class, with appropriate hints if any failures happen along the way.static <T> T
Just likecreate(Class, Object...)
, but unwraps any InvocationTargetExceptions and throws the true cause.static Object
createEx
(Constructor<?> constructor, Object... params) Just likecreate(Constructor, Object...)
, but unwraps any InvocationTargetExceptions and throws the true cause.static Object
Just likecreate(String, Object...)
, but unwraps any InvocationTargetExceptions and throws the true cause.static <T> T
Get the value of a field.static <T> T
Get the value of a field.static Class<?>
getClassForName
(String className) Dynamically look up a class by name, with appropriate hints if the class cannot be found.static Field
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).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).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).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).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).static Method
Look up a method by name and parameter profile, turning any errors into test case failures with appropriate hint messages.static <T> T
invoke
(Class<?> targetClass, Object receiver, Class<T> returnType, String methodName, Object... params) static <T> T
Dynamically look up and invoke a method on a target object, with appropriate hints if any failures happen along the way.static Object
Just likeMethod.invoke(Object, Object...)
, but converts any thrown exceptions into RuntimeExceptions.static void
Dynamically look up and invoke a method on a target object, with appropriate hints if any failures happen along the way.static <T> T
Just likeinvoke(Object, Class, String, Object...)
, but unwraps any InvocationTargetExceptions and throws the true cause.static Object
Just likeMethod.invoke(Object, Object...)
, but unwraps any InvocationTargetExceptions and throws the true cause.static void
Just likeinvoke(Object, String, Object...)
, but unwraps any InvocationTargetExceptions and throws the true cause.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.static void
Sets value of a field.static void
Sets value of a field.static void
Sets value of a field.static void
setField
(Class<?> receiverClass, Object receiver, String fieldName, Object value, Class<?> fieldType) Sets value of a field.static void
Sets value of a field.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.static String
simpleClassName
(Class<?> aClass) Returns the name of the given class without any package prefix.static String
simpleClassNameUsingPrimitives
(Class<?> aClass) Returns the name of the given class without any package prefix.static String
simpleMethodName
(Method method) Constructs a printable version of a method's name.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.
-
Method Details
-
getClassForName
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
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 createparams
- 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 createmandatoryModifiers
- 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
Just likeConstructor.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 invokeparams
- The parameters to pass to the constructor- Returns:
- The newly created object
-
create
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
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 createparams
- The parameters to pass to the constructor- Returns:
- The newly created object
-
createEx
Just likecreate(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 invokeparams
- The parameters to pass to the constructor- Returns:
- The newly created object
- Throws:
Exception
- if the underlying method throws one
-
createEx
Just likecreate(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
Just likecreate(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 createparams
- The parameters to pass to the constructor- Returns:
- The newly created object
- Throws:
Exception
- if the underlying method throws one
-
getMethod
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 receivername
- The method nameparams
- The method's parameter profile- Returns:
- The corresponding Method object
-
getMatchingMethod
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 receivername
- The method nameparams
- 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 receivername
- The method namemandatoryModifiers
- 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 onreturnType
- The expected type of the method's return value. Use null (orvoid.class
) if the method that is looked up is a void method.methodName
- The name of the method to invokeparams
- The parameters to pass to the method- Returns:
- The results from invoking the given method
-
invoke
-
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 onreturnType
- The expected type of the method's return value. Use null (orvoid.class
) if the method that is looked up is a void method.methodName
- The name of the method to invokeparams
- The parameters to pass to the method- Returns:
- The results from invoking the given method
-
invoke
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 onmethodName
- The name of the method to invokeparams
- The parameters to pass to the method
-
invoke
Just likeMethod.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 onmethod
- The method to invokeparams
- 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 likeinvoke(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 onreturnType
- The expected type of the method's return value. Use null (orvoid.class
) if the method that is looked up is a void method.methodName
- The name of the method to invokeparams
- The parameters to pass to the method- Returns:
- The results from invoking the given method
- Throws:
Exception
- if the underlying method throws one
-
invokeEx
Just likeinvoke(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 onmethodName
- The name of the method to invokeparams
- The parameters to pass to the method- Throws:
Exception
- if the underlying method throws one
-
invokeEx
Just likeMethod.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 onmethod
- The method to invokeparams
- 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 ofReflectionSupport.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 receiverreceiver
- the receiver (may be null, if the field is static)type
- The type of this fieldfieldName
- The name of the field- Returns:
- The corresponding Field
-
get
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 fieldtype
- The type of this fieldfieldName
- The name of the field- Returns:
- The value corresponding Field
-
get
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 receiverreceiver
- the receiver (may be null in case of a static field)type
- The type of this fieldfieldName
- The name of the field- Returns:
- The value corresponding Field
-
set
Sets value of a field.- Parameters:
receiver
- The object of the receiverfieldName
- The name of the fieldvalue
- The value to set in the field
-
set
Sets value of a field.- Parameters:
receiver
- The object of the receiverfieldName
- The name of the fieldvalue
- The value to set in the fieldfieldType
- the type of the field (either value.getClass() or a primitive type)
-
set
Sets value of a field.- Parameters:
receiverClass
- The class of the receiverreceiver
- the receiver (may be null in case of a static field)fieldName
- The name of the fieldvalue
- The value will be set in the field
-
setInt
Sets value of a field.- Parameters:
receiverClass
- The class of the receiverreceiver
- the receiver (may be null in case of a static field)fieldName
- The name of the fieldvalue
- 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 receiverreceiver
- the receiver (may be null in case of a static field)fieldName
- The name of the fieldvalue
- The value will be set in the fieldfieldType
- the type of the field (either value.getClass() or a primitive type)
-
simpleClassName
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
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
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 nameparams
- The method's parameter type(s), in order- Returns:
- A printable version of the method name, like "myMethod()" or "yourMethod(String, int)"
-
simpleArgumentList
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
Constructs a printable version of a method's name. UnlikeMethod.toString()
, this one usessimpleClassName(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
Determine whether an actual argument type matches a formal argument type. This usesClass.isAssignableFrom(Class)
, but gives the correct results for primitive types vs. wrapper types.- Parameters:
actual
- The type of the actual parameterformal
- The type of the formal parameter- Returns:
- True if the actual value can be passed into a parameter declared using the formal type
-
canAutoBoxFromActualToFormal
Determine whether it is appropriate to attempt to "auto-box" an actual argument of typeactual
into a formal parameter typeformal
.- 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.
-