All Downloads are FREE. Search and download functionalities are using the official Maven repository.

junit.extensions.PA Maven / Gradle / Ivy

Go to download

gives privileged access to private and protected methods and attributes. Use it in testing scenarios to set up your objects under test.

The newest version!
/*
 * Copyright Sebastian Dietrich ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
 * and limitations under the License.
 */
package junit.extensions;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;

/**
 * This class is used to access a method or field of an object no matter what the access modifier of the method or field. The syntax for
 * accessing fields and methods is out of the ordinary because this class uses reflection to peel away protection.
 * 

* Here is an example of using this to access a private member:
* Given the following class MyClass:
*

* *
 * public class MyClass {
 *   private String name; // private attribute
 *
 *   // private constructor
 *   private MyClass() {
 *     super();
 *   }
 *
 *   // private method
 *   private void setName(String newName) {
 *     this.name = newName;
 *   }
 * }
 * 
*

* We now want to access the class:
* *

 * MyClass myObj = PA.instantiate(MyClass.class);
 * PA.invokeMethod(myObj, "setName(java.lang.String)", "myNewName");
 * String name = PA.getValue(myObj, "name");
 * 
* * @author Sebastian Dietrich ([email protected]) */ public class PA { private final T instanceOrClass; /** * Private constructor to make it impossible to instantiate this class from outside of PA. * * @param instanceOrClass the instanceOrClass privileged access is provided upon */ private PA(T instanceOrClass) { this.instanceOrClass = instanceOrClass; } /** * Returns a string representation of the given object. The string has the following format: {@code {}} * whereas {@code } is a comma separated list with {@code =}. * {@code } includes all attributes of the objects class followed by the attributes of its superclass (if any) and * so on. * * @param instanceOrClass the object or class to get a string representation of * @return a string representation of the given object * @deprecated use org.apache.commons.lang3.builder.ToStringBuilder instead */ @Deprecated public static String toString(final Object instanceOrClass) { Collection fields = getFieldNames(instanceOrClass); if (fields.isEmpty()) return getClass(instanceOrClass).getName(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(getClass(instanceOrClass).getName()).append(" {"); for (String fieldName : fields) { try { stringBuilder.append(fieldName).append("=").append(getValue(instanceOrClass, fieldName)).append(", "); } catch (IllegalArgumentException e) { assert false : "It should always be possible to get a field that was just here"; } } stringBuilder.replace(stringBuilder.lastIndexOf(", "), stringBuilder.length(), "}"); return stringBuilder.toString(); } /** * Gets the name of all fields (public, private, protected, default) of the given instance or class. This includes as well all fields * (public, private, protected, default) of all its super classes. * * @param instanceOrClass the instance or class to get the fields of * @return the collection of field names of the given instance or classA */ public static Collection getFieldNames(final Object instanceOrClass) { if (instanceOrClass == null) return new HashSet<>(); Class clazz = getClass(instanceOrClass); Field[] fields = clazz.getDeclaredFields(); Collection fieldNames = getFieldNames(clazz.getSuperclass()); for (Field field : fields) { fieldNames.add(field.getName()); } return fieldNames; } /** * Gets the class of the given parameter. If the parameter is a class, it is returned, if it is an object, its class is returned * * @param instanceOrClass the instance or class to get the class of * @return the class of the given parameter */ private static Class getClass(final Object instanceOrClass) { return (instanceOrClass instanceof Class) ? (Class) instanceOrClass : instanceOrClass.getClass(); } /** * Gets the type of the field with the given fieldName in the given instance or class. If not found in the given instance or class checks * as well its super classes. * * @param instanceOrClass the instance or class to get the field type of * @param fieldName the name of the field to get the type of * @return the collection of field names of the given instance or class */ public static Class getFieldType(final Object instanceOrClass, final String fieldName) { try { if (instanceOrClass == null) throw new InvalidParameterException("Can't get field type on null object/class"); return getField(instanceOrClass, fieldName).getType(); } catch (NoSuchFieldException e) { throw new IllegalArgumentException("Can't get type of " + fieldName + " from " + instanceOrClass, e); } } /** * Return the named field from the given instance or class. Returns a static field if instanceOrClass is a class. * * @param instanceOrClass the instance or class to get the field from * @param fieldName the name of the field to get * @return the field * @throws NoSuchFieldException if no such field can be found * @throws InvalidParameterException if instanceOrClass was null */ private static Field getField(final Object instanceOrClass, final String fieldName) throws NoSuchFieldException, InvalidParameterException { if (instanceOrClass == null) throw new InvalidParameterException("Can't get field on null object/class"); Class type = getClass(instanceOrClass); for (Field field : type.getDeclaredFields()) { if (field.getName().equals(fieldName)) { field.setAccessible(true); return field; } } if (type.getSuperclass() == null) throw new NoSuchFieldException(fieldName); return getField(type.getSuperclass(), fieldName); } /** * Gets the signatures (including return types) of all methods (public, private, protected, default) of the given instance or class. This * includes as well all methods (public, private, protected, default) of all its super classes. This does not include constructors. * * @param instanceOrClass the instance or class to get the method signatures of * @return the collection of method signatures of the given instance or class */ public static Collection getMethodSignatures(final Object instanceOrClass) { if (instanceOrClass == null) return new HashSet<>(); Class clazz = getClass(instanceOrClass); Method[] methods = clazz.getDeclaredMethods(); Collection methodSignatures = getMethodSignatures(clazz.getSuperclass()); for (Method method : methods) { methodSignatures .add(method.getReturnType().getName() + " " + method.getName() + "(" + getParameterTypesAsString(method.getParameterTypes()) + ")"); } return methodSignatures; } /** * Gets the parameter types as a string. * * @param classTypes the types to get as names. * @return the parameter types as a string * @see java.lang.Class#argumentTypesToString(Class[]) */ private static String getParameterTypesAsString(final Class[] classTypes) { assert classTypes != null : "getParameterTypes() should have been called before this method and should have provided not-null " + "classTypes"; if (classTypes.length == 0) return ""; StringBuilder parameterTypes = new StringBuilder(); for (Class clazz : classTypes) { assert clazz != null : "getParameterTypes() should have been called before this method and should have provided not-null classTypes"; parameterTypes.append(clazz.getName()).append(", "); } return parameterTypes.substring(0, parameterTypes.length() - 2); } /** * Gets the value of the named field and returns it as an object. If instanceOrClass is a class then a static field is returned. * * @param instanceOrClass the instance or class to get the field from * @param fieldName the name of the field * @return an object representing the value of the field * @throws IllegalArgumentException if the field does not exist */ public static Object getValue(final Object instanceOrClass, final String fieldName) { try { Field field = getField(instanceOrClass, fieldName); try { return field.get(instanceOrClass); } catch (IllegalAccessException e) { assert false : "getField() should have setAccessible(true), so an IllegalAccessException should not occur in this place"; return null; } } catch (Exception e) { throw new IllegalArgumentException("Can't get value of " + fieldName + " from " + instanceOrClass, e); } } /** * Instantiates an object of the given class with the given arguments and the given argument types. If you want to instantiate a member * class, you must provide the object it is a member of as first argument. * * @param fromClass the class to instantiate an object from * @param arguments the arguments to pass to the constructor * @param argumentTypes the fully qualified types of the arguments of the constructor * @param the type of the to be instantiated object * @return an object of the given type * @throws IllegalArgumentException if the class can't be instantiated. This could be the case if the number of actual and formal * parameters differ; if an unwrapping conversion for primitive arguments fails; if, after possible unwrapping, a parameter value * cannot be converted to the corresponding formal parameter type by a method invocation conversion; if this Constructor object * enforces Java language access control and the underlying constructor is inaccessible; if the underlying constructor throws an * exception; if the constructor could not be found; or if the class that declares the underlying constructor represents an * abstract class. */ @SuppressWarnings("unchecked") public static T instantiate(final Class fromClass, final Class[] argumentTypes, final Object... arguments) { try { return (T) getConstructor(fromClass, argumentTypes).newInstance(correctVarargs(arguments)); } catch (Exception e) { throw new IllegalArgumentException("Can't instantiate class " + fromClass + " with arguments " + Arrays.toString(arguments), e); } } /** * Gets the constructor for a given class with the given parameters. * * @param type the class to instantiate * @param parameterTypes the types of the parameters * @return the constructor * @throws NoSuchMethodException if the method could not be found */ private static Constructor getConstructor(final Class type, final Class[] parameterTypes) throws NoSuchMethodException { for (Constructor constructor : type.getDeclaredConstructors()) { if (autoboxingEquals(constructor.getParameterTypes(), parameterTypes)) { constructor.setAccessible(true); return constructor; } } throw new NoSuchMethodException(type.getName() + "." + argumentTypesToString(parameterTypes)); } private static String argumentTypesToString(Class[] argTypes) { StringBuilder buf = new StringBuilder(); buf.append("("); if (argTypes != null) { for (int i = 0; i < argTypes.length; i++ ) { if (i > 0) { buf.append(", "); } Class c = argTypes[i]; buf.append((c == null) ? "null" : c.getName()); } } buf.append(")"); return buf.toString(); } /** * Check if the given objectTypes match the given possiblyPrimitiveTypes. Considers autoboxing. */ private static boolean autoboxingEquals(Class[] possiblyPrimitiveTypes, Class[] objectTypes) { int length = possiblyPrimitiveTypes.length; if (objectTypes.length != length) return false; for (int i = 0; i < length; i++ ) { Class possiblyPrimitiveType = possiblyPrimitiveTypes[i]; Class objectType = objectTypes[i]; if ( !isAssignableFrom(possiblyPrimitiveType, objectType)) return false; } return true; } /** * Checks if the given type1 is assignable from the given other type2. Consideres autoboxing - i.e. on the contrary to * Class.isAssignableFrom an int is assignable from an integer */ private static boolean isAssignableFrom(final Class type1, final Class type2) { if (type1.equals(Integer.class) || type1.equals(int.class)) { return type2.equals(Integer.class) || type2.equals(int.class); } else if (type1.equals(Float.class) || type1.equals(float.class)) { return type2.equals(Float.class) || type2.equals(float.class); } else if (type1.equals(Double.class) || type1.equals(double.class)) { return type2.equals(Double.class) || type2.equals(double.class); } else if (type1.equals(Character.class) || type1.equals(char.class)) { return type2.equals(Character.class) || type2.equals(char.class); } else if (type1.equals(Long.class) || type1.equals(long.class)) { return type2.equals(Long.class) || type2.equals(long.class); } else if (type1.equals(Short.class) || type1.equals(short.class)) { return type2.equals(Short.class) || type2.equals(short.class); } else if (type1.equals(Boolean.class) || type1.equals(boolean.class)) { return type2.equals(Boolean.class) || type2.equals(boolean.class); } else if (type1.equals(Byte.class) || type1.equals(byte.class)) { return type2.equals(Byte.class) || type2.equals(byte.class); } return type1.isAssignableFrom(type2); } /** * Instantiates an object of the given class with the given arguments. If you want to instantiate a member class, you must provide the * object it is a member of as first argument (like Class.forName("mypackage.MyClass$MyInnerClass")). * * @param fromClass the class to instantiate an object from * @param arguments the arguments to pass to the constructor * @param the type of the to be instantiated object * @return an object of the given type * @throws IllegalArgumentException if the class can't be instantiated. This could be the case if the number of actual and formal * parameters differ; if an unwrapping conversion for primitive arguments fails; or if, after possible unwrapping, a parameter * value cannot be converted to the corresponding formal parameter type by a method invocation conversion; if this Constructor * object enforces Java language access control and the underlying constructor is inaccessible; if the underlying constructor * throws an exception; if the constructor could not be found; or if the class that declares the underlying constructor represents * an abstract class. */ @SuppressWarnings({"unchecked"}) public static T instantiate(final Class fromClass, final Object... arguments) { try { final Object[] args = correctVarargs(arguments); return (T) getConstructor(fromClass, getParameterTypes(args)).newInstance(args); } catch (Exception e) { throw new IllegalArgumentException("Can't instantiate class " + fromClass + " with arguments " + Arrays.toString(arguments), e); } } /** * Gets the types of the parameters. * * @param parameters the parameters * @return the class-types of the arguments */ private static Class[] getParameterTypes(final Object[] parameters) { if (parameters == null) return new Class[0]; Class[] typesOfParameters = new Class[parameters.length]; for (int i = 0; i < parameters.length; i++ ) { typesOfParameters[i] = parameters[i].getClass(); } return typesOfParameters; } /** * Calls a method on the given object instance with the given arguments. Arguments can be object types or representations for primitives. * * @param instanceOrClass the instance or class to invoke the method on * @param methodSignature the name of the method and the parameters
* (e.g. "myMethod(java.lang.String, com.company.project.MyObject)") * @param arguments an array of objects to pass as arguments * @return the return value of this method or null if void * @throws RuntimeException any runtime exception the invoked method has thrown * @throws IllegalArgumentException if the method could not be invoked or the method threw a non-runtime exception or error. This could be * the case if the method is inaccessible; if the underlying method throws an exception; if no method with the given * methodSignature could be found; or if an argument couldn't be converted to match the expected type S */ public static Object invokeMethod(final Object instanceOrClass, final String methodSignature, final Object... arguments) { try { if ((methodSignature.indexOf('(') == -1) || (methodSignature.indexOf('(') >= methodSignature.indexOf(')'))) { throw new NoSuchMethodException(methodSignature); } Class[] parameterTypes = getParameterTypes(methodSignature); try { final Class[] parameterTypes1 = parameterTypes; return getMethod(getClass(instanceOrClass), getMethodName(methodSignature), parameterTypes1) .invoke(instanceOrClass, getCorrectedArguments(parameterTypes, correctVarargs(arguments))); } catch (InvocationTargetException e) { throw e.getCause(); } } catch (IllegalAccessException e) { throw new IllegalArgumentException( "Can't access method " + methodSignature + " of " + instanceOrClass + " with arguments " + Arrays.toString(arguments), e); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Can't find method " + methodSignature + " in " + instanceOrClass, e); } catch (RuntimeException e) { throw e; } catch (Throwable e) { throw new IllegalArgumentException( "Invoking method " + methodSignature + " on " + instanceOrClass + " with arguments " + Arrays.toString(arguments) + " threw the non-runtime exception " + e.getClass().getName(), e); } } /** * Gets the types of the given parameters. If the parameters don't match the given methodSignature an IllegalArgumentException is thrown. * * @param methodSignature the signature of the method * @return the parameter types as class[] * @throws NoSuchMethodException if the method could not be found * @throws IllegalArgumentException if one of the given parameters doesn't math the given methodSignature */ private static Class[] getParameterTypes(final String methodSignature) throws NoSuchMethodException, IllegalArgumentException { String signature = getSignatureWithoutBraces(methodSignature); StringTokenizer tokenizer = new StringTokenizer(signature, ", *"); Class[] typesInSignature = new Class[tokenizer.countTokens()]; for (int x = 0; tokenizer.hasMoreTokens(); x++ ) { String className = tokenizer.nextToken(); try { typesInSignature[x] = getClassForName(className); } catch (ClassNotFoundException e) { NoSuchMethodException noSuchMethodException = new NoSuchMethodException(methodSignature); noSuchMethodException.initCause(e); throw noSuchMethodException; } } return typesInSignature; } /** * Gets the class with the given className. Can handle arrays, varargs, primitives, ... * * @param className the name of the class to get * @return the class for the given className * @throws ClassNotFoundException if the class could not be found */ private static Class getClassForName(final String className) throws ClassNotFoundException { if (className.contains("[")) { Class clazz = getClassForName(className.substring(0, className.indexOf('['))); return Array.newInstance(clazz, 0).getClass(); } if (className.contains("...")) { Class clazz = getClassForName(className.substring(0, className.indexOf("..."))); return Array.newInstance(clazz, 0).getClass(); } try { return Class.forName(className, false, Thread.currentThread().getContextClassLoader()); } catch (ClassNotFoundException e) { return getSpecialClassForName(className); } } /** * Maps string representation of primitives to their corresponding classes. */ private static final Map> PRIMITIVE_MAPPER = new HashMap<>(8); /** * Fills the map with all java primitives and their corresponding classes. */ static { PRIMITIVE_MAPPER.put("int", Integer.TYPE); PRIMITIVE_MAPPER.put("float", Float.TYPE); PRIMITIVE_MAPPER.put("double", Double.TYPE); PRIMITIVE_MAPPER.put("short", Short.TYPE); PRIMITIVE_MAPPER.put("long", Long.TYPE); PRIMITIVE_MAPPER.put("byte", Byte.TYPE); PRIMITIVE_MAPPER.put("char", Character.TYPE); PRIMITIVE_MAPPER.put("boolean", Boolean.TYPE); } /** * Gets special classes for the given className. Special classes are primitives and "standard" Java types (like String) * * @param className the name of the class to get * @return the class for the given className * @throws ClassNotFoundException if the class could not be found */ private static Class getSpecialClassForName(final String className) throws ClassNotFoundException { if (PRIMITIVE_MAPPER.containsKey(className)) return PRIMITIVE_MAPPER.get(className); if (missesPackageName(className)) return getStandardClassForName(className); throw new ClassNotFoundException(className); } /** * Tests if the given className possibly misses its package name. * * @param className the className * @return true if the className might miss its package name, otherwise false */ private static boolean missesPackageName(String className) { if (className.contains(".")) return false; return className.startsWith(className.substring(0, 1).toUpperCase()); } /** * Gets a 'standard' java class for the given className. * * @param className the className * @return the class for the given className (if any) * @throws ClassNotFoundException of no 'standard' java class was found for the given className */ private static Class getStandardClassForName(String className) throws ClassNotFoundException { try { return Class.forName("java.lang." + className, false, Thread.currentThread().getContextClassLoader()); } catch (ClassNotFoundException e) { try { return Class.forName("java.util." + className, false, Thread.currentThread().getContextClassLoader()); } catch (ClassNotFoundException e1) { throw new ClassNotFoundException(className); } } } /** * Removes the braces around the methods signature. * * @param methodSignature the signature with braces * @return the signature without braces */ private static String getSignatureWithoutBraces(final String methodSignature) { try { return methodSignature.substring(methodSignature.indexOf('(') + 1, methodSignature.indexOf(')')); } catch (IndexOutOfBoundsException e) { assert false : "signature must have been checked before this method"; return null; } } /** * Return the named method with a method signature matching classTypes from the given class. * * @param type the class to get the method from * @param methodName the name of the method to get * @param parameterTypes the parameter-types of the method to get * @return the method * @throws NoSuchMethodException if the method could not be found */ private static Method getMethod(final Class type, final String methodName, final Class[] parameterTypes) throws NoSuchMethodException { for (Method method : type.getDeclaredMethods()) { if (method.getName().equals(methodName) && Arrays.equals(method.getParameterTypes(), parameterTypes)) { method.setAccessible(true); return method; } } if (type.getSuperclass() == null) { throw new NoSuchMethodException(type.getName() + "." + methodName + argumentTypesToString(parameterTypes)); } return getMethod(type.getSuperclass(), methodName, parameterTypes); } /** * Gets the name of a method. * * @param methodSignature the signature of the method * @return the name of the method */ private static String getMethodName(final String methodSignature) { try { return methodSignature.substring(0, methodSignature.indexOf('(')).trim(); } catch (StringIndexOutOfBoundsException e) { assert false : "Signature must have been checked before this method was called"; return null; } } /** * Gets the given arguments corrected to match the given methodSignature. Correction is necessary for array arguments not to be mistaken * by varargs. * * @param parameterTypes the method signatue the given arguments should match * @param arguments the arguments that should be corrected * @return the corrected arguments */ private static Object[] getCorrectedArguments(Class[] parameterTypes, Object[] arguments) { if (arguments == null) return arguments; if (parameterTypes.length > arguments.length) return arguments; if (parameterTypes.length < arguments.length) return getCorrectedArguments(parameterTypes, new Object[] {arguments}); Object[] correctedArguments = new Object[arguments.length]; int currentArgument = 0; for (Class parameterType : parameterTypes) { correctedArguments[currentArgument] = getCorrectedArgument(parameterType, arguments[currentArgument]); currentArgument++ ; } return correctedArguments; } /** * Gets the given argument corrected to match the given parameterType. Correction is necessary for array arguments not to be mistaken by * varargs. * * @param parameterType the type to match the given argument upon * @param argument the argument to match the given parameterType * @return the corrected argument */ private static Object getCorrectedArgument(Class parameterType, Object argument) { if ( !parameterType.isArray() || (argument == null)) { return argument; // normal argument for normal parameterType } if ( !argument.getClass().isArray()) { return new Object[] {argument}; } if (parameterType.equals(argument.getClass())) return argument; // no need to cast // (typed) array argument for (object) array parameterType, elements need to be casted Object correctedArrayArgument = Array.newInstance(parameterType.getComponentType(), Array.getLength(argument)); for (int index = 0; index < Array.getLength(argument); index++ ) { if (parameterType.getComponentType().isPrimitive()) { // rely on autoboxing Array.set(correctedArrayArgument, index, Array.get(argument, index)); } else { // cast to expected type try { Array.set(correctedArrayArgument, index, parameterType.getComponentType().cast(Array.get(argument, index))); } catch (ClassCastException e) { throw new IllegalArgumentException( "Argument " + argument + " of type " + argument.getClass() + " does not match expected argument type " + parameterType + "."); } } } return correctedArrayArgument; } /** * Corrects varargs to their initial form. If you call a method with an object-array as last argument the Java varargs mechanism converts * this array in single arguments. This method returns an object array if the arguments are all of the same type. * * @param arguments the possibly converted arguments of a vararg method * @return arguments possibly converted */ private static Object[] correctVarargs(final Object... arguments) { if ((arguments == null) || changedByVararg(arguments)) return new Object[] {arguments}; return arguments; } /** * Tests if the arguments were changed by vararg. Arguments are changed by vararg if they are of a non primitive array type. E.g. * arguments[] = Object[String[]] is converted to String[] while e.g. arguments[] = Object[int[]] is not converted and stays Object[int[]] *

* Unfortunately we can't detect the difference for arg = Object[primitive] since arguments[] = Object[Object[primitive]] which is * converted to Object[primitive] and arguments[] = Object[primitive] which stays Object[primitive] *

* and we can't detect the difference for arg = Object[non primitive] since arguments[] = Object[Object[non primitive]] is converted to * Object[non primitive] and arguments[] = Object[non primitive] stays Object[non primitive] * * @param parameters the parameters * @return true if parameters were changes by varargs, false otherwise */ private static boolean changedByVararg(final Object[] parameters) { if ((parameters.length == 0) || (parameters[0] == null)) return false; return parameters.getClass() != Object[].class; } /** * Sets the value of the named field. If fieldName denotes a static field, provide a class, otherwise provide an instance. If the * fieldName denotes a final field, this method tries to set it nevertheless (by temporarily removing the modifier).
*
* Example:
*
* * String myString = "Test";
*
* //setting the private field value
* PA.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});
*
* //setting the static final field serialVersionUID - MIGHT FAIL
* PA.setValue(myString.getClass(), "serialVersionUID", 1);
*
*
* * @param instanceOrClass the instance or class to set the field * @param fieldName the name of the field * @param value the new value of the field * @param the type of the object to set the value * @return this, so that calls to this method can be chained * @throws IllegalArgumentException if the value could not be set. This could be the case if no field with the given * fieldName can be found; or if the field was final */ public static PA setValue(final T instanceOrClass, final String fieldName, final Object value) { try { Field field = getField(instanceOrClass, fieldName); if (Modifier.isFinal(field.getModifiers())) { setValue(field, "modifiers", field.getModifiers() ^ Modifier.FINAL); field.set(instanceOrClass, value); setValue(field, "modifiers", field.getModifiers() | Modifier.FINAL); } field.set(instanceOrClass, value); } catch (Exception e) { throw new IllegalArgumentException("Can't set value " + value + " at " + fieldName + " in " + instanceOrClass, e); } return new PA<>(instanceOrClass); } /** * Gets the value of the named field and returns it as an object. * * @param fieldName the name of the field * @return an object representing the value of the field * @throws IllegalArgumentException if the field does not exist * @see PA#getValue(Object, String) */ public Object getValue(final String fieldName) { return PA.getValue(instanceOrClass, fieldName); } /** * Calls a method with the given arguments. Arguments can be object types or representations for primitives. * * @param methodSignature the name of the method and the parameters
* (e.g. "myMethod(java.lang.String, com.company.project.MyObject)") * @param arguments an array of objects to pass as arguments * @return the return value of this method or null if void * @throws RuntimeException any runtime exception the invoked method has thrown * @throws IllegalArgumentException if the method could not be invoked or threw a non-runtime exception or error. This could be the case * if the method is inaccessible; if the underlying method throws an exception; if no method with the given * methodSignature could be found; or if an argument couldn't be converted to match the expected type * @see PA#invokeMethod(Object, String, Object...) */ public Object invokeMethod(final String methodSignature, final Object... arguments) { return PA.invokeMethod(instanceOrClass, methodSignature, arguments); } /** * Sets the value of the named field. If fieldName denotes a static field, provide a class, otherwise provide an instance. If the * fieldName denotes a final field, this method could fail with an IllegalAccessException, since setting the value of final fields at * other times than instantiation can have unpredictable effects.
*
* Example:
*
* * String myString = "Test";
*
* //setting the private field value - will fail with JDK after 1.6
* PA.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});
*
* //setting the static final field serialVersionUID - MIGHT FAIL
* PA.setValue(myString.getClass(), "serialVersionUID", 1);
*
*
* * @param fieldName the name of the field * @param value the new value of the field * @return this, so calls to this method can be chained * @throws IllegalArgumentException if the value could not be set. This could be the case if no field with the given * fieldName can be found; or if the field was final * @see junit.extensions.PA#setValue(Object, String, Object) */ public PA setValue(final String fieldName, final Object value) { PA.setValue(instanceOrClass, fieldName, value); return this; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy