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 *      https://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.AccessibleObject;
021import java.lang.reflect.Field;
022import java.lang.reflect.Modifier;
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.List;
026import java.util.Objects;
027import java.util.stream.Collectors;
028
029import org.apache.commons.lang3.ArrayUtils;
030import org.apache.commons.lang3.ClassUtils;
031import org.apache.commons.lang3.JavaVersion;
032import org.apache.commons.lang3.StringUtils;
033import org.apache.commons.lang3.SystemUtils;
034import org.apache.commons.lang3.Validate;
035
036/**
037 * Utilities for working with {@link Field}s by reflection. Adapted and refactored from the dormant [reflect] Commons
038 * sandbox component.
039 * <p>
040 * The ability is provided to break the scoping restrictions coded by the programmer. This can allow fields to be
041 * changed that shouldn't be. This facility should be used with care.
042 * </p>
043 * @since 2.5
044 */
045public class FieldUtils {
046
047    /**
048     * Gets all fields of the given class and its parents (if any).
049     *
050     * @param cls
051     *            the {@link Class} to query
052     * @return an array of Fields (possibly empty).
053     * @throws NullPointerException
054     *             if the class is {@code null}.
055     * @since 3.2
056     */
057    public static Field[] getAllFields(final Class<?> cls) {
058        return getAllFieldsList(cls).toArray(ArrayUtils.EMPTY_FIELD_ARRAY);
059    }
060
061    /**
062     * Gets all fields of the given class and its parents (if any).
063     *
064     * @param cls
065     *            the {@link Class} to query
066     * @return a list of Fields (possibly empty).
067     * @throws NullPointerException
068     *             if the class is {@code null}.
069     * @since 3.2
070     */
071    public static List<Field> getAllFieldsList(final Class<?> cls) {
072        Objects.requireNonNull(cls, "cls");
073        final List<Field> allFields = new ArrayList<>();
074        Class<?> currentClass = cls;
075        while (currentClass != null) {
076            final Field[] declaredFields = currentClass.getDeclaredFields();
077            Collections.addAll(allFields, declaredFields);
078            currentClass = currentClass.getSuperclass();
079        }
080        return allFields;
081    }
082
083    /**
084     * Gets an accessible {@link Field} by name respecting scope. Only the specified class will be considered.
085     *
086     * @param cls
087     *            the {@link Class} to reflect, must not be {@code null}
088     * @param fieldName
089     *            the field name to obtain.
090     * @return the Field object.
091     * @throws NullPointerException
092     *             if the class is {@code null}.
093     * @throws IllegalArgumentException
094     *             if the field name is {@code null}, blank, or empty.
095     * @throws SecurityException if an underlying accessible object's method denies the request.
096     * @see SecurityManager#checkPermission
097     */
098    public static Field getDeclaredField(final Class<?> cls, final String fieldName) {
099        return getDeclaredField(cls, fieldName, false);
100    }
101
102    /**
103     * Gets an accessible {@link Field} by name, breaking scope if requested. Only the specified class will be
104     * considered.
105     *
106     * @param cls
107     *            the {@link Class} to reflect, must not be {@code null}.
108     * @param fieldName
109     *            the field name to obtain.
110     * @param forceAccess
111     *            whether to break scope restrictions using the
112     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
113     *            match {@code public} fields.
114     * @return the Field object
115     * @throws NullPointerException
116     *             if the class is {@code null}.
117     * @throws IllegalArgumentException
118     *             if the field name is {@code null}, blank, or empty.
119     * @throws SecurityException if an underlying accessible object's method denies the request.
120     * @see SecurityManager#checkPermission
121     */
122    public static Field getDeclaredField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
123        Objects.requireNonNull(cls, "cls");
124        Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
125        try {
126            // only consider the specified class by using getDeclaredField()
127            final Field field = cls.getDeclaredField(fieldName);
128            if (!MemberUtils.isAccessible(field)) {
129                if (!forceAccess) {
130                    return null;
131                }
132                field.setAccessible(true);
133            }
134            return field;
135        } catch (final NoSuchFieldException ignored) {
136            // ignore
137        }
138        return null;
139    }
140
141    /**
142     * Gets an accessible {@link Field} by name respecting scope. Superclasses/interfaces will be considered.
143     *
144     * @param cls
145     *            the {@link Class} to reflect, must not be {@code null}.
146     * @param fieldName
147     *            the field name to obtain.
148     * @return the Field object.
149     * @throws NullPointerException
150     *             if the class is {@code null}.
151     * @throws IllegalArgumentException
152     *             if the field name is {@code null}, blank, or empty
153     * @throws SecurityException if an underlying accessible object's method denies the request.
154     * @see SecurityManager#checkPermission
155     */
156    public static Field getField(final Class<?> cls, final String fieldName) {
157        return MemberUtils.setAccessibleWorkaround(getField(cls, fieldName, false));
158    }
159
160    /**
161     * Gets an accessible {@link Field} by name, breaking scope if requested. Superclasses/interfaces will be
162     * considered.
163     *
164     * @param cls
165     *            the {@link Class} to reflect, must not be {@code null}.
166     * @param fieldName
167     *            the field name to obtain.
168     * @param forceAccess
169     *            whether to break scope restrictions using the
170     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
171     *            match {@code public} fields.
172     * @return the Field object.
173     * @throws NullPointerException if the class is {@code null}.
174     * @throws IllegalArgumentException if the field name is blank or empty or is matched at multiple places
175     * in the inheritance hierarchy.
176     * @throws SecurityException if an underlying accessible object's method denies the request.
177     * @see SecurityManager#checkPermission
178     */
179    public static Field getField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
180        Objects.requireNonNull(cls, "cls");
181        Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
182        // FIXME is this workaround still needed? lang requires Java 6
183        // Sun Java 1.3 has a bugged implementation of getField hence we write the
184        // code ourselves
185
186        // getField() will return the Field object with the declaring class
187        // set correctly to the class that declares the field. Thus requesting the
188        // field on a subclass will return the field from the superclass.
189        //
190        // priority order for lookup:
191        // searchclass private/protected/package/public
192        // superclass protected/package/public
193        // private/different package blocks access to further superclasses
194        // implementedinterface public
195
196        // check up the superclass hierarchy
197        for (Class<?> acls = cls; acls != null; acls = acls.getSuperclass()) {
198            try {
199                final Field field = acls.getDeclaredField(fieldName);
200                // getDeclaredField checks for non-public scopes as well
201                // and it returns accurate results
202                if (!MemberUtils.isPublic(field)) {
203                    if (!forceAccess) {
204                        continue;
205                    }
206                    field.setAccessible(true);
207                }
208                return field;
209            } catch (final NoSuchFieldException ignored) {
210                // ignore
211            }
212        }
213        // check the public interface case. This must be manually searched for
214        // incase there is a public supersuperclass field hidden by a private/package
215        // superclass field.
216        Field match = null;
217        for (final Class<?> class1 : ClassUtils.getAllInterfaces(cls)) {
218            try {
219                final Field test = class1.getField(fieldName);
220                Validate.isTrue(match == null,
221                        "Reference to field %s is ambiguous relative to %s; a matching field exists on two or more implemented interfaces.", fieldName, cls);
222                match = test;
223            } catch (final NoSuchFieldException ignored) {
224                // ignore
225            }
226        }
227        return match;
228    }
229
230    /**
231     * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
232     * @param cls
233     *            the {@link Class} to query.
234     * @param annotationCls
235     *            the {@link Annotation} that must be present on a field to be matched.
236     * @return a list of Fields (possibly empty).
237     * @throws NullPointerException
238     *            if the class or annotation are {@code null}.
239     * @since 3.4
240     */
241    public static List<Field> getFieldsListWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
242        Objects.requireNonNull(annotationCls, "annotationCls");
243        return getAllFieldsList(cls).stream().filter(field -> field.getAnnotation(annotationCls) != null).collect(Collectors.toList());
244    }
245
246    /**
247     * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
248     * @param cls
249     *            the {@link Class} to query.
250     * @param annotationCls
251     *            the {@link Annotation} that must be present on a field to be matched
252     * @return an array of Fields (possibly empty).
253     * @throws NullPointerException
254     *            if the class or annotation are {@code null}.
255     * @since 3.4
256     */
257    public static Field[] getFieldsWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
258        return getFieldsListWithAnnotation(cls, annotationCls).toArray(ArrayUtils.EMPTY_FIELD_ARRAY);
259    }
260
261    /**
262     * Reads the named {@code public} {@link Field}. Only the class of the specified object will be considered.
263     *
264     * @param target
265     *            the object to reflect, must not be {@code null}.
266     * @param fieldName
267     *            the field name to obtain.
268     * @return the value of the field.
269     * @throws NullPointerException
270     *             if {@code target} is {@code null}.
271     * @throws IllegalArgumentException
272     *             if {@code fieldName} is {@code null}, blank or empty, or could not be found.
273     * @throws IllegalAccessException
274     *             if the named field is not {@code public}
275     * @throws SecurityException if an underlying accessible object's method denies the request.
276     * @see SecurityManager#checkPermission
277     */
278    public static Object readDeclaredField(final Object target, final String fieldName) throws IllegalAccessException {
279        return readDeclaredField(target, fieldName, false);
280    }
281
282    /**
283     * Gets a {@link Field} value by name. Only the class of the specified object will be considered.
284     *
285     * @param target
286     *            the object to reflect, must not be {@code null}.
287     * @param fieldName
288     *            the field name to obtain.
289     * @param forceAccess
290     *            whether to break scope restrictions using the
291     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
292     *            match public fields.
293     * @return the Field object.
294     * @throws NullPointerException
295     *             if {@code target} is {@code null}.
296     * @throws IllegalArgumentException
297     *             if {@code fieldName} is {@code null}, blank or empty, or could not be found.
298     * @throws IllegalAccessException
299     *             if the field is not made accessible.
300     * @throws SecurityException if an underlying accessible object's method denies the request.
301     * @see SecurityManager#checkPermission
302     */
303    public static Object readDeclaredField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
304        Objects.requireNonNull(target, "target");
305        final Class<?> cls = target.getClass();
306        final Field field = getDeclaredField(cls, fieldName, forceAccess);
307        Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls, fieldName);
308        // already forced access above, don't repeat it here:
309        return readField(field, target, false);
310    }
311
312    /**
313     * Gets the value of a {@code static} {@link Field} by name. The field must be {@code public}. Only the specified
314     * class will be considered.
315     *
316     * @param cls
317     *            the {@link Class} to reflect, must not be {@code null}.
318     * @param fieldName
319     *            the field name to obtain.
320     * @return the value of the field.
321     * @throws NullPointerException
322     *             if the class is {@code null}, or the field could not be found.
323     * @throws IllegalArgumentException
324     *             if the field name is {@code null}, blank, empty, or is not {@code static}.
325     * @throws IllegalAccessException
326     *             if the field is not accessible
327     * @throws SecurityException if an underlying accessible object's method denies the request.
328     * @see SecurityManager#checkPermission
329     */
330    public static Object readDeclaredStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
331        return readDeclaredStaticField(cls, fieldName, false);
332    }
333
334    /**
335     * Gets the value of a {@code static} {@link Field} by name. Only the specified class will be considered.
336     *
337     * @param cls
338     *            the {@link Class} to reflect, must not be {@code null}.
339     * @param fieldName
340     *            the field name to obtain.
341     * @param forceAccess
342     *            whether to break scope restrictions using the
343     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
344     *            match {@code public} fields.
345     * @return the Field object
346     * @throws NullPointerException
347     *             if the class is {@code null}, or the field could not be found.
348     * @throws IllegalArgumentException
349     *             if the field name is blank or empty, is not {@code static}.
350     * @throws IllegalAccessException
351     *             if the field is not made accessible
352     * @throws SecurityException if an underlying accessible object's method denies the request.
353     * @see SecurityManager#checkPermission
354     */
355    public static Object readDeclaredStaticField(final Class<?> cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
356        final Field field = getDeclaredField(cls, fieldName, forceAccess);
357        Validate.notNull(field, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
358        // already forced access above, don't repeat it here:
359        return readStaticField(field, false);
360    }
361
362    /**
363     * Reads an accessible {@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     * @return the field value
370     * @throws NullPointerException
371     *             if the field is {@code null}.
372     * @throws IllegalAccessException
373     *             if the field is not accessible.
374     * @throws SecurityException if an underlying accessible object's method denies the request.
375     * @see SecurityManager#checkPermission
376     */
377    public static Object readField(final Field field, final Object target) throws IllegalAccessException {
378        return readField(field, target, false);
379    }
380
381    /**
382     * Reads a {@link Field}.
383     *
384     * @param field
385     *            the field to use.
386     * @param target
387     *            the object to call on, may be {@code null} for {@code static} fields.
388     * @param forceAccess
389     *            whether to break scope restrictions using the
390     *            {@link AccessibleObject#setAccessible(boolean)} method.
391     * @return the field value
392     * @throws NullPointerException
393     *             if the field is {@code null}.
394     * @throws IllegalAccessException
395     *             if the field is not made accessible.
396     * @throws SecurityException if an underlying accessible object's method denies the request.
397     * @see SecurityManager#checkPermission
398     * @throws SecurityException if an underlying accessible object's method denies the request.
399     * @see SecurityManager#checkPermission
400     */
401    public static Object readField(final Field field, final Object target, final boolean forceAccess) throws IllegalAccessException {
402        Objects.requireNonNull(field, "field");
403        if (forceAccess && !field.isAccessible()) {
404            field.setAccessible(true);
405        } else {
406            MemberUtils.setAccessibleWorkaround(field);
407        }
408        return field.get(target);
409    }
410
411    /**
412     * Reads the named {@code public} {@link Field}. Superclasses will be considered.
413     *
414     * @param target
415     *            the object to reflect, must not be {@code null}.
416     * @param fieldName
417     *            the field name to obtain.
418     * @return the value of the field.
419     * @throws NullPointerException
420     *             if the 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 {@code public}.
425     * @throws SecurityException if an underlying accessible object's method denies the request.
426     * @see SecurityManager#checkPermission
427     */
428    public static Object readField(final Object target, final String fieldName) throws IllegalAccessException {
429        return readField(target, fieldName, false);
430    }
431
432    /**
433     * Reads the named {@link Field}. Superclasses will be considered.
434     *
435     * @param target
436     *            the object to reflect, must not be {@code null}.
437     * @param fieldName
438     *            the field name to obtain.
439     * @param forceAccess
440     *            whether to break scope restrictions using the
441     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
442     *            match {@code public} fields.
443     * @return the field value
444     * @throws NullPointerException
445     *             if {@code target} is {@code null}.
446     * @throws IllegalArgumentException
447     *             if the field name is {@code null}, blank, empty, or could not be found.
448     * @throws IllegalAccessException
449     *             if the named field is not made accessible.
450     * @throws SecurityException if an underlying accessible object's method denies the request.
451     * @see SecurityManager#checkPermission
452     */
453    public static Object readField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
454        Objects.requireNonNull(target, "target");
455        final Class<?> cls = target.getClass();
456        final Field field = getField(cls, fieldName, forceAccess);
457        Validate.isTrue(field != null, "Cannot locate field %s on %s", fieldName, cls);
458        // already forced access above, don't repeat it here:
459        return readField(field, target, false);
460    }
461
462    /**
463     * Reads the named {@code public static} {@link Field}. Superclasses will be considered.
464     *
465     * @param cls
466     *            the {@link Class} to reflect, must not be {@code null}.
467     * @param fieldName
468     *            the field name to obtain.
469     * @return the value of the field.
470     * @throws NullPointerException
471     *             if the class is {@code null}, or the field could not be found.
472     * @throws IllegalArgumentException
473     *             if the field name is {@code null}, blank or empty, or is not {@code static}.
474     * @throws IllegalAccessException
475     *             if the field is not accessible.
476     * @throws SecurityException if an underlying accessible object's method denies the request.
477     * @see SecurityManager#checkPermission
478     */
479    public static Object readStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
480        return readStaticField(cls, fieldName, false);
481    }
482
483    /**
484     * Reads the named {@code static} {@link Field}. Superclasses will be considered.
485     *
486     * @param cls
487     *            the {@link Class} to reflect, must not be {@code null}.
488     * @param fieldName
489     *            the field name to obtain.
490     * @param forceAccess
491     *            whether to break scope restrictions using the
492     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
493     *            match {@code public} fields.
494     * @return the Field object.
495     * @throws NullPointerException
496     *             if the class is {@code null}, or the field could not be found.
497     * @throws IllegalArgumentException
498     *             if the field name is {@code null}, blank or empty, or is not {@code static}.
499     * @throws IllegalAccessException
500     *             if the field is not made accessible.
501     * @throws SecurityException if an underlying accessible object's method denies the request.
502     * @see SecurityManager#checkPermission
503     */
504    public static Object readStaticField(final Class<?> cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
505        final Field field = getField(cls, fieldName, forceAccess);
506        Validate.notNull(field, "Cannot locate field '%s' on %s", fieldName, cls);
507        // already forced access above, don't repeat it here:
508        return readStaticField(field, false);
509    }
510
511    /**
512     * Reads an accessible {@code static} {@link Field}.
513     *
514     * @param field
515     *            to read.
516     * @return the field value.
517     * @throws NullPointerException
518     *             if the field is {@code null}.
519     * @throws IllegalArgumentException
520     *             if the field is not {@code static}.
521     * @throws IllegalAccessException
522     *             if the field is not accessible
523     * @throws SecurityException if an underlying accessible object's method denies the request.
524     * @see SecurityManager#checkPermission
525     */
526    public static Object readStaticField(final Field field) throws IllegalAccessException {
527        return readStaticField(field, false);
528    }
529
530    /**
531     * Reads a static {@link Field}.
532     *
533     * @param field
534     *            to read.
535     * @param forceAccess
536     *            whether to break scope restrictions using the
537     *            {@link AccessibleObject#setAccessible(boolean)} method.
538     * @return the field value.
539     * @throws NullPointerException
540     *             if the field is {@code null}.
541     * @throws IllegalArgumentException
542     *             if the field is not {@code static}.
543     * @throws IllegalAccessException
544     *             if the field is not made accessible.
545     * @throws SecurityException if an underlying accessible object's method denies the request.
546     * @see SecurityManager#checkPermission
547     */
548    public static Object readStaticField(final Field field, final boolean forceAccess) throws IllegalAccessException {
549        Objects.requireNonNull(field, "field");
550        Validate.isTrue(MemberUtils.isStatic(field), "The field '%s' is not static", field.getName());
551        return readField(field, (Object) null, forceAccess);
552    }
553
554    /**
555     * Removes the final modifier from a {@link Field}.
556     *
557     * @param field
558     *            to remove the final modifier.
559     * @throws NullPointerException
560     *             if the field is {@code null}.
561     * @throws SecurityException if an underlying accessible object's method denies the request.
562     * @see SecurityManager#checkPermission
563     * @since 3.2
564     */
565    public static void removeFinalModifier(final Field field) {
566        removeFinalModifier(field, true);
567    }
568
569    /**
570     * Removes the final modifier from a {@link Field}.
571     *
572     * @param field
573     *            to remove the final modifier.
574     * @param forceAccess
575     *            whether to break scope restrictions using the
576     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
577     *            match {@code public} fields.
578     * @throws NullPointerException
579     *             if the field is {@code null}.
580     * @throws SecurityException if an underlying accessible object's method denies the request.
581     * @see SecurityManager#checkPermission
582     * @deprecated As of Java 12, we can no longer drop the {@code final} modifier, thus
583     *             rendering this method obsolete. The JDK discussion about this change can be found
584     *             here: https://mail.openjdk.java.net/pipermail/core-libs-dev/2018-November/056486.html
585     * @since 3.3
586     */
587    @Deprecated
588    public static void removeFinalModifier(final Field field, final boolean forceAccess) {
589        Objects.requireNonNull(field, "field");
590
591        try {
592            if (Modifier.isFinal(field.getModifiers())) {
593                // Do all JREs implement Field with a private ivar called "modifiers"?
594                final Field modifiersField = Field.class.getDeclaredField("modifiers");
595                final boolean doForceAccess = forceAccess && !modifiersField.isAccessible();
596                if (doForceAccess) {
597                    modifiersField.setAccessible(true);
598                }
599                try {
600                    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
601                } finally {
602                    if (doForceAccess) {
603                        modifiersField.setAccessible(false);
604                    }
605                }
606            }
607        } catch (final NoSuchFieldException | IllegalAccessException e) {
608            if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_12)) {
609              throw new UnsupportedOperationException(
610                  "In java 12+ final cannot be removed.",
611                  e
612              );
613            }
614            // else no exception is thrown because we can modify final.
615        }
616    }
617
618    /**
619     * Writes a {@code public} {@link Field}. Only the specified class will be considered.
620     *
621     * @param target
622     *            the object to reflect, must not be {@code null}.
623     * @param fieldName
624     *            the field name to obtain.
625     * @param value
626     *            the new value.
627     * @throws NullPointerException
628     *             if {@code target} is {@code null}.
629     * @throws IllegalArgumentException
630     *             if {@code fieldName} is {@code null}, blank or empty, or could not be found,
631     *             or {@code value} is not assignable.
632     * @throws IllegalAccessException
633     *             if the field is not made accessible
634     * @throws SecurityException if an underlying accessible object's method denies the request.
635     * @see SecurityManager#checkPermission
636     */
637    public static void writeDeclaredField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
638        writeDeclaredField(target, fieldName, value, false);
639    }
640
641    /**
642     * Writes a {@code public} {@link Field}. Only the specified class will be considered.
643     *
644     * @param target
645     *            the object to reflect, must not be {@code null}.
646     * @param fieldName
647     *            the field name to obtain.
648     * @param value
649     *            the new value.
650     * @param forceAccess
651     *            whether to break scope restrictions using the
652     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
653     *            match {@code public} fields.
654     * @throws IllegalArgumentException
655     *             if {@code fieldName} is {@code null}, blank or empty, or could not be found,
656     *             or {@code value} is not assignable
657     * @throws IllegalAccessException
658     *             if the field is not made accessible
659     * @throws SecurityException if an underlying accessible object's method denies the request.
660     * @see SecurityManager#checkPermission
661     */
662    public static void writeDeclaredField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
663            throws IllegalAccessException {
664        Objects.requireNonNull(target, "target");
665        final Class<?> cls = target.getClass();
666        final Field field = getDeclaredField(cls, fieldName, forceAccess);
667        Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
668        // already forced access above, don't repeat it here:
669        writeField(field, target, value, false);
670    }
671
672    /**
673     * Writes a named {@code public static} {@link Field}. Only the specified class will be considered.
674     *
675     * @param cls
676     *            {@link Class} on which the field is to be found.
677     * @param fieldName
678     *            to write.
679     * @param value
680     *            the new value.
681     * @throws NullPointerException
682     *             if {@code cls} is {@code null} or the field cannot be located.
683     * @throws IllegalArgumentException
684     *             if the field name is {@code null}, blank, empty, not {@code static}, or {@code value} is not assignable.
685     * @throws IllegalAccessException
686     *             if the field is not {@code public} or is {@code final}
687     * @throws SecurityException if an underlying accessible object's method denies the request.
688     * @see SecurityManager#checkPermission
689     */
690    public static void writeDeclaredStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
691        writeDeclaredStaticField(cls, fieldName, value, false);
692    }
693
694    /**
695     * Writes a named {@code static} {@link Field}. Only the specified class will be considered.
696     *
697     * @param cls
698     *            {@link Class} on which the field is to be found.
699     * @param fieldName
700     *            to write
701     * @param value
702     *            the new value.
703     * @param forceAccess
704     *            whether to break scope restrictions using the {@code AccessibleObject#setAccessible(boolean)} method.
705     *            {@code false} will only match {@code public} fields.
706     * @throws NullPointerException
707     *             if {@code cls} is {@code null} or the field cannot be located.
708     * @throws IllegalArgumentException
709     *             if the field name is {@code null}, blank, empty, not {@code static}, or {@code value} is not assignable.
710     * @throws IllegalAccessException
711     *             if the field is not made accessible or is {@code final}
712     * @throws SecurityException if an underlying accessible object's method denies the request.
713     * @see SecurityManager#checkPermission
714     */
715    public static void writeDeclaredStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
716            throws IllegalAccessException {
717        final Field field = getDeclaredField(cls, fieldName, forceAccess);
718        Validate.notNull(field, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
719        // already forced access above, don't repeat it here:
720        writeField(field, (Object) null, value, false);
721    }
722
723    /**
724     * Writes an accessible {@link Field}.
725     *
726     * @param field
727     *            to write.
728     * @param target
729     *            the object to call on, may be {@code null} for {@code static} fields.
730     * @param value
731     *            the new value.
732     * @throws NullPointerException
733     *             if the field is {@code null}.
734     * @throws IllegalArgumentException
735     *             if {@code value} is not assignable.
736     * @throws IllegalAccessException
737     *             if the field is not accessible or is {@code final}.
738     * @throws SecurityException if an underlying accessible object's method denies the request.
739     * @see SecurityManager#checkPermission
740     */
741    public static void writeField(final Field field, final Object target, final Object value) throws IllegalAccessException {
742        writeField(field, target, value, false);
743    }
744
745    /**
746     * Writes a {@link Field}.
747     *
748     * @param field
749     *            to write.
750     * @param target
751     *            the object to call on, may be {@code null} for {@code static} fields
752     * @param value
753     *            the new value.
754     * @param forceAccess
755     *            whether to break scope restrictions using the
756     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
757     *            match {@code public} fields.
758     * @throws NullPointerException
759     *             if the field is {@code null}.
760     * @throws IllegalArgumentException
761     *             if {@code value} is not assignable.
762     * @throws IllegalAccessException
763     *             if the field is not made accessible or is {@code final}
764     * @throws SecurityException if an underlying accessible object's method denies the request.
765     * @see SecurityManager#checkPermission
766     */
767    public static void writeField(final Field field, final Object target, final Object value, final boolean forceAccess)
768            throws IllegalAccessException {
769        Objects.requireNonNull(field, "field");
770        if (forceAccess && !field.isAccessible()) {
771            field.setAccessible(true);
772        } else {
773            MemberUtils.setAccessibleWorkaround(field);
774        }
775        field.set(target, value);
776    }
777
778    /**
779     * Writes a {@code public} {@link Field}. Superclasses will be considered.
780     *
781     * @param target
782     *            the object to reflect, must not be {@code null}.
783     * @param fieldName
784     *            the field name to obtain.
785     * @param value
786     *            the new value.
787     * @throws NullPointerException
788     *             if {@code target} is {@code null}.
789     * @throws IllegalArgumentException
790     *             if {@code fieldName} is {@code null}, blank, empty, or could not be found,
791     *             or {@code value} is not assignable.
792     * @throws IllegalAccessException
793     *             if the field is not accessible.
794     * @throws SecurityException if an underlying accessible object's method denies the request.
795     * @see SecurityManager#checkPermission
796     */
797    public static void writeField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
798        writeField(target, fieldName, value, false);
799    }
800
801    /**
802     * Writes a {@link Field}. Superclasses will be considered.
803     *
804     * @param target
805     *            the object to reflect, must not be {@code null}.
806     * @param fieldName
807     *            the field name to obtain.
808     * @param value
809     *            the new value.
810     * @param forceAccess
811     *            whether to break scope restrictions using the
812     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
813     *            match {@code public} fields.
814     * @throws NullPointerException
815     *             if {@code target} is {@code null}.
816     * @throws IllegalArgumentException
817     *             if {@code fieldName} is {@code null}, blank, empty, or could not be found,
818     *             or {@code value} is not assignable.
819     * @throws IllegalAccessException
820     *             if the field is not made accessible.
821     * @throws SecurityException if an underlying accessible object's method denies the request.
822     * @see SecurityManager#checkPermission
823     */
824    public static void writeField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
825            throws IllegalAccessException {
826        Objects.requireNonNull(target, "target");
827        final Class<?> cls = target.getClass();
828        final Field field = getField(cls, fieldName, forceAccess);
829        Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
830        // already forced access above, don't repeat it here:
831        writeField(field, target, value, false);
832    }
833
834    /**
835     * Writes a named {@code public static} {@link Field}. Superclasses will be considered.
836     *
837     * @param cls
838     *            {@link Class} on which the field is to be found.
839     * @param fieldName
840     *            to write.
841     * @param value
842     *            the new value.
843     * @throws NullPointerException
844     *             if {@code target} is {@code null}.
845     * @throws IllegalArgumentException
846     *             if {@code fieldName} is {@code null}, blank or empty, the field cannot be located or is
847     *             not {@code static}, or {@code value} is not assignable.
848     * @throws IllegalAccessException
849     *             if the field is not {@code public} or is {@code final}
850     * @throws SecurityException if an underlying accessible object's method denies the request.
851     * @see SecurityManager#checkPermission
852     */
853    public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
854        writeStaticField(cls, fieldName, value, false);
855    }
856
857    /**
858     * Writes a named {@code static} {@link Field}. Superclasses will be considered.
859     *
860     * @param cls
861     *            {@link Class} on which the field is to be found.
862     * @param fieldName
863     *            to write.
864     * @param value
865     *            the new value.
866     * @param forceAccess
867     *            whether to break scope restrictions using the
868     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
869     *            match {@code public} fields.
870     * @throws NullPointerException
871     *             if {@code cls} is {@code null} or the field cannot be located.
872     * @throws IllegalArgumentException
873     *             if {@code fieldName} is {@code null}, blank or empty, the field not {@code static}, or {@code value} is not assignable.
874     * @throws IllegalAccessException
875     *             if the field is not made accessible or is {@code final}.
876     * @throws SecurityException if an underlying accessible object's method denies the request.
877     * @see SecurityManager#checkPermission
878     */
879    public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
880            throws IllegalAccessException {
881        final Field field = getField(cls, fieldName, forceAccess);
882        Validate.notNull(field, "Cannot locate field %s on %s", fieldName, cls);
883        // already forced access above, don't repeat it here:
884        writeStaticField(field, value, false);
885    }
886
887    /**
888     * Writes a {@code public static} {@link Field}.
889     *
890     * @param field
891     *            to write.
892     * @param value
893     *            the new value.
894     * @throws NullPointerException
895     *              if the field is {@code null}.
896     * @throws IllegalArgumentException
897     *              if the field is not {@code static}, or {@code value} is not assignable.
898     * @throws IllegalAccessException
899     *             if the field is not {@code public} or is {@code final}.
900     * @throws SecurityException if an underlying accessible object's method denies the request.
901     * @see SecurityManager#checkPermission
902     */
903    public static void writeStaticField(final Field field, final Object value) throws IllegalAccessException {
904        writeStaticField(field, value, false);
905    }
906
907    /**
908     * Writes a static {@link Field}.
909     *
910     * @param field
911     *            to write.
912     * @param value
913     *            the new value.
914     * @param forceAccess
915     *            whether to break scope restrictions using the
916     *            {@link AccessibleObject#setAccessible(boolean)} method. {@code false} will only
917     *            match {@code public} fields.
918     * @throws NullPointerException
919     *              if the field is {@code null}.
920     * @throws IllegalArgumentException
921     *              if the field is not {@code static}, or {@code value} is not assignable.
922     * @throws IllegalAccessException
923     *             if the field is not made accessible or is {@code final}
924     * @throws SecurityException if an underlying accessible object's method denies the request.
925     * @see SecurityManager#checkPermission
926     */
927    public static void writeStaticField(final Field field, final Object value, final boolean forceAccess) throws IllegalAccessException {
928        Objects.requireNonNull(field, "field");
929        Validate.isTrue(MemberUtils.isStatic(field), "The field %s.%s is not static", field.getDeclaringClass().getName(),
930                field.getName());
931        writeField(field, (Object) null, value, forceAccess);
932    }
933
934    /**
935     * {@link FieldUtils} instances should NOT be constructed in standard programming.
936     * <p>
937     * This constructor is {@code public} to permit tools that require a JavaBean instance to operate.
938     * </p>
939     *
940     * @deprecated TODO Make private in 4.0.
941     */
942    @Deprecated
943    public FieldUtils() {
944        // empty
945    }
946}