JAL-3438 spotless for 2.11.2.0
[jalview.git] / test / junit / extensions / PA.java
1 /*
2  * Copyright 2004-2012 Sebastian Dietrich (Sebastian.Dietrich@e-movimento.com)
3  *
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
7  * 
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  * 
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.
15  */
16 package junit.extensions;
17
18 import java.util.Collection;
19
20 /**
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
24  * away protection.
25  * <p>
26  * a.k.a. The "ObjectMolester"
27  * <p>
28  * Here is an example of using this to access a private member: <br>
29  * Given the following class <code>MyClass</code>: <br>
30  * 
31  * <pre>
32  * public class MyClass
33  * {
34  *   private String name; // private attribute
35  * 
36  *   // private constructor
37  *   private MyClass()
38  *   {
39  *     super();
40  *   }
41  * 
42  *   // private method
43  *   private void setName(String newName)
44  *   {
45  *     this.name = newName;
46  *   }
47  * }
48  * </pre>
49  * 
50  * We now want to access the class: <br>
51  * 
52  * <pre>
53  * MyClass myObj = PA.instantiate(MyClass.class);
54  * PA.invokeMethod(myObj, &quot;setName(java.lang.String)&quot;, &quot;myNewName&quot;);
55  * String name = PA.getValue(myObj, &quot;name&quot;);
56  * </pre>
57  * 
58  * This class extends {@link PrivilegedAccessor} by re-throwing checked
59  * {@link Exception}s as {@link RuntimeException}s.
60  * 
61  * 
62  * @see PrivilegedAccessor
63  * 
64  * @author Sebastian Dietrich (sebastian.dietrich@e-movimento.com)
65  * @author Lubos Bistak (lubos@bistak.sk)
66  */
67 public class PA
68 {
69   private final Object instanceOrClass;
70
71   /**
72    * Private constructor to make it impossible to instantiate this class from
73    * outside of PA.
74    * 
75    * @param instanceOrClass
76    */
77   private PA(Object instanceOrClass)
78   {
79     this.instanceOrClass = instanceOrClass;
80   }
81
82   /**
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.
89    * 
90    * @param instanceOrClass
91    *          the object or class to get a string representation of
92    * @return a string representation of the given object
93    * 
94    * @see PrivilegedAccessor#toString(Object)
95    */
96   public static String toString(final Object instanceOrClass)
97   {
98     return PrivilegedAccessor.toString(instanceOrClass);
99   }
100
101   /**
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.
105    * 
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
109    * 
110    * @see PrivilegedAccessor#getFieldNames(Object)
111    */
112   public static Collection<String> getFieldNames(
113           final Object instanceOrClass)
114   {
115     return PrivilegedAccessor.getFieldNames(instanceOrClass);
116   }
117
118   /**
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.
123    * 
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
127    * 
128    * @see PrivilegedAccessor#getMethodSignatures(Object)
129    */
130   public static Collection<String> getMethodSignatures(
131           final Object instanceOrClass)
132   {
133     return PrivilegedAccessor.getMethodSignatures(instanceOrClass);
134   }
135
136   /**
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.
139    * 
140    * @param instanceOrClass
141    *          the instance or class to get the field from
142    * @param fieldName
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
147    * 
148    * @see PrivilegedAccessor#getValue(Object,String)
149    */
150   public static Object getValue(final Object instanceOrClass,
151           final String fieldName)
152   {
153     try
154     {
155       return PrivilegedAccessor.getValue(instanceOrClass, fieldName);
156     } catch (Exception e)
157     {
158       throw new IllegalArgumentException("Can't get value of " + fieldName
159               + " from " + instanceOrClass, e);
160     }
161   }
162
163   /**
164    * Gets the value of the named field and returns it as an object.
165    * 
166    * @param fieldName
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
171    * 
172    * @see PA#getValue(Object,String)
173    */
174   public Object getValue(final String fieldName)
175   {
176     return PA.getValue(instanceOrClass, fieldName);
177   }
178
179   /**
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.
183    * 
184    * @param fromClass
185    *          the class to instantiate an object from
186    * @param arguments
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.
202    * 
203    * @see PrivilegedAccessor#instantiate(Class,Class[],Object[])
204    */
205   public static <T> T instantiate(final Class<? extends T> fromClass,
206           final Class<?>[] argumentTypes, final Object... arguments)
207   {
208     try
209     {
210       return PrivilegedAccessor.instantiate(fromClass, argumentTypes,
211               correctVarargs(arguments));
212     } catch (Exception e)
213     {
214       throw new IllegalArgumentException("Can't instantiate class "
215               + fromClass + " with arguments " + arguments, e);
216     }
217   }
218
219   /**
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.
223    * 
224    * @param fromClass
225    *          the class to instantiate an object from
226    * @param arguments
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.
240    * 
241    * @see PrivilegedAccessor#instantiate(Class,Object[])
242    */
243   public static <T> T instantiate(final Class<? extends T> fromClass,
244           final Object... arguments)
245   {
246     try
247     {
248       return PrivilegedAccessor.instantiate(fromClass,
249               correctVarargs(arguments));
250     } catch (Exception e)
251     {
252       throw new IllegalArgumentException("Can't instantiate class "
253               + fromClass + " with arguments " + arguments, e);
254     }
255   }
256
257   /**
258    * Calls a method on the given object instance with the given arguments.
259    * Arguments can be object types or representations for primitives.
260    * 
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)")
266    * @param arguments
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
275    * 
276    * @see PrivilegedAccessor#invokeMethod(Object,String,Object[])
277    */
278   public static Object invokeMethod(final Object instanceOrClass,
279           final String methodSignature, final Object... arguments)
280   {
281     try
282     {
283       return PrivilegedAccessor.invokeMethod(instanceOrClass,
284               methodSignature, correctVarargs(arguments));
285     } catch (Exception e)
286     {
287       throw new IllegalArgumentException(
288               "Can't invoke method " + methodSignature + " on "
289                       + instanceOrClass + " with arguments " + arguments,
290               e);
291     }
292   }
293
294   /**
295    * Calls a method with the given arguments. Arguments can be object types or
296    * representations for primitives.
297    * 
298    * @param methodSignature
299    *          the name of the method and the parameters <br>
300    *          (e.g. "myMethod(java.lang.String, com.company.project.MyObject)")
301    * @param arguments
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...)
311    */
312   public Object invokeMethod(final String methodSignature,
313           final Object... arguments)
314   {
315     return PA.invokeMethod(instanceOrClass, methodSignature, arguments);
316   }
317
318   /**
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.
323    * 
324    * @param arguments
325    *          the possibly converted arguments of a vararg method
326    * @return arguments possibly converted
327    */
328   private static Object[] correctVarargs(final Object... arguments)
329   {
330     if ((arguments == null) || changedByVararg(arguments))
331       return new Object[] { arguments };
332     return arguments;
333   }
334
335   /**
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[]]
340    * 
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
344    * Object[primitive]
345    * 
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
349    * primitive]
350    * 
351    * @param parameters
352    *          the parameters
353    * @return true if parameters were changes by varargs, false otherwise
354    */
355   private static boolean changedByVararg(final Object[] parameters)
356   {
357     if ((parameters.length == 0) || (parameters[0] == null))
358       return false;
359
360     if (parameters.getClass() == Object[].class)
361       return false;
362
363     return true;
364   }
365
366   /**
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/>
372    * <br/>
373    * Example:<br/>
374    * <br/>
375    * <code>
376    * String myString = "Test"; <br/>
377    * <br/>
378    * //setting the private field value<br/>
379    * PrivilegedAccessor.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});<br/>
380    * <br/>
381    * //setting the static final field serialVersionUID - MIGHT FAIL<br/>
382    * PrivilegedAccessor.setValue(myString.getClass(), "serialVersionUID", 1);<br/>
383    * <br/>
384    * </code>
385    * 
386    * @param instanceOrClass
387    *          the instance or class to set the field
388    * @param fieldName
389    *          the name of the field
390    * @param value
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
395    *           field was final
396    * 
397    * @see PrivilegedAccessor.setValue(Object,String,Object)
398    */
399   public static PA setValue(final Object instanceOrClass,
400           final String fieldName, final Object value)
401   {
402     try
403     {
404       PrivilegedAccessor.setValue(instanceOrClass, fieldName, value);
405     } catch (Exception e)
406     {
407       throw new IllegalArgumentException("Can't set value " + value + " at "
408               + fieldName + " in " + instanceOrClass, e);
409     }
410     return new PA(instanceOrClass);
411   }
412
413   /**
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/>
419    * <br/>
420    * Example:<br/>
421    * <br/>
422    * <code>
423    * String myString = "Test"; <br/>
424    * <br/>
425    * //setting the private field value<br/>
426    * PrivilegedAccessor.setValue(myString, "value", new char[] {'T', 'e', 's', 't'});<br/>
427    * <br/>
428    * //setting the static final field serialVersionUID - MIGHT FAIL<br/>
429    * PrivilegedAccessor.setValue(myString.getClass(), "serialVersionUID", 1);<br/>
430    * <br/>
431    * </code>
432    * 
433    * @param fieldName
434    *          the name of the field
435    * @param value
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
440    *           field was final
441    * 
442    * @see PA.setValue(Object,String,Object)
443    */
444   public PA setValue(final String fieldName, final Object value)
445   {
446     PA.setValue(instanceOrClass, fieldName, value);
447     return this;
448   }
449 }