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