2 * Copyright 2004-2012 Sebastian Dietrich (Sebastian.Dietrich@e-movimento.com)
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package junit.extensions;
18 import java.util.Collection;
21 * This class is used to access a method or field of an object no matter what
22 * the access modifier of the method or field. The syntax for accessing fields
23 * and methods is out of the ordinary because this class uses reflection to peel
26 * a.k.a. The "ObjectMolester"
28 * Here is an example of using this to access a private member: <br>
29 * Given the following class <code>MyClass</code>: <br>
32 * public class MyClass
34 * private String name; // private attribute
36 * // private constructor
43 * private void setName(String newName)
45 * this.name = newName;
50 * We now want to access the class: <br>
53 * MyClass myObj = PA.instantiate(MyClass.class);
54 * PA.invokeMethod(myObj, "setName(java.lang.String)", "myNewName");
55 * String name = PA.getValue(myObj, "name");
58 * This class extends {@link PrivilegedAccessor} by re-throwing checked
59 * {@link Exception}s as {@link RuntimeException}s.
62 * @see PrivilegedAccessor
64 * @author Sebastian Dietrich (sebastian.dietrich@e-movimento.com)
65 * @author Lubos Bistak (lubos@bistak.sk)
69 private final Object instanceOrClass;
72 * Private constructor to make it impossible to instantiate this class from
75 * @param instanceOrClass
77 private PA(Object instanceOrClass)
79 this.instanceOrClass = instanceOrClass;
83 * Returns a string representation of the given object. The string has the
84 * following format: "<classname> {<attributes and values>}" whereas
85 * <attributes and values> is a comma separated list with
86 * <attributeName>=<attributeValue> <atributes and values> includes all
87 * attributes of the objects class followed by the attributes of its
88 * superclass (if any) and so on.
90 * @param instanceOrClass
91 * the object or class to get a string representation of
92 * @return a string representation of the given object
94 * @see PrivilegedAccessor#toString(Object)
96 public static String toString(final Object instanceOrClass)
98 return PrivilegedAccessor.toString(instanceOrClass);
102 * Gets the name of all fields (public, private, protected, default) of the
103 * given instance or class. This includes as well all fields (public, private,
104 * protected, default) of all its super classes.
106 * @param instanceOrClass
107 * the instance or class to get the fields of
108 * @return the collection of field names of the given instance or class
110 * @see PrivilegedAccessor#getFieldNames(Object)
112 public static Collection<String> getFieldNames(
113 final Object instanceOrClass)
115 return PrivilegedAccessor.getFieldNames(instanceOrClass);
119 * Gets the signatures of all methods (public, private, protected, default) of
120 * the given instance or class. This includes as well all methods (public,
121 * private, protected, default) of all its super classes. This does not
122 * include constructors.
124 * @param instanceOrClass
125 * the instance or class to get the method signatures of
126 * @return the collection of method signatures of the given instance or class
128 * @see PrivilegedAccessor#getMethodSignatures(Object)
130 public static Collection<String> getMethodSignatures(
131 final Object instanceOrClass)
133 return PrivilegedAccessor.getMethodSignatures(instanceOrClass);
137 * Gets the value of the named field and returns it as an object. If
138 * instanceOrClass is a class then a static field is returned.
140 * @param instanceOrClass
141 * the instance or class to get the field from
143 * the name of the field
144 * @return an object representing the value of the field
145 * @throws IllegalArgumentException
146 * if the field does not exist
148 * @see PrivilegedAccessor#getValue(Object,String)
150 public static Object getValue(final Object instanceOrClass,
151 final String fieldName)
155 return PrivilegedAccessor.getValue(instanceOrClass, fieldName);
156 } catch (Exception e)
158 throw new IllegalArgumentException("Can't get value of " + fieldName
159 + " from " + instanceOrClass, e);
164 * Gets the value of the named field and returns it as an object.
167 * the name of the field
168 * @return an object representing the value of the field
169 * @throws IllegalArgumentException
170 * if the field does not exist
172 * @see PA#getValue(Object,String)
174 public Object getValue(final String fieldName)
176 return PA.getValue(instanceOrClass, fieldName);
180 * Instantiates an object of the given class with the given arguments and the
181 * given argument types. If you want to instantiate a member class, you must
182 * provide the object it is a member of as first argument.
185 * the class to instantiate an object from
187 * the arguments to pass to the constructor
188 * @param argumentTypes
189 * the fully qualified types of the arguments of the constructor
190 * @return an object of the given type
191 * @throws IllegalArgumentException
192 * if the class can't be instantiated. This could be the case if the
193 * number of actual and formal parameters differ; if an unwrapping
194 * conversion for primitive arguments fails; if, after possible
195 * unwrapping, a parameter value cannot be converted to the
196 * corresponding formal parameter type by a method invocation
197 * conversion; if this Constructor object enforces Java language
198 * access control and the underlying constructor is inaccessible; if
199 * the underlying constructor throws an exception; if the
200 * constructor could not be found; or if the class that declares the
201 * underlying constructor represents an abstract class.
203 * @see PrivilegedAccessor#instantiate(Class,Class[],Object[])
205 public static <T> T instantiate(final Class<? extends T> fromClass,
206 final Class<?>[] argumentTypes, final Object... arguments)
210 return PrivilegedAccessor.instantiate(fromClass, argumentTypes,
211 correctVarargs(arguments));
212 } catch (Exception e)
214 throw new IllegalArgumentException("Can't instantiate class "
215 + fromClass + " with arguments " + arguments, e);
220 * Instantiates an object of the given class with the given arguments. If you
221 * want to instantiate a member class, you must provide the object it is a
222 * member of as first argument.
225 * the class to instantiate an object from
227 * the arguments to pass to the constructor
228 * @return an object of the given type
229 * @throws IllegalArgumentException
230 * if the class can't be instantiated. This could be the case if the
231 * number of actual and formal parameters differ; if an unwrapping
232 * conversion for primitive arguments fails; or if, after possible
233 * unwrapping, a parameter value cannot be converted to the
234 * corresponding formal parameter type by a method invocation
235 * conversion; if this Constructor object enforces Java language
236 * access control and the underlying constructor is inaccessible; if
237 * the underlying constructor throws an exception; if the
238 * constructor could not be found; or if the class that declares the
239 * underlying constructor represents an abstract class.
241 * @see PrivilegedAccessor#instantiate(Class,Object[])
243 public static <T> T instantiate(final Class<? extends T> fromClass,
244 final Object... arguments)
248 return PrivilegedAccessor.instantiate(fromClass,
249 correctVarargs(arguments));
250 } catch (Exception e)
252 throw new IllegalArgumentException("Can't instantiate class "
253 + fromClass + " with arguments " + arguments, e);
258 * Calls a method on the given object instance with the given arguments.
259 * Arguments can be object types or representations for primitives.
261 * @param instanceOrClass
262 * the instance or class to invoke the method on
263 * @param methodSignature
264 * the name of the method and the parameters <br>
265 * (e.g. "myMethod(java.lang.String, com.company.project.MyObject)")
267 * an array of objects to pass as arguments
268 * @return the return value of this method or null if void
269 * @throws IllegalArgumentException
270 * if the method could not be invoked. This could be the case if the
271 * method is inaccessible; if the underlying method throws an
272 * exception; if no method with the given
273 * <code>methodSignature</code> could be found; or if an argument
274 * couldn't be converted to match the expected type
276 * @see PrivilegedAccessor#invokeMethod(Object,String,Object[])
278 public static Object invokeMethod(final Object instanceOrClass,
279 final String methodSignature, final Object... arguments)
283 return PrivilegedAccessor.invokeMethod(instanceOrClass,
284 methodSignature, correctVarargs(arguments));
285 } catch (Exception e)
287 throw new IllegalArgumentException(
288 "Can't invoke method " + methodSignature + " on "
289 + instanceOrClass + " with arguments " + arguments,
295 * Calls a method with the given arguments. Arguments can be object types or
296 * representations for primitives.
298 * @param methodSignature
299 * the name of the method and the parameters <br>
300 * (e.g. "myMethod(java.lang.String, com.company.project.MyObject)")
302 * an array of objects to pass as arguments
303 * @return the return value of this method or null if void
304 * @throws IllegalArgumentException
305 * if the method could not be invoked. This could be the case if the
306 * method is inaccessible; if the underlying method throws an
307 * exception; if no method with the given
308 * <code>methodSignature</code> could be found; or if an argument
309 * couldn't be converted to match the expected type
310 * @see PA#invokeMethod(Object, String, Object...)
312 public Object invokeMethod(final String methodSignature,
313 final Object... arguments)
315 return PA.invokeMethod(instanceOrClass, methodSignature, arguments);
319 * Corrects varargs to their initial form. If you call a method with an
320 * object-array as last argument the Java varargs mechanism converts this
321 * array in single arguments. This method returns an object array if the
322 * arguments are all of the same type.
325 * the possibly converted arguments of a vararg method
326 * @return arguments possibly converted
328 private static Object[] correctVarargs(final Object... arguments)
330 if ((arguments == null) || changedByVararg(arguments))
331 return new Object[] { arguments };
336 * Tests if the arguments were changed by vararg. Arguments are changed by
337 * vararg if they are of a non primitive array type. E.g. arguments[] =
338 * Object[String[]] is converted to String[] while e.g. arguments[] =
339 * Object[int[]] is not converted and stays Object[int[]]
341 * Unfortunately we can't detect the difference for arg = Object[primitive]
342 * since arguments[] = Object[Object[primitive]] which is converted to
343 * Object[primitive] and arguments[] = Object[primitive] which stays
346 * and we can't detect the difference for arg = Object[non primitive] since
347 * arguments[] = Object[Object[non primitive]] is converted to Object[non
348 * primitive] and arguments[] = Object[non primitive] stays Object[non
353 * @return true if parameters were changes by varargs, false otherwise
355 private static boolean changedByVararg(final Object[] parameters)
357 if ((parameters.length == 0) || (parameters[0] == null))
360 if (parameters.getClass() == Object[].class)
367 * Sets the value of the named field. If fieldName denotes a static field,
368 * provide a class, otherwise provide an instance. If the fieldName denotes a
369 * final field, this method could fail with an IllegalAccessException, since
370 * setting the value of final fields at other times than instantiation can
371 * have unpredictable effects.<br/>
376 * String myString = "Test"; <br/>
378 * //setting the private field value<br/>
379 * PrivilegedAccessor.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});<br/>
381 * //setting the static final field serialVersionUID - MIGHT FAIL<br/>
382 * PrivilegedAccessor.setValue(myString.getClass(), "serialVersionUID", 1);<br/>
386 * @param instanceOrClass
387 * the instance or class to set the field
389 * the name of the field
391 * the new value of the field
392 * @throws IllegalArgumentException
393 * if the value could not be set. This could be the case if no field
394 * with the given <code>fieldName</code> can be found; or if the
397 * @see PrivilegedAccessor.setValue(Object,String,Object)
399 public static PA setValue(final Object instanceOrClass,
400 final String fieldName, final Object value)
404 PrivilegedAccessor.setValue(instanceOrClass, fieldName, value);
405 } catch (Exception e)
407 throw new IllegalArgumentException("Can't set value " + value + " at "
408 + fieldName + " in " + instanceOrClass, e);
410 return new PA(instanceOrClass);
414 * Sets the value of the named field. If fieldName denotes a static field,
415 * provide a class, otherwise provide an instance. If the fieldName denotes a
416 * final field, this method could fail with an IllegalAccessException, since
417 * setting the value of final fields at other times than instantiation can
418 * have unpredictable effects.<br/>
423 * String myString = "Test"; <br/>
425 * //setting the private field value<br/>
426 * PrivilegedAccessor.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});<br/>
428 * //setting the static final field serialVersionUID - MIGHT FAIL<br/>
429 * PrivilegedAccessor.setValue(myString.getClass(), "serialVersionUID", 1);<br/>
434 * the name of the field
436 * the new value of the field
437 * @throws IllegalArgumentException
438 * if the value could not be set. This could be the case if no field
439 * with the given <code>fieldName</code> can be found; or if the
442 * @see PA.setValue(Object,String,Object)
444 public PA setValue(final String fieldName, final Object value)
446 PA.setValue(instanceOrClass, fieldName, value);