View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
4    */
5   package mockit;
6   
7   import edu.umd.cs.findbugs.annotations.NonNull;
8   import edu.umd.cs.findbugs.annotations.Nullable;
9   
10  import mockit.internal.reflection.FieldReflection;
11  import mockit.internal.reflection.MethodReflection;
12  import mockit.internal.util.ClassLoad;
13  
14  /**
15   * Provides utility methods that enable access to ("de-encapsulate") otherwise non-accessible fields.
16   *
17   * @see #getField(Object, String)
18   * @see #setField(Object, String, Object)
19   */
20  public final class Deencapsulation {
21      private Deencapsulation() {
22      }
23  
24      /**
25       * Gets the value of a non-accessible (eg <code>private</code>) field from a given object.
26       *
27       * @param <T>
28       *            interface or class type to which the returned value should be assignable
29       * @param objectWithField
30       *            the instance from which to get the field value
31       * @param fieldName
32       *            the name of the field to get
33       *
34       * @return the field
35       *
36       * @throws IllegalArgumentException
37       *             if the desired field is not found
38       *
39       * @see #getField(Object, Class)
40       * @see #getField(Class, String)
41       * @see #setField(Object, String, Object)
42       */
43      @Nullable
44      public static <T> T getField(@NonNull Object objectWithField, @NonNull String fieldName) {
45          return FieldReflection.getField(objectWithField.getClass(), fieldName, objectWithField);
46      }
47  
48      /**
49       * Gets the value of a non-accessible (eg <code>private</code>) field from a given object, <em>assuming</em> there
50       * is only one field declared in the class of the given object whose type can receive values of the specified field
51       * type.
52       *
53       * @param <T>
54       *            the generic type
55       * @param objectWithField
56       *            the instance from which to get the field value
57       * @param fieldType
58       *            the declared type of the field, or a sub-type of the declared field type
59       *
60       * @return the field
61       *
62       * @throws IllegalArgumentException
63       *             if either the desired field is not found, or more than one is
64       *
65       * @see #getField(Object, String)
66       * @see #getField(Class, String)
67       * @see #setField(Object, Object)
68       */
69      @Nullable
70      public static <T> T getField(@NonNull Object objectWithField, @NonNull Class<T> fieldType) {
71          return FieldReflection.getField(objectWithField.getClass(), fieldType, objectWithField);
72      }
73  
74      /**
75       * Gets the value of a non-accessible static field defined in a given class.
76       *
77       * @param <T>
78       *            interface or class type to which the returned value should be assignable
79       * @param classWithStaticField
80       *            the class from which to get the field value
81       * @param fieldName
82       *            the name of the static field to get
83       *
84       * @return the field
85       *
86       * @throws IllegalArgumentException
87       *             if the desired field is not found
88       *
89       * @see #getField(Class, Class)
90       * @see #getField(Object, String)
91       * @see #setField(Class, String, Object)
92       */
93      @Nullable
94      public static <T> T getField(@NonNull Class<?> classWithStaticField, @NonNull String fieldName) {
95          return FieldReflection.getField(classWithStaticField, fieldName, null);
96      }
97  
98      /**
99       * Gets the value of a non-accessible static field defined in a given class, <em>assuming</em> there is only one
100      * field declared in the given class whose type can receive values of the specified field type.
101      *
102      * @param <T>
103      *            interface or class type to which the returned value should be assignable
104      * @param classWithStaticField
105      *            the class from which to get the field value
106      * @param fieldType
107      *            the declared type of the field, or a sub-type of the declared field type
108      *
109      * @return the field
110      *
111      * @throws IllegalArgumentException
112      *             if either the desired field is not found, or more than one is
113      *
114      * @see #getField(Class, String)
115      * @see #getField(Object, Class)
116      * @see #setField(Class, Object)
117      */
118     @Nullable
119     public static <T> T getField(@NonNull Class<?> classWithStaticField, @NonNull Class<T> fieldType) {
120         return FieldReflection.getField(classWithStaticField, fieldType, null);
121     }
122 
123     /**
124      * Sets the value of a non-accessible field on a given object.
125      *
126      * @param objectWithField
127      *            the instance on which to set the field value
128      * @param fieldName
129      *            the name of the field to set
130      * @param fieldValue
131      *            the value to set the field to
132      *
133      * @throws IllegalArgumentException
134      *             if the desired field is not found
135      *
136      * @see #setField(Class, String, Object)
137      * @see #setField(Object, Object)
138      * @see #getField(Object, String)
139      */
140     public static void setField(@NonNull Object objectWithField, @NonNull String fieldName,
141             @Nullable Object fieldValue) {
142         FieldReflection.setField(objectWithField.getClass(), objectWithField, fieldName, fieldValue);
143     }
144 
145     /**
146      * Sets the value of a non-accessible field on a given object. The field is looked up by the type of the given field
147      * value instead of by name.
148      *
149      * @param objectWithField
150      *            the object with field
151      * @param fieldValue
152      *            the field value
153      *
154      * @throws IllegalArgumentException
155      *             if either the desired field is not found, or more than one is
156      *
157      * @see #setField(Object, String, Object)
158      * @see #setField(Class, String, Object)
159      * @see #getField(Object, String)
160      */
161     public static void setField(@NonNull Object objectWithField, @NonNull Object fieldValue) {
162         FieldReflection.setField(objectWithField.getClass(), objectWithField, null, fieldValue);
163     }
164 
165     /**
166      * Sets the value of a non-accessible static field on a given class.
167      *
168      * @param classWithStaticField
169      *            the class on which the static field is defined
170      * @param fieldName
171      *            the name of the field to set
172      * @param fieldValue
173      *            the value to set the field to
174      *
175      * @throws IllegalArgumentException
176      *             if the desired field is not found
177      *
178      * @see #setField(Class, Object)
179      * @see #setField(Object, String, Object)
180      * @see #getField(Class, String)
181      */
182     public static void setField(@NonNull Class<?> classWithStaticField, @NonNull String fieldName,
183             @Nullable Object fieldValue) {
184         FieldReflection.setField(classWithStaticField, null, fieldName, fieldValue);
185     }
186 
187     /**
188      * Sets the value of a non-accessible static field on a given class. The field is looked up by the type of the given
189      * field value instead of by name.
190      *
191      * @param classWithStaticField
192      *            the class on which the static field is defined
193      * @param fieldValue
194      *            the value to set the field to
195      *
196      * @throws IllegalArgumentException
197      *             if either the desired field is not found, or more than one is
198      *
199      * @see #setField(Class, String, Object)
200      * @see #setField(Object, Object)
201      * @see #getField(Class, Class)
202      */
203     public static void setField(@NonNull Class<?> classWithStaticField, @NonNull Object fieldValue) {
204         FieldReflection.setField(classWithStaticField, null, null, fieldValue);
205     }
206 
207     /**
208      * Invokes a non-accessible (eg {@code private}) instance method from a given class with the given arguments.
209      *
210      * @param <T>
211      *            type to which the returned value should be assignable
212      * @param objectWithMethod
213      *            the instance on which the invocation is to be done
214      * @param methodName
215      *            the name of the method to invoke
216      * @param parameterTypes
217      *            the types of the parameters as declared in the desired method
218      * @param methodArgs
219      *            zero or more parameter values for the invocation
220      *
221      * @return the return value from the invoked method
222      *
223      * @throws IllegalArgumentException
224      *             if the desired method is not found
225      *
226      * @see #invoke(Class, String, Object...)
227      */
228     public static <T> T invoke(Object objectWithMethod, String methodName, Class<?>[] parameterTypes,
229             Object... methodArgs) {
230         Class<?> theClass = objectWithMethod.getClass();
231         return MethodReflection.invoke(theClass, objectWithMethod, methodName, parameterTypes, methodArgs);
232     }
233 
234     /**
235      * Invokes a non-accessible (eg {@code private}) instance method from a given class with the given arguments.
236      *
237      * @param <T>
238      *            type to which the returned value should be assignable
239      * @param objectWithMethod
240      *            the instance on which the invocation is to be done
241      * @param methodName
242      *            the name of the method to invoke
243      * @param nonNullArgs
244      *            zero or more non-null parameter values for the invocation; if a null value needs to be passed, the
245      *            {@code Class} object for the corresponding parameter type must be passed instead
246      *
247      * @return the return value from the invoked method
248      *
249      * @throws IllegalArgumentException
250      *             if the desired method is not found, or a null reference was provided for a parameter
251      *
252      * @see #invoke(Class, String, Object...)
253      */
254     public static <T> T invoke(Object objectWithMethod, String methodName, Object... nonNullArgs) {
255         Class<?> theClass = objectWithMethod.getClass();
256         return MethodReflection.invoke(theClass, objectWithMethod, methodName, nonNullArgs);
257     }
258 
259     /**
260      * Invokes a non-accessible (eg {@code private}) {@code static} method with the given arguments.
261      *
262      * @param <T>
263      *            type to which the returned value should be assignable
264      * @param classWithStaticMethod
265      *            the class on which the invocation is to be done
266      * @param methodName
267      *            the name of the static method to invoke
268      * @param parameterTypes
269      *            the types of the parameters as declared in the desired method
270      * @param methodArgs
271      *            zero or more parameter values for the invocation
272      *
273      * @return the return value from the invoked method
274      *
275      * @see #invoke(String, String, Object...)
276      */
277     public static <T> T invoke(Class<?> classWithStaticMethod, String methodName, Class<?>[] parameterTypes,
278             Object... methodArgs) {
279         return MethodReflection.invoke(classWithStaticMethod, null, methodName, parameterTypes, methodArgs);
280     }
281 
282     /**
283      * Invokes a non-accessible (eg {@code private}) {@code static} method with the given arguments.
284      *
285      * @param <T>
286      *            type to which the returned value should be assignable
287      * @param classWithStaticMethod
288      *            the class on which the invocation is to be done
289      * @param methodName
290      *            the name of the static method to invoke
291      * @param nonNullArgs
292      *            zero or more non-null parameter values for the invocation; if a null value needs to be passed, the
293      *            {@code Class} object for the corresponding parameter type must be passed instead
294      *
295      * @return the return value from the invoked method
296      *
297      * @throws IllegalArgumentException
298      *             if the desired method is not found, or a null reference was provided for a parameter
299      *
300      * @see #invoke(String, String, Object...)
301      */
302     public static <T> T invoke(Class<?> classWithStaticMethod, String methodName, Object... nonNullArgs) {
303         return MethodReflection.invoke(classWithStaticMethod, null, methodName, nonNullArgs);
304     }
305 
306     /**
307      * Invokes a non-accessible (eg {@code private}) {@code static} method with the given arguments.
308      *
309      * @param <T>
310      *            type to which the returned value should be assignable
311      * @param classWithStaticMethod
312      *            the (fully qualified) name of the class on which the invocation is to be done; must not be null
313      * @param methodName
314      *            the name of the static method to invoke
315      * @param nonNullArgs
316      *            zero or more non-null parameter values for the invocation; if a null value needs to be passed, the
317      *            {@code Class} object for the corresponding parameter type must be passed instead
318      *
319      * @return the return value from the invoked method
320      *
321      * @throws IllegalArgumentException
322      *             if the desired method is not found, or a null reference was provided for a parameter
323      *
324      * @see #invoke(Class, String, Object...)
325      */
326     public static <T> T invoke(String classWithStaticMethod, String methodName, Object... nonNullArgs) {
327         Class<Object> theClass = ClassLoad.loadClass(classWithStaticMethod);
328         return MethodReflection.invoke(theClass, null, methodName, nonNullArgs);
329     }
330 }