    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    public FieldUtils() {
    878    }
    879}