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