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 sandbox
030 * 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 1546799 2013-12-01 10:34:02Z mcucchiara $
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.</p>
044     */
045    public FieldUtils() {
046        super();
047    }
048
049    /**
050     * Gets an accessible {@link Field} by name respecting scope. Superclasses/interfaces will be considered.
051     * 
052     * @param cls
053     *            the {@link Class} to reflect, must not be {@code null}
054     * @param fieldName
055     *            the field name to obtain
056     * @return the Field object
057     * @throws IllegalArgumentException
058     *             if the class is {@code null}, or the field name is blank or empty
059     */
060    public static Field getField(final Class<?> cls, final String fieldName) {
061        final Field field = getField(cls, fieldName, false);
062        MemberUtils.setAccessibleWorkaround(field);
063        return field;
064    }
065
066    /**
067     * Gets an accessible {@link Field} by name, breaking scope if requested. Superclasses/interfaces will be
068     * considered.
069     * 
070     * @param cls
071     *            the {@link Class} to reflect, must not be {@code null}
072     * @param fieldName
073     *            the field name to obtain
074     * @param forceAccess
075     *            whether to break scope restrictions using the
076     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
077     *            {@code false} will only match {@code public} fields.
078     * @return the Field object
079     * @throws IllegalArgumentException
080     *             if the class is {@code null}, or the field name is blank or empty or is matched at
081     *             multiple places in the inheritance hierarchy
082     */
083    public static Field getField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
084        Validate.isTrue(cls != null, "The class must not be null");
085        Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
086        // Sun Java 1.3 has a bugged implementation of getField hence we write the
087        // code ourselves
088
089        // getField() will return the Field object with the declaring class
090        // set correctly to the class that declares the field. Thus requesting the
091        // field on a subclass will return the field from the superclass.
092        //
093        // priority order for lookup:
094        // searchclass private/protected/package/public
095        // superclass protected/package/public
096        // private/different package blocks access to further superclasses
097        // implementedinterface public
098
099        // check up the superclass hierarchy
100        for (Class<?> acls = cls; acls != null; acls = acls.getSuperclass()) {
101            try {
102                final Field field = acls.getDeclaredField(fieldName);
103                // getDeclaredField checks for non-public scopes as well
104                // and it returns accurate results
105                if (!Modifier.isPublic(field.getModifiers())) {
106                    if (forceAccess) {
107                        field.setAccessible(true);
108                    } else {
109                        continue;
110                    }
111                }
112                return field;
113            } catch (final NoSuchFieldException ex) { // NOPMD
114                // ignore
115            }
116        }
117        // check the public interface case. This must be manually searched for
118        // incase there is a public supersuperclass field hidden by a private/package
119        // superclass field.
120        Field match = null;
121        for (final Class<?> class1 : ClassUtils.getAllInterfaces(cls)) {
122            try {
123                final Field test = class1.getField(fieldName);
124                Validate.isTrue(match == null, "Reference to field %s is ambiguous relative to %s"
125                        + "; a matching field exists on two or more implemented interfaces.", fieldName, cls);
126                match = test;
127            } catch (final NoSuchFieldException ex) { // NOPMD
128                // ignore
129            }
130        }
131        return match;
132    }
133
134    /**
135     * Gets an accessible {@link Field} by name respecting scope. Only the specified class will be considered.
136     * 
137     * @param cls
138     *            the {@link Class} to reflect, must not be {@code null}
139     * @param fieldName
140     *            the field name to obtain
141     * @return the Field object
142     * @throws IllegalArgumentException
143     *             if the class is {@code null}, or the field name is blank or empty
144     */
145    public static Field getDeclaredField(final Class<?> cls, final String fieldName) {
146        return getDeclaredField(cls, fieldName, false);
147    }
148
149    /**
150     * Gets an accessible {@link Field} by name, breaking scope if requested. Only the specified class will be
151     * considered.
152     * 
153     * @param cls
154     *            the {@link Class} to reflect, must not be {@code null}
155     * @param fieldName
156     *            the field name to obtain
157     * @param forceAccess
158     *            whether to break scope restrictions using the
159     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
160     *            {@code false} will only match {@code public} fields.
161     * @return the Field object
162     * @throws IllegalArgumentException
163     *             if the class is {@code null}, or the field name is blank or empty
164     */
165    public static Field getDeclaredField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
166        Validate.isTrue(cls != null, "The class must not be null");
167        Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
168        try {
169            // only consider the specified class by using getDeclaredField()
170            final Field field = cls.getDeclaredField(fieldName);
171            if (!MemberUtils.isAccessible(field)) {
172                if (forceAccess) {
173                    field.setAccessible(true);
174                } else {
175                    return null;
176                }
177            }
178            return field;
179        } catch (final NoSuchFieldException e) { // NOPMD
180            // ignore
181        }
182        return null;
183    }
184
185    /**
186     * Gets all fields of the given class and its parents (if any).
187     * 
188     * @param cls
189     *            the {@link Class} to query
190     * @return an array of Fields (possibly empty).
191     * @throws IllegalArgumentException
192     *             if the class is {@code null}
193     * @since 3.2
194     */
195    public static Field[] getAllFields(Class<?> cls) {
196        final List<Field> allFieldsList = getAllFieldsList(cls);
197        return allFieldsList.toArray(new Field[allFieldsList.size()]);
198    }
199
200    /**
201     * Gets all fields of the given class and its parents (if any).
202     * 
203     * @param cls
204     *            the {@link Class} to query
205     * @return an array of Fields (possibly empty).
206     * @throws IllegalArgumentException
207     *             if the class is {@code null}
208     * @since 3.2
209     */
210    public static List<Field> getAllFieldsList(Class<?> cls) {
211        Validate.isTrue(cls != null, "The class must not be null");
212        final List<Field> allFields = new ArrayList<Field>();
213        Class<?> currentClass = cls;
214        while (currentClass != null) {
215            final Field[] declaredFields = currentClass.getDeclaredFields();
216            for (Field field : declaredFields) {
217                allFields.add(field);
218            }
219            currentClass = currentClass.getSuperclass();
220        }
221        return allFields;
222    }
223
224    /**
225     * Reads an accessible {@code static} {@link Field}.
226     * 
227     * @param field
228     *            to read
229     * @return the field value
230     * @throws IllegalArgumentException
231     *             if the field is {@code null}, or not {@code static}
232     * @throws IllegalAccessException
233     *             if the field is not accessible
234     */
235    public static Object readStaticField(final Field field) throws IllegalAccessException {
236        return readStaticField(field, false);
237    }
238
239    /**
240     * Reads a static {@link Field}.
241     * 
242     * @param field
243     *            to read
244     * @param forceAccess
245     *            whether to break scope restrictions using the
246     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
247     * @return the field value
248     * @throws IllegalArgumentException
249     *             if the field is {@code null} or not {@code static}
250     * @throws IllegalAccessException
251     *             if the field is not made accessible
252     */
253    public static Object readStaticField(final Field field, final boolean forceAccess) throws IllegalAccessException {
254        Validate.isTrue(field != null, "The field must not be null");
255        Validate.isTrue(Modifier.isStatic(field.getModifiers()), "The field '%s' is not static", field.getName());
256        return readField(field, (Object) null, forceAccess);
257    }
258
259    /**
260     * Reads the named {@code public static} {@link Field}. Superclasses will be considered.
261     * 
262     * @param cls
263     *            the {@link Class} to reflect, must not be {@code null}
264     * @param fieldName
265     *            the field name to obtain
266     * @return the value of the field
267     * @throws IllegalArgumentException
268     *             if the class is {@code null}, or the field name is blank or empty,
269     *             is not {@code static}, or could not be found
270     * @throws IllegalAccessException
271     *             if the field is not accessible
272     */
273    public static Object readStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
274        return readStaticField(cls, fieldName, false);
275    }
276
277    /**
278     * Reads the named {@code static} {@link Field}. Superclasses will be considered.
279     * 
280     * @param cls
281     *            the {@link Class} to reflect, must not be {@code null}
282     * @param fieldName
283     *            the field name to obtain
284     * @param forceAccess
285     *            whether to break scope restrictions using the
286     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
287     *            {@code false} will only match {@code public} fields.
288     * @return the Field object
289     * @throws IllegalArgumentException
290     *             if the class is {@code null}, or the field name is blank or empty,
291     *             is not {@code static}, or could not be found
292     * @throws IllegalAccessException
293     *             if the field is not made accessible
294     */
295    public static Object readStaticField(final Class<?> cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
296        final Field field = getField(cls, fieldName, forceAccess);
297        Validate.isTrue(field != null, "Cannot locate field '%s' on %s", fieldName, cls);
298        // already forced access above, don't repeat it here:
299        return readStaticField(field, false);
300    }
301
302    /**
303     * Gets the value of a {@code static} {@link Field} by name. The field must be {@code public}.
304     * Only the specified class will be considered.
305     * 
306     * @param cls
307     *            the {@link Class} to reflect, must not be {@code null}
308     * @param fieldName
309     *            the field name to obtain
310     * @return the value of the field
311     * @throws IllegalArgumentException
312     *             if the class is {@code null}, or the field name is blank or empty,
313     *             is not {@code static}, or could not be found
314     * @throws IllegalAccessException
315     *             if the field is not accessible
316     */
317    public static Object readDeclaredStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
318        return readDeclaredStaticField(cls, fieldName, false);
319    }
320
321    /**
322     * Gets the value of a {@code static} {@link Field} by name.
323     * 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.
332     *            {@code false} will only 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,
336     *             is not {@code static}, or could 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
400     *             the field name is blank or empty or could not be found
401     * @throws IllegalAccessException
402     *             if the named field is not {@code public}
403     */
404    public static Object readField(final Object target, final String fieldName) throws IllegalAccessException {
405        return readField(target, fieldName, false);
406    }
407
408    /**
409     * Reads the named {@link Field}. Superclasses will be considered.
410     * 
411     * @param target
412     *            the object to reflect, must not be {@code null}
413     * @param fieldName
414     *            the field name to obtain
415     * @param forceAccess
416     *            whether to break scope restrictions using the
417     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
418     *            {@code false} will only match {@code public} fields.
419     * @return the field value
420     * @throws IllegalArgumentException
421     *             if {@code target} is {@code null}, or
422     *             the field name is blank or empty or could not be found
423     * @throws IllegalAccessException
424     *             if the named field is not made accessible
425     */
426    public static Object readField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
427        Validate.isTrue(target != null, "target object must not be null");
428        final Class<?> cls = target.getClass();
429        final Field field = getField(cls, fieldName, forceAccess);
430        Validate.isTrue(field != null, "Cannot locate field %s on %s" , fieldName, cls);
431        // already forced access above, don't repeat it here:
432        return readField(field, target);
433    }
434
435    /**
436     * Reads the named {@code public} {@link Field}. Only the class of the specified object will be considered.
437     * 
438     * @param target
439     *            the object to reflect, must not be {@code null}
440     * @param fieldName
441     *            the field name to obtain
442     * @return the value of the field
443     * @throws IllegalArgumentException
444     *             if {@code target} is {@code null}, or
445     *             the field name is blank or empty or could not be found
446     * @throws IllegalAccessException
447     *             if the named field is not {@code public}
448     */
449    public static Object readDeclaredField(final Object target, final String fieldName) throws IllegalAccessException {
450        return readDeclaredField(target, fieldName, false);
451    }
452
453    /**
454     * <p<>Gets a {@link Field} value by name. Only the class of the specified object will be considered.
455     * 
456     * @param target
457     *            the object to reflect, must not be {@code null}
458     * @param fieldName
459     *            the field name to obtain
460     * @param forceAccess
461     *            whether to break scope restrictions using the
462     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
463     *            {@code false} will only match public fields.
464     * @return the Field object
465     * @throws IllegalArgumentException
466     *             if {@code target} is {@code null}, or
467     *             the field name is blank or empty or could not be found
468     * @throws IllegalAccessException
469     *             if the field is not made accessible
470     */
471    public static Object readDeclaredField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
472        Validate.isTrue(target != null, "target object must not be null");
473        final Class<?> cls = target.getClass();
474        final Field field = getDeclaredField(cls, fieldName, forceAccess);
475        Validate.isTrue(field != null, "Cannot locate declared field %s.%s" , cls, fieldName);
476        // already forced access above, don't repeat it here:
477        return readField(field, target);
478    }
479
480    /**
481     * Writes a {@code public static} {@link Field}.
482     * 
483     * @param field
484     *            to write
485     * @param value
486     *            to set
487     * @throws IllegalArgumentException
488     *             if the field is {@code null} or not {@code static},
489     *             or {@code value} is not assignable
490     * @throws IllegalAccessException
491     *             if the field is not {@code public} or is {@code final}
492     */
493    public static void writeStaticField(final Field field, final Object value) throws IllegalAccessException {
494        writeStaticField(field, value, false);
495    }
496
497    /**
498     * Writes a static {@link Field}.
499     * 
500     * @param field
501     *            to write
502     * @param value
503     *            to set
504     * @param forceAccess
505     *            whether to break scope restrictions using the
506     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false}
507     *            will only match {@code public} fields.
508     * @throws IllegalArgumentException
509     *             if the field is {@code null} or not {@code static},
510     *             or {@code value} is not assignable
511     * @throws IllegalAccessException
512     *             if the field is not made accessible or is {@code final}
513     */
514    public static void writeStaticField(final Field field, final Object value, final boolean forceAccess) throws IllegalAccessException {
515        Validate.isTrue(field != null, "The field must not be null");
516        Validate.isTrue(Modifier.isStatic(field.getModifiers()), "The field %s.%s is not static",
517                field.getDeclaringClass().getName(), field.getName());
518        writeField(field, (Object) null, value, forceAccess);
519    }
520
521    /**
522     * Writes a named {@code public static} {@link Field}. Superclasses will be considered.
523     * 
524     * @param cls
525     *            {@link Class} on which the field is to be found
526     * @param fieldName
527     *            to write
528     * @param value
529     *            to set
530     * @throws IllegalArgumentException
531     *             if {@code cls} is {@code null},
532     *             the field name is blank or empty,
533     *             the field cannot be located or is not {@code static}, or
534     *             {@code value} is not assignable
535     * @throws IllegalAccessException
536     *             if the field is not {@code public} or is {@code final}
537     */
538    public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
539        writeStaticField(cls, fieldName, value, false);
540    }
541
542    /**
543     * Writes a named {@code static} {@link Field}. Superclasses will be considered.
544     * 
545     * @param cls
546     *            {@link Class} on which the field is to be found
547     * @param fieldName
548     *            to write
549     * @param value
550     *            to set
551     * @param forceAccess
552     *            whether to break scope restrictions using the
553     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
554     *            {@code false} will only match {@code public} fields.
555     * @throws IllegalArgumentException
556     *             if {@code cls} is {@code null},
557     *             the field name is blank or empty,
558     *             the field cannot be located or is not {@code static}, or
559     *             {@code value} is not assignable
560     * @throws IllegalAccessException
561     *             if the field is not made accessible or is {@code final}
562     */
563    public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
564            throws IllegalAccessException {
565        final Field field = getField(cls, fieldName, forceAccess);
566        Validate.isTrue(field != null, "Cannot locate field %s on %s", fieldName, cls);
567        // already forced access above, don't repeat it here:
568        writeStaticField(field, value);
569    }
570
571    /**
572     * Writes a named {@code public static} {@link Field}. Only the specified class will be considered.
573     * 
574     * @param cls
575     *            {@link Class} on which the field is to be found
576     * @param fieldName
577     *            to write
578     * @param value
579     *            to set
580     * @throws IllegalArgumentException
581     *             if {@code cls} is {@code null},
582     *             the field name is blank or empty,
583     *             the field cannot be located or is not {@code static}, or
584     *             {@code value} is not assignable
585     * @throws IllegalAccessException
586     *             if the field is not {@code public} or is {@code final}
587     */
588    public static void writeDeclaredStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
589        writeDeclaredStaticField(cls, fieldName, value, false);
590    }
591
592    /**
593     * Writes a named {@code static} {@link Field}. Only the specified class will be considered.
594     * 
595     * @param cls
596     *            {@link Class} on which the field is to be found
597     * @param fieldName
598     *            to write
599     * @param value
600     *            to set
601     * @param forceAccess
602     *            whether to break scope restrictions using the {@code AccessibleObject#setAccessible(boolean)} method.
603     *            {@code false} will only match {@code public} fields.
604     * @throws IllegalArgumentException
605     *             if {@code cls} is {@code null},
606     *             the field name is blank or empty,
607     *             the field cannot be located or is not {@code static}, or
608     *             {@code value} is not assignable
609     * @throws IllegalAccessException
610     *             if the field is not made accessible or is {@code final}
611     */
612    public static void writeDeclaredStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
613            throws IllegalAccessException {
614        final Field field = getDeclaredField(cls, fieldName, forceAccess);
615        Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
616        // already forced access above, don't repeat it here:
617        writeField(field, (Object) null, value);
618    }
619
620    /**
621     * Writes an accessible {@link Field}.
622     * 
623     * @param field
624     *            to write
625     * @param target
626     *            the object to call on, may be {@code null} for {@code static} fields
627     * @param value
628     *            to set
629     * @throws IllegalAccessException
630     *             if the field or target is {@code null},
631     *             the field is not accessible or is {@code final}, or
632     *             {@code value} is not assignable
633     */
634    public static void writeField(final Field field, final Object target, final Object value) throws IllegalAccessException {
635        writeField(field, target, value, false);
636    }
637
638    /**
639     * Writes a {@link Field}.
640     * 
641     * @param field
642     *            to write
643     * @param target
644     *            the object to call on, may be {@code null} for {@code static} fields
645     * @param value
646     *            to set
647     * @param forceAccess
648     *            whether to break scope restrictions using the
649     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
650     *            {@code false} will only match {@code public} fields.
651     * @throws IllegalArgumentException
652     *             if the field is {@code null} or
653     *             {@code value} is not assignable
654     * @throws IllegalAccessException
655     *             if the field is not made accessible or is {@code final}
656     */
657    public static void writeField(final Field field, final Object target, final Object value, final boolean forceAccess)
658            throws IllegalAccessException {
659        Validate.isTrue(field != null, "The field must not be null");
660        if (forceAccess && !field.isAccessible()) {
661            field.setAccessible(true);
662        } else {
663            MemberUtils.setAccessibleWorkaround(field);
664        }
665        field.set(target, value);
666    }
667
668    /**
669     * Remove the final modifier from a {@link Field}
670     * @param field to remove the final modifier
671     * @throws IllegalArgumentException
672     *             if the field is {@code null}
673     */
674    public static void removeFinalModifier(Field field)  {
675        Validate.isTrue(field != null, "The field must not be null");
676
677        try {
678            if(Modifier.isFinal(field.getModifiers())){
679                Field modifiersField = Field.class.getDeclaredField("modifiers");
680                modifiersField.setAccessible(true);
681                modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
682            }
683        } catch (NoSuchFieldException ignored) {
684            // The field class contains always a modifiers field
685        } catch (IllegalAccessException ignored) {
686             // The modifiers field is made accessible
687        }
688    }
689
690    /**
691     * Writes a {@code public} {@link Field}. Superclasses will be considered.
692     * 
693     * @param target
694     *            the object to reflect, must not be {@code null}
695     * @param fieldName
696     *            the field name to obtain
697     * @param value
698     *            to set
699     * @throws IllegalArgumentException
700     *             if {@code target} is {@code null},
701     *             {@code fieldName} is blank or empty or could not be found,
702     *             or {@code value} is not assignable
703     * @throws IllegalAccessException
704     *             if the field is not accessible
705     */
706    public static void writeField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
707        writeField(target, fieldName, value, false);
708    }
709
710    /**
711     * Writes a {@link Field}. Superclasses will be considered.
712     * 
713     * @param target
714     *            the object to reflect, must not be {@code null}
715     * @param fieldName
716     *            the field name to obtain
717     * @param value
718     *            to set
719     * @param forceAccess
720     *            whether to break scope restrictions using the
721     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false}
722     *            will only match {@code public} fields.
723     * @throws IllegalArgumentException
724     *             if {@code target} is {@code null},
725     *             {@code fieldName} is blank or empty or could not be found,
726     *             or {@code value} is not assignable
727     * @throws IllegalAccessException
728     *             if the field is not made accessible
729     */
730    public static void writeField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
731            throws IllegalAccessException {
732        Validate.isTrue(target != null, "target object must not be null");
733        final Class<?> cls = target.getClass();
734        final Field field = getField(cls, fieldName, forceAccess);
735        Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
736        // already forced access above, don't repeat it here:
737        writeField(field, target, value);
738    }
739
740    /**
741     * Writes a {@code public} {@link Field}. Only the specified class will be considered.
742     * 
743     * @param target
744     *            the object to reflect, must not be {@code null}
745     * @param fieldName
746     *            the field name to obtain
747     * @param value
748     *            to set
749     * @throws IllegalArgumentException
750     *             if {@code target} is {@code null},
751     *             {@code fieldName} is blank or empty or could not be found,
752     *             or {@code value} is not assignable
753     * @throws IllegalAccessException
754     *             if the field is not made accessible
755     */
756    public static void writeDeclaredField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
757        writeDeclaredField(target, fieldName, value, false);
758    }
759
760    /**
761     * Writes a {@code public} {@link Field}. Only the specified class will be considered.
762     * 
763     * @param target
764     *            the object to reflect, must not be {@code null}
765     * @param fieldName
766     *            the field name to obtain
767     * @param value
768     *            to set
769     * @param forceAccess
770     *            whether to break scope restrictions using the
771     *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
772     *            {@code false} will only match {@code public} fields.
773     * @throws IllegalArgumentException
774     *             if {@code target} is {@code null},
775     *             {@code fieldName} is blank or empty or could not be found,
776     *             or {@code value} is not assignable
777     * @throws IllegalAccessException
778     *             if the field is not made accessible
779     */
780    public static void writeDeclaredField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
781            throws IllegalAccessException {
782        Validate.isTrue(target != null, "target object must not be null");
783        final Class<?> cls = target.getClass();
784        final Field field = getDeclaredField(cls, fieldName, forceAccess);
785        Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
786        // already forced access above, don't repeat it here:
787        writeField(field, target, value);
788    }
789}