001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.reflect;
018
019import java.lang.annotation.Annotation;
020import java.lang.reflect.Field;
021import java.lang.reflect.Modifier;
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.List;
025import java.util.Objects;
026import java.util.stream.Collectors;
027
028import org.apache.commons.lang3.ArrayUtils;
029import org.apache.commons.lang3.ClassUtils;
030import org.apache.commons.lang3.JavaVersion;
031import org.apache.commons.lang3.StringUtils;
032import org.apache.commons.lang3.SystemUtils;
033import org.apache.commons.lang3.Validate;
034
035/**
036 * Utilities for working with {@link Field}s by reflection. Adapted and refactored from the dormant [reflect] Commons
037 * sandbox component.
038 * <p>
039 * The ability is provided to break the scoping restrictions coded by the programmer. This can allow fields to be
040 * changed that shouldn't be. This facility should be used with care.
041 * </p>
042 * @since 2.5
043 */
044public class FieldUtils {
045
046    /**
047     * Gets all fields of the given class and its parents (if any).
048     *
049     * @param cls
050     *            the {@link Class} to query
051     * @return an array of Fields (possibly empty).
052     * @throws NullPointerException
053     *             if the class is {@code null}
054     * @since 3.2
055     */
056    public static Field[] getAllFields(final Class<?> cls) {
057        return getAllFieldsList(cls).toArray(ArrayUtils.EMPTY_FIELD_ARRAY);
058    }
059
060    /**
061     * Gets all fields of the given class and its parents (if any).
062     *
063     * @param cls
064     *            the {@link Class} to query
065     * @return a list of Fields (possibly empty).
066     * @throws NullPointerException
067     *             if the class is {@code null}
068     * @since 3.2
069     */
070    public static List<Field> getAllFieldsList(final Class<?> cls) {
071        Objects.requireNonNull(cls, "cls");
072        final List<Field> allFields = new ArrayList<>();
073        Class<?> currentClass = cls;
074        while (currentClass != null) {
075            final Field[] declaredFields = currentClass.getDeclaredFields();
076            Collections.addAll(allFields, declaredFields);
077            currentClass = currentClass.getSuperclass();
078        }
079        return allFields;
080    }
081
082    /**
083     * Gets an accessible {@link Field} by name respecting scope. Only the specified class will be considered.
084     *
085     * @param cls
086     *            the {@link Class} to reflect, must not be {@code null}
087     * @param fieldName
088     *            the field name to obtain
089     * @return the Field object
090     * @throws NullPointerException
091     *             if the class is {@code null}
092     * @throws IllegalArgumentException
093     *             if the field name is {@code null}, blank, or empty
094     */
095    public static Field getDeclaredField(final Class<?> cls, final String fieldName) {
096        return getDeclaredField(cls, fieldName, false);
097    }
098
099    /**
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     * @deprecated TODO Make private in 4.0.
878     */
879    @Deprecated
880    public FieldUtils() {
881        // empty
882    }
883}