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