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