View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.reflect;
18  
19  import java.lang.annotation.Annotation;
20  import java.lang.reflect.Field;
21  import java.lang.reflect.Modifier;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Objects;
26  import java.util.stream.Collectors;
27  
28  import org.apache.commons.lang3.ArrayUtils;
29  import org.apache.commons.lang3.ClassUtils;
30  import org.apache.commons.lang3.JavaVersion;
31  import org.apache.commons.lang3.StringUtils;
32  import org.apache.commons.lang3.SystemUtils;
33  import org.apache.commons.lang3.Validate;
34  
35  /**
36   * Utilities for working with {@link Field}s by reflection. Adapted and refactored from the dormant [reflect] Commons
37   * sandbox component.
38   * <p>
39   * The ability is provided to break the scoping restrictions coded by the programmer. This can allow fields to be
40   * changed that shouldn't be. This facility should be used with care.
41   * </p>
42   * @since 2.5
43   */
44  public class FieldUtils {
45  
46      /**
47       * Gets all fields of the given class and its parents (if any).
48       *
49       * @param cls
50       *            the {@link Class} to query
51       * @return an array of Fields (possibly empty).
52       * @throws NullPointerException
53       *             if the class is {@code null}
54       * @since 3.2
55       */
56      public static Field[] getAllFields(final Class<?> cls) {
57          return getAllFieldsList(cls).toArray(ArrayUtils.EMPTY_FIELD_ARRAY);
58      }
59  
60      /**
61       * Gets all fields of the given class and its parents (if any).
62       *
63       * @param cls
64       *            the {@link Class} to query
65       * @return a list of Fields (possibly empty).
66       * @throws NullPointerException
67       *             if the class is {@code null}
68       * @since 3.2
69       */
70      public static List<Field> getAllFieldsList(final Class<?> cls) {
71          Objects.requireNonNull(cls, "cls");
72          final List<Field> allFields = new ArrayList<>();
73          Class<?> currentClass = cls;
74          while (currentClass != null) {
75              final Field[] declaredFields = currentClass.getDeclaredFields();
76              Collections.addAll(allFields, declaredFields);
77              currentClass = currentClass.getSuperclass();
78          }
79          return allFields;
80      }
81  
82      /**
83       * Gets an accessible {@link Field} by name respecting scope. Only the specified class will be considered.
84       *
85       * @param cls
86       *            the {@link Class} to reflect, must not be {@code null}
87       * @param fieldName
88       *            the field name to obtain
89       * @return the Field object
90       * @throws NullPointerException
91       *             if the class is {@code null}
92       * @throws IllegalArgumentException
93       *             if the field name is {@code null}, blank, or empty
94       */
95      public static Field getDeclaredField(final Class<?> cls, final String fieldName) {
96          return getDeclaredField(cls, fieldName, false);
97      }
98  
99      /**
100      * Gets an accessible {@link Field} by name, breaking scope if requested. Only the specified class will be
101      * considered.
102      *
103      * @param cls
104      *            the {@link Class} to reflect, must not be {@code null}
105      * @param fieldName
106      *            the field name to obtain
107      * @param forceAccess
108      *            whether to break scope restrictions using the
109      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
110      *            match {@code public} fields.
111      * @return the Field object
112      * @throws NullPointerException
113      *             if the class is {@code null}
114      * @throws IllegalArgumentException
115      *             if the field name is {@code null}, blank, or empty
116      */
117     public static Field getDeclaredField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
118         Objects.requireNonNull(cls, "cls");
119         Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
120         try {
121             // only consider the specified class by using getDeclaredField()
122             final Field field = cls.getDeclaredField(fieldName);
123             if (!MemberUtils.isAccessible(field)) {
124                 if (!forceAccess) {
125                     return null;
126                 }
127                 field.setAccessible(true);
128             }
129             return field;
130         } catch (final NoSuchFieldException ignored) {
131             // ignore
132         }
133         return null;
134     }
135 
136     /**
137      * Gets an accessible {@link Field} by name respecting scope. Superclasses/interfaces will be considered.
138      *
139      * @param cls
140      *            the {@link Class} to reflect, must not be {@code null}
141      * @param fieldName
142      *            the field name to obtain
143      * @return the Field object
144      * @throws NullPointerException
145      *             if the class is {@code null}
146      * @throws IllegalArgumentException
147      *             if the field name is {@code null}, blank, or empty
148      */
149     public static Field getField(final Class<?> cls, final String fieldName) {
150         return MemberUtils.setAccessibleWorkaround(getField(cls, fieldName, false));
151     }
152 
153     /**
154      * Gets an accessible {@link Field} by name, breaking scope if requested. Superclasses/interfaces will be
155      * considered.
156      *
157      * @param cls
158      *            the {@link Class} to reflect, must not be {@code null}
159      * @param fieldName
160      *            the field name to obtain
161      * @param forceAccess
162      *            whether to break scope restrictions using the
163      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
164      *            match {@code public} fields.
165      * @return the Field object
166      * @throws NullPointerException if the class is {@code null}
167      * @throws IllegalArgumentException if the field name is blank or empty or is matched at multiple places
168      * in the inheritance hierarchy
169      */
170     public static Field getField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
171         Objects.requireNonNull(cls, "cls");
172         Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
173         // FIXME is this workaround still needed? lang requires Java 6
174         // Sun Java 1.3 has a bugged implementation of getField hence we write the
175         // code ourselves
176 
177         // getField() will return the Field object with the declaring class
178         // set correctly to the class that declares the field. Thus requesting the
179         // field on a subclass will return the field from the superclass.
180         //
181         // priority order for lookup:
182         // searchclass private/protected/package/public
183         // superclass protected/package/public
184         // private/different package blocks access to further superclasses
185         // implementedinterface public
186 
187         // check up the superclass hierarchy
188         for (Class<?> acls = cls; acls != null; acls = acls.getSuperclass()) {
189             try {
190                 final Field field = acls.getDeclaredField(fieldName);
191                 // getDeclaredField checks for non-public scopes as well
192                 // and it returns accurate results
193                 if (!MemberUtils.isPublic(field)) {
194                     if (!forceAccess) {
195                         continue;
196                     }
197                     field.setAccessible(true);
198                 }
199                 return field;
200             } catch (final NoSuchFieldException ignored) {
201                 // ignore
202             }
203         }
204         // check the public interface case. This must be manually searched for
205         // incase there is a public supersuperclass field hidden by a private/package
206         // superclass field.
207         Field match = null;
208         for (final Class<?> class1 : ClassUtils.getAllInterfaces(cls)) {
209             try {
210                 final Field test = class1.getField(fieldName);
211                 Validate.isTrue(match == null, "Reference to field %s is ambiguous relative to %s"
212                         + "; a matching field exists on two or more implemented interfaces.", fieldName, cls);
213                 match = test;
214             } catch (final NoSuchFieldException ignored) {
215                 // ignore
216             }
217         }
218         return match;
219     }
220 
221     /**
222      * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
223      * @param cls
224      *            the {@link Class} to query
225      * @param annotationCls
226      *            the {@link Annotation} that must be present on a field to be matched
227      * @return a list of Fields (possibly empty).
228      * @throws NullPointerException
229      *            if the class or annotation are {@code null}
230      * @since 3.4
231      */
232     public static List<Field> getFieldsListWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
233         Objects.requireNonNull(annotationCls, "annotationCls");
234         return getAllFieldsList(cls).stream().filter(field -> field.getAnnotation(annotationCls) != null).collect(Collectors.toList());
235     }
236 
237     /**
238      * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
239      * @param cls
240      *            the {@link Class} to query
241      * @param annotationCls
242      *            the {@link Annotation} that must be present on a field to be matched
243      * @return an array of Fields (possibly empty).
244      * @throws NullPointerException
245      *            if the class or annotation are {@code null}
246      * @since 3.4
247      */
248     public static Field[] getFieldsWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
249         return getFieldsListWithAnnotation(cls, annotationCls).toArray(ArrayUtils.EMPTY_FIELD_ARRAY);
250     }
251 
252     /**
253      * Reads the named {@code public} {@link Field}. Only the class of the specified object will be considered.
254      *
255      * @param target
256      *            the object to reflect, must not be {@code null}
257      * @param fieldName
258      *            the field name to obtain
259      * @return the value of the field
260      * @throws NullPointerException
261      *             if {@code target} is {@code null}
262      * @throws IllegalArgumentException
263      *             if {@code fieldName} is {@code null}, blank or empty, or could not be found
264      * @throws IllegalAccessException
265      *             if the named field is not {@code public}
266      */
267     public static Object readDeclaredField(final Object target, final String fieldName) throws IllegalAccessException {
268         return readDeclaredField(target, fieldName, false);
269     }
270 
271     /**
272      * Gets a {@link Field} value by name. Only the class of the specified object will be considered.
273      *
274      * @param target
275      *            the object to reflect, must not be {@code null}
276      * @param fieldName
277      *            the field name to obtain
278      * @param forceAccess
279      *            whether to break scope restrictions using the
280      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
281      *            match public fields.
282      * @return the Field object
283      * @throws NullPointerException
284      *             if {@code target} is {@code null}
285      * @throws IllegalArgumentException
286      *             if {@code fieldName} is {@code null}, blank or empty, or could not be found
287      * @throws IllegalAccessException
288      *             if the field is not made accessible
289      */
290     public static Object readDeclaredField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
291         Objects.requireNonNull(target, "target");
292         final Class<?> cls = target.getClass();
293         final Field field = getDeclaredField(cls, fieldName, forceAccess);
294         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls, fieldName);
295         // already forced access above, don't repeat it here:
296         return readField(field, target, false);
297     }
298 
299     /**
300      * Gets the value of a {@code static} {@link Field} by name. The field must be {@code public}. Only the specified
301      * class will be considered.
302      *
303      * @param cls
304      *            the {@link Class} to reflect, must not be {@code null}
305      * @param fieldName
306      *            the field name to obtain
307      * @return the value of the field
308      * @throws NullPointerException
309      *             if the class is {@code null}, or the field could not be found
310      * @throws IllegalArgumentException
311      *             if the field name is {@code null}, blank, empty, or is not {@code static}
312      * @throws IllegalAccessException
313      *             if the field is not accessible
314      */
315     public static Object readDeclaredStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
316         return readDeclaredStaticField(cls, fieldName, false);
317     }
318 
319     /**
320      * Gets the value of a {@code static} {@link Field} by name. Only the specified class will be considered.
321      *
322      * @param cls
323      *            the {@link Class} to reflect, must not be {@code null}
324      * @param fieldName
325      *            the field name to obtain
326      * @param forceAccess
327      *            whether to break scope restrictions using the
328      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
329      *            match {@code public} fields.
330      * @return the Field object
331      * @throws NullPointerException
332      *             if the class is {@code null}, or the field could not be found
333      * @throws IllegalArgumentException
334      *             if the field name is blank or empty, is not {@code static}
335      * @throws IllegalAccessException
336      *             if the field is not made accessible
337      */
338     public static Object readDeclaredStaticField(final Class<?> cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
339         final Field field = getDeclaredField(cls, fieldName, forceAccess);
340         Validate.notNull(field, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
341         // already forced access above, don't repeat it here:
342         return readStaticField(field, false);
343     }
344 
345     /**
346      * Reads an accessible {@link Field}.
347      *
348      * @param field
349      *            the field to use
350      * @param target
351      *            the object to call on, may be {@code null} for {@code static} fields
352      * @return the field value
353      * @throws NullPointerException
354      *             if the field is {@code null}
355      * @throws IllegalAccessException
356      *             if the field is not accessible
357      */
358     public static Object readField(final Field field, final Object target) throws IllegalAccessException {
359         return readField(field, target, false);
360     }
361 
362     /**
363      * Reads a {@link Field}.
364      *
365      * @param field
366      *            the field to use
367      * @param target
368      *            the object to call on, may be {@code null} for {@code static} fields
369      * @param forceAccess
370      *            whether to break scope restrictions using the
371      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
372      * @return the field value
373      * @throws NullPointerException
374      *             if the field is {@code null}
375      * @throws IllegalAccessException
376      *             if the field is not made accessible
377      */
378     public static Object readField(final Field field, final Object target, final boolean forceAccess) throws IllegalAccessException {
379         Objects.requireNonNull(field, "field");
380         if (forceAccess && !field.isAccessible()) {
381             field.setAccessible(true);
382         } else {
383             MemberUtils.setAccessibleWorkaround(field);
384         }
385         return field.get(target);
386     }
387 
388     /**
389      * Reads the named {@code public} {@link Field}. Superclasses will be considered.
390      *
391      * @param target
392      *            the object to reflect, must not be {@code null}
393      * @param fieldName
394      *            the field name to obtain
395      * @return the value of the field
396      * @throws NullPointerException
397      *             if the target is {@code null}
398      * @throws IllegalArgumentException
399      *             if the field name is {@code null}, blank, empty, or could not be found
400      * @throws IllegalAccessException
401      *             if the named field is not {@code public}
402      */
403     public static Object readField(final Object target, final String fieldName) throws IllegalAccessException {
404         return readField(target, fieldName, false);
405     }
406 
407     /**
408      * Reads the named {@link Field}. Superclasses will be considered.
409      *
410      * @param target
411      *            the object to reflect, must not be {@code null}
412      * @param fieldName
413      *            the field name to obtain
414      * @param forceAccess
415      *            whether to break scope restrictions using the
416      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
417      *            match {@code public} fields.
418      * @return the field value
419      * @throws NullPointerException
420      *             if {@code target} is {@code null}
421      * @throws IllegalArgumentException
422      *             if the field name is {@code null}, blank, empty, or could not be found
423      * @throws IllegalAccessException
424      *             if the named field is not made accessible
425      */
426     public static Object readField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
427         Objects.requireNonNull(target, "target");
428         final Class<?> cls = target.getClass();
429         final Field field = getField(cls, fieldName, forceAccess);
430         Validate.isTrue(field != null, "Cannot locate field %s on %s", fieldName, cls);
431         // already forced access above, don't repeat it here:
432         return readField(field, target, false);
433     }
434 
435     /**
436      * Reads the named {@code public static} {@link Field}. Superclasses will be considered.
437      *
438      * @param cls
439      *            the {@link Class} to reflect, must not be {@code null}
440      * @param fieldName
441      *            the field name to obtain
442      * @return the value of the field
443      * @throws NullPointerException
444      *             if the class is {@code null}, or the field could not be found
445      * @throws IllegalArgumentException
446      *             if the field name is {@code null}, blank or empty, or is not {@code static}
447      * @throws IllegalAccessException
448      *             if the field is not accessible
449      */
450     public static Object readStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
451         return readStaticField(cls, fieldName, false);
452     }
453 
454     /**
455      * Reads the named {@code static} {@link Field}. Superclasses will be considered.
456      *
457      * @param cls
458      *            the {@link Class} to reflect, must not be {@code null}
459      * @param fieldName
460      *            the field name to obtain
461      * @param forceAccess
462      *            whether to break scope restrictions using the
463      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
464      *            match {@code public} fields.
465      * @return the Field object
466      * @throws NullPointerException
467      *             if the class is {@code null}, or the field could not be found
468      * @throws IllegalArgumentException
469      *             if the field name is {@code null}, blank or empty, or is not {@code static}
470      * @throws IllegalAccessException
471      *             if the field is not made accessible
472      */
473     public static Object readStaticField(final Class<?> cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
474         final Field field = getField(cls, fieldName, forceAccess);
475         Validate.notNull(field, "Cannot locate field '%s' on %s", fieldName, cls);
476         // already forced access above, don't repeat it here:
477         return readStaticField(field, false);
478     }
479 
480     /**
481      * Reads an accessible {@code static} {@link Field}.
482      *
483      * @param field
484      *            to read
485      * @return the field value
486      * @throws NullPointerException
487      *             if the field is {@code null}
488      * @throws IllegalArgumentException
489      *             if the field is not {@code static}
490      * @throws IllegalAccessException
491      *             if the field is not accessible
492      */
493     public static Object readStaticField(final Field field) throws IllegalAccessException {
494         return readStaticField(field, false);
495     }
496 
497     /**
498      * Reads a static {@link Field}.
499      *
500      * @param field
501      *            to read
502      * @param forceAccess
503      *            whether to break scope restrictions using the
504      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
505      * @return the field value
506      * @throws NullPointerException
507      *             if the field is {@code null}
508      * @throws IllegalArgumentException
509      *             if the field is not {@code static}
510      * @throws IllegalAccessException
511      *             if the field is not made accessible
512      */
513     public static Object readStaticField(final Field field, final boolean forceAccess) throws IllegalAccessException {
514         Objects.requireNonNull(field, "field");
515         Validate.isTrue(MemberUtils.isStatic(field), "The field '%s' is not static", field.getName());
516         return readField(field, (Object) null, forceAccess);
517     }
518 
519     /**
520      * Removes the final modifier from a {@link Field}.
521      *
522      * @param field
523      *            to remove the final modifier
524      * @throws NullPointerException
525      *             if the field is {@code null}
526      * @since 3.2
527      */
528     public static void removeFinalModifier(final Field field) {
529         removeFinalModifier(field, true);
530     }
531 
532     /**
533      * Removes the final modifier from a {@link Field}.
534      *
535      * @param field
536      *            to remove the final modifier
537      * @param forceAccess
538      *            whether to break scope restrictions using the
539      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
540      *            match {@code public} fields.
541      * @throws NullPointerException
542      *             if the field is {@code null}
543      * @deprecated As of Java 12, we can no longer drop the {@code final} modifier, thus
544      *             rendering this method obsolete. The JDK discussion about this change can be found
545      *             here: https://mail.openjdk.java.net/pipermail/core-libs-dev/2018-November/056486.html
546      * @since 3.3
547      */
548     @Deprecated
549     public static void removeFinalModifier(final Field field, final boolean forceAccess) {
550         Objects.requireNonNull(field, "field");
551 
552         try {
553             if (Modifier.isFinal(field.getModifiers())) {
554                 // Do all JREs implement Field with a private ivar called "modifiers"?
555                 final Field modifiersField = Field.class.getDeclaredField("modifiers");
556                 final boolean doForceAccess = forceAccess && !modifiersField.isAccessible();
557                 if (doForceAccess) {
558                     modifiersField.setAccessible(true);
559                 }
560                 try {
561                     modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
562                 } finally {
563                     if (doForceAccess) {
564                         modifiersField.setAccessible(false);
565                     }
566                 }
567             }
568         } catch (final NoSuchFieldException | IllegalAccessException e) {
569             if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_12)) {
570               throw new UnsupportedOperationException(
571                   "In java 12+ final cannot be removed.",
572                   e
573               );
574             }
575             // else no exception is thrown because we can modify final.
576         }
577     }
578 
579     /**
580      * Writes a {@code public} {@link Field}. Only the specified class will be considered.
581      *
582      * @param target
583      *            the object to reflect, must not be {@code null}
584      * @param fieldName
585      *            the field name to obtain
586      * @param value
587      *            to set
588      * @throws NullPointerException
589      *             if {@code target} is {@code null}
590      * @throws IllegalArgumentException
591      *             if {@code fieldName} is {@code null}, blank or empty, or could not be found,
592      *             or {@code value} is not assignable
593      * @throws IllegalAccessException
594      *             if the field is not made accessible
595      */
596     public static void writeDeclaredField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
597         writeDeclaredField(target, fieldName, value, false);
598     }
599 
600     /**
601      * Writes a {@code public} {@link Field}. Only the specified class will be considered.
602      *
603      * @param target
604      *            the object to reflect, must not be {@code null}
605      * @param fieldName
606      *            the field name to obtain
607      * @param value
608      *            to set
609      * @param forceAccess
610      *            whether to break scope restrictions using the
611      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
612      *            match {@code public} fields.
613      * @throws IllegalArgumentException
614      *             if {@code fieldName} is {@code null}, blank or empty, or could not be found,
615      *             or {@code value} is not assignable
616      * @throws IllegalAccessException
617      *             if the field is not made accessible
618      */
619     public static void writeDeclaredField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
620             throws IllegalAccessException {
621         Objects.requireNonNull(target, "target");
622         final Class<?> cls = target.getClass();
623         final Field field = getDeclaredField(cls, fieldName, forceAccess);
624         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
625         // already forced access above, don't repeat it here:
626         writeField(field, target, value, false);
627     }
628 
629     /**
630      * Writes a named {@code public static} {@link Field}. Only the specified class will be considered.
631      *
632      * @param cls
633      *            {@link Class} on which the field is to be found
634      * @param fieldName
635      *            to write
636      * @param value
637      *            to set
638      * @throws NullPointerException
639      *             if {@code cls} is {@code null} or the field cannot be located
640      * @throws IllegalArgumentException
641      *             if the field name is {@code null}, blank, empty, not {@code static}, or {@code value} is not assignable
642      * @throws IllegalAccessException
643      *             if the field is not {@code public} or is {@code final}
644      */
645     public static void writeDeclaredStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
646         writeDeclaredStaticField(cls, fieldName, value, false);
647     }
648 
649     /**
650      * Writes a named {@code static} {@link Field}. Only the specified class will be considered.
651      *
652      * @param cls
653      *            {@link Class} on which the field is to be found
654      * @param fieldName
655      *            to write
656      * @param value
657      *            to set
658      * @param forceAccess
659      *            whether to break scope restrictions using the {@code AccessibleObject#setAccessible(boolean)} method.
660      *            {@code false} will only match {@code public} fields.
661      * @throws NullPointerException
662      *             if {@code cls} is {@code null} or the field cannot be located
663      * @throws IllegalArgumentException
664      *             if the field name is {@code null}, blank, empty, not {@code static}, or {@code value} is not assignable
665      * @throws IllegalAccessException
666      *             if the field is not made accessible or is {@code final}
667      */
668     public static void writeDeclaredStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
669             throws IllegalAccessException {
670         final Field field = getDeclaredField(cls, fieldName, forceAccess);
671         Validate.notNull(field, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
672         // already forced access above, don't repeat it here:
673         writeField(field, (Object) null, value, false);
674     }
675 
676     /**
677      * Writes an accessible {@link Field}.
678      *
679      * @param field
680      *            to write
681      * @param target
682      *            the object to call on, may be {@code null} for {@code static} fields
683      * @param value
684      *            to set
685      * @throws NullPointerException
686      *             if the field is {@code null}
687      * @throws IllegalArgumentException
688      *             if {@code value} is not assignable
689      * @throws IllegalAccessException
690      *             if the field is not accessible or is {@code final}
691      */
692     public static void writeField(final Field field, final Object target, final Object value) throws IllegalAccessException {
693         writeField(field, target, value, false);
694     }
695 
696     /**
697      * Writes a {@link Field}.
698      *
699      * @param field
700      *            to write
701      * @param target
702      *            the object to call on, may be {@code null} for {@code static} fields
703      * @param value
704      *            to set
705      * @param forceAccess
706      *            whether to break scope restrictions using the
707      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
708      *            match {@code public} fields.
709      * @throws NullPointerException
710      *             if the field is {@code null}
711      * @throws IllegalArgumentException
712      *             if {@code value} is not assignable
713      * @throws IllegalAccessException
714      *             if the field is not made accessible or is {@code final}
715      */
716     public static void writeField(final Field field, final Object target, final Object value, final boolean forceAccess)
717             throws IllegalAccessException {
718         Objects.requireNonNull(field, "field");
719         if (forceAccess && !field.isAccessible()) {
720             field.setAccessible(true);
721         } else {
722             MemberUtils.setAccessibleWorkaround(field);
723         }
724         field.set(target, value);
725     }
726 
727     /**
728      * Writes a {@code public} {@link Field}. Superclasses will be considered.
729      *
730      * @param target
731      *            the object to reflect, must not be {@code null}
732      * @param fieldName
733      *            the field name to obtain
734      * @param value
735      *            to set
736      * @throws NullPointerException
737      *             if {@code target} is {@code null}
738      * @throws IllegalArgumentException
739      *             if {@code fieldName} is {@code null}, blank, empty, or could not be found,
740      *             or {@code value} is not assignable
741      * @throws IllegalAccessException
742      *             if the field is not accessible
743      */
744     public static void writeField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
745         writeField(target, fieldName, value, false);
746     }
747 
748     /**
749      * Writes a {@link Field}. Superclasses will be considered.
750      *
751      * @param target
752      *            the object to reflect, must not be {@code null}
753      * @param fieldName
754      *            the field name to obtain
755      * @param value
756      *            to set
757      * @param forceAccess
758      *            whether to break scope restrictions using the
759      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
760      *            match {@code public} fields.
761      * @throws NullPointerException
762      *             if {@code target} is {@code null}
763      * @throws IllegalArgumentException
764      *             if {@code fieldName} is {@code null}, blank, empty, or could not be found,
765      *             or {@code value} is not assignable
766      * @throws IllegalAccessException
767      *             if the field is not made accessible
768      */
769     public static void writeField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
770             throws IllegalAccessException {
771         Objects.requireNonNull(target, "target");
772         final Class<?> cls = target.getClass();
773         final Field field = getField(cls, fieldName, forceAccess);
774         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
775         // already forced access above, don't repeat it here:
776         writeField(field, target, value, false);
777     }
778 
779     /**
780      * Writes a named {@code public static} {@link Field}. Superclasses will be considered.
781      *
782      * @param cls
783      *            {@link Class} on which the field is to be found
784      * @param fieldName
785      *            to write
786      * @param value
787      *            to set
788      * @throws NullPointerException
789      *             if {@code target} is {@code null}
790      * @throws IllegalArgumentException
791      *             if {@code fieldName} is {@code null}, blank or empty, the field cannot be located or is
792      *             not {@code static}, or {@code value} is not assignable
793      * @throws IllegalAccessException
794      *             if the field is not {@code public} or is {@code final}
795      */
796     public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
797         writeStaticField(cls, fieldName, value, false);
798     }
799 
800     /**
801      * Writes a named {@code static} {@link Field}. Superclasses will be considered.
802      *
803      * @param cls
804      *            {@link Class} on which the field is to be found
805      * @param fieldName
806      *            to write
807      * @param value
808      *            to set
809      * @param forceAccess
810      *            whether to break scope restrictions using the
811      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
812      *            match {@code public} fields.
813      * @throws NullPointerException
814      *             if {@code cls} is {@code null} or the field cannot be located
815      * @throws IllegalArgumentException
816      *             if {@code fieldName} is {@code null}, blank or empty, the field not {@code static}, or {@code value} is not assignable
817      * @throws IllegalAccessException
818      *             if the field is not made accessible or is {@code final}
819      */
820     public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
821             throws IllegalAccessException {
822         final Field field = getField(cls, fieldName, forceAccess);
823         Validate.notNull(field, "Cannot locate field %s on %s", fieldName, cls);
824         // already forced access above, don't repeat it here:
825         writeStaticField(field, value, false);
826     }
827 
828     /**
829      * Writes a {@code public static} {@link Field}.
830      *
831      * @param field
832      *            to write
833      * @param value
834      *            to set
835      * @throws NullPointerException
836      *              if the field is {@code null}
837      * @throws IllegalArgumentException
838      *              if the field is not {@code static}, or {@code value} is not assignable
839      * @throws IllegalAccessException
840      *             if the field is not {@code public} or is {@code final}
841      */
842     public static void writeStaticField(final Field field, final Object value) throws IllegalAccessException {
843         writeStaticField(field, value, false);
844     }
845 
846     /**
847      * Writes a static {@link Field}.
848      *
849      * @param field
850      *            to write
851      * @param value
852      *            to set
853      * @param forceAccess
854      *            whether to break scope restrictions using the
855      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
856      *            match {@code public} fields.
857      * @throws NullPointerException
858      *              if the field is {@code null}
859      * @throws IllegalArgumentException
860      *              if the field is not {@code static}, or {@code value} is not assignable
861      * @throws IllegalAccessException
862      *             if the field is not made accessible or is {@code final}
863      */
864     public static void writeStaticField(final Field field, final Object value, final boolean forceAccess) throws IllegalAccessException {
865         Objects.requireNonNull(field, "field");
866         Validate.isTrue(MemberUtils.isStatic(field), "The field %s.%s is not static", field.getDeclaringClass().getName(),
867                 field.getName());
868         writeField(field, (Object) null, value, forceAccess);
869     }
870 
871     /**
872      * {@link FieldUtils} instances should NOT be constructed in standard programming.
873      * <p>
874      * This constructor is {@code public} to permit tools that require a JavaBean instance to operate.
875      * </p>
876      */
877     public FieldUtils() {
878     }
879 }