Coverage Report - org.apache.commons.lang3.reflect.FieldUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
FieldUtils
98%
142/144
89%
73/82
1,743
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.lang3.reflect;
 18  
 
 19  
 import org.apache.commons.lang3.ClassUtils;
 20  
 import org.apache.commons.lang3.StringUtils;
 21  
 import org.apache.commons.lang3.Validate;
 22  
 
 23  
 import java.lang.annotation.Annotation;
 24  
 import java.lang.reflect.Field;
 25  
 import java.lang.reflect.Modifier;
 26  
 import java.util.ArrayList;
 27  
 import java.util.List;
 28  
 
 29  
 /**
 30  
  * Utilities for working with {@link Field}s by reflection. Adapted and refactored from the dormant [reflect] Commons
 31  
  * sandbox component.
 32  
  * <p>
 33  
  * The ability is provided to break the scoping restrictions coded by the programmer. This can allow fields to be
 34  
  * changed that shouldn't be. This facility should be used with care.
 35  
  * 
 36  
  * @since 2.5
 37  
  */
 38  
 public class FieldUtils {
 39  
 
 40  
     /**
 41  
      * {@link FieldUtils} instances should NOT be constructed in standard programming.
 42  
      * <p>
 43  
      * This constructor is {@code public} to permit tools that require a JavaBean instance to operate.
 44  
      * </p>
 45  
      */
 46  
     public FieldUtils() {
 47  1
         super();
 48  1
     }
 49  
 
 50  
     /**
 51  
      * Gets an accessible {@link Field} by name respecting scope. Superclasses/interfaces will be considered.
 52  
      * 
 53  
      * @param cls
 54  
      *            the {@link Class} to reflect, must not be {@code null}
 55  
      * @param fieldName
 56  
      *            the field name to obtain
 57  
      * @return the Field object
 58  
      * @throws IllegalArgumentException
 59  
      *             if the class is {@code null}, or the field name is blank or empty
 60  
      */
 61  
     public static Field getField(final Class<?> cls, final String fieldName) {
 62  25
         final Field field = getField(cls, fieldName, false);
 63  20
         MemberUtils.setAccessibleWorkaround(field);
 64  20
         return field;
 65  
     }
 66  
 
 67  
     /**
 68  
      * Gets an accessible {@link Field} by name, breaking scope if requested. Superclasses/interfaces will be
 69  
      * considered.
 70  
      * 
 71  
      * @param cls
 72  
      *            the {@link Class} to reflect, must not be {@code null}
 73  
      * @param fieldName
 74  
      *            the field name to obtain
 75  
      * @param forceAccess
 76  
      *            whether to break scope restrictions using the
 77  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 78  
      *            match {@code public} fields.
 79  
      * @return the Field object
 80  
      * @throws IllegalArgumentException
 81  
      *             if the class is {@code null}, or the field name is blank or empty or is matched at multiple places
 82  
      *             in the inheritance hierarchy
 83  
      */
 84  
     public static Field getField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
 85  154
         Validate.isTrue(cls != null, "The class must not be null");
 86  150
         Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
 87  
         // FIXME is this workaround still needed? lang requires Java 6
 88  
         // Sun Java 1.3 has a bugged implementation of getField hence we write the
 89  
         // code ourselves
 90  
 
 91  
         // getField() will return the Field object with the declaring class
 92  
         // set correctly to the class that declares the field. Thus requesting the
 93  
         // field on a subclass will return the field from the superclass.
 94  
         //
 95  
         // priority order for lookup:
 96  
         // searchclass private/protected/package/public
 97  
         // superclass protected/package/public
 98  
         // private/different package blocks access to further superclasses
 99  
         // implementedinterface public
 100  
 
 101  
         // check up the superclass hierarchy
 102  279
         for (Class<?> acls = cls; acls != null; acls = acls.getSuperclass()) {
 103  
             try {
 104  241
                 final Field field = acls.getDeclaredField(fieldName);
 105  
                 // getDeclaredField checks for non-public scopes as well
 106  
                 // and it returns accurate results
 107  134
                 if (!Modifier.isPublic(field.getModifiers())) {
 108  76
                     if (forceAccess) {
 109  36
                         field.setAccessible(true);
 110  
                     } else {
 111  40
                         continue;
 112  
                     }
 113  
                 }
 114  94
                 return field;
 115  107
             } catch (final NoSuchFieldException ex) { // NOPMD
 116  
                 // ignore
 117  
             }
 118  
         }
 119  
         // check the public interface case. This must be manually searched for
 120  
         // incase there is a public supersuperclass field hidden by a private/package
 121  
         // superclass field.
 122  38
         Field match = null;
 123  38
         for (final Class<?> class1 : ClassUtils.getAllInterfaces(cls)) {
 124  
             try {
 125  31
                 final Field test = class1.getField(fieldName);
 126  13
                 Validate.isTrue(match == null, "Reference to field %s is ambiguous relative to %s"
 127  
                         + "; a matching field exists on two or more implemented interfaces.", fieldName, cls);
 128  12
                 match = test;
 129  18
             } catch (final NoSuchFieldException ex) { // NOPMD
 130  
                 // ignore
 131  12
             }
 132  30
         }
 133  37
         return match;
 134  
     }
 135  
 
 136  
     /**
 137  
      * Gets an accessible {@link Field} by name respecting scope. Only the specified class will be considered.
 138  
      * 
 139  
      * @param cls
 140  
      *            the {@link Class} to reflect, must not be {@code null}
 141  
      * @param fieldName
 142  
      *            the field name to obtain
 143  
      * @return the Field object
 144  
      * @throws IllegalArgumentException
 145  
      *             if the class is {@code null}, or the field name is blank or empty
 146  
      */
 147  
     public static Field getDeclaredField(final Class<?> cls, final String fieldName) {
 148  21
         return getDeclaredField(cls, fieldName, false);
 149  
     }
 150  
 
 151  
     /**
 152  
      * Gets an accessible {@link Field} by name, breaking scope if requested. Only the specified class will be
 153  
      * considered.
 154  
      * 
 155  
      * @param cls
 156  
      *            the {@link Class} to reflect, must not be {@code null}
 157  
      * @param fieldName
 158  
      *            the field name to obtain
 159  
      * @param forceAccess
 160  
      *            whether to break scope restrictions using the
 161  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 162  
      *            match {@code public} fields.
 163  
      * @return the Field object
 164  
      * @throws IllegalArgumentException
 165  
      *             if the class is {@code null}, or the field name is blank or empty
 166  
      */
 167  
     public static Field getDeclaredField(final Class<?> cls, final String fieldName, final boolean forceAccess) {
 168  135
         Validate.isTrue(cls != null, "The class must not be null");
 169  133
         Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty");
 170  
         try {
 171  
             // only consider the specified class by using getDeclaredField()
 172  121
             final Field field = cls.getDeclaredField(fieldName);
 173  89
             if (!MemberUtils.isAccessible(field)) {
 174  50
                 if (forceAccess) {
 175  30
                     field.setAccessible(true);
 176  
                 } else {
 177  20
                     return null;
 178  
                 }
 179  
             }
 180  69
             return field;
 181  32
         } catch (final NoSuchFieldException e) { // NOPMD
 182  
             // ignore
 183  
         }
 184  32
         return null;
 185  
     }
 186  
 
 187  
     /**
 188  
      * Gets all fields of the given class and its parents (if any).
 189  
      * 
 190  
      * @param cls
 191  
      *            the {@link Class} to query
 192  
      * @return an array of Fields (possibly empty).
 193  
      * @throws IllegalArgumentException
 194  
      *             if the class is {@code null}
 195  
      * @since 3.2
 196  
      */
 197  
     public static Field[] getAllFields(final Class<?> cls) {
 198  4
         final List<Field> allFieldsList = getAllFieldsList(cls);
 199  4
         return allFieldsList.toArray(new Field[allFieldsList.size()]);
 200  
     }
 201  
 
 202  
     /**
 203  
      * Gets all fields of the given class and its parents (if any).
 204  
      * 
 205  
      * @param cls
 206  
      *            the {@link Class} to query
 207  
      * @return an array of Fields (possibly empty).
 208  
      * @throws IllegalArgumentException
 209  
      *             if the class is {@code null}
 210  
      * @since 3.2
 211  
      */
 212  
     public static List<Field> getAllFieldsList(final Class<?> cls) {
 213  14
         Validate.isTrue(cls != null, "The class must not be null");
 214  12
         final List<Field> allFields = new ArrayList<Field>();
 215  12
         Class<?> currentClass = cls;
 216  36
         while (currentClass != null) {
 217  24
             final Field[] declaredFields = currentClass.getDeclaredFields();
 218  76
             for (final Field field : declaredFields) {
 219  52
                 allFields.add(field);
 220  
             }
 221  24
             currentClass = currentClass.getSuperclass();
 222  24
         }
 223  12
         return allFields;
 224  
     }
 225  
 
 226  
     /**
 227  
      * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
 228  
      * @param cls
 229  
      *            the {@link Class} to query
 230  
      * @param annotationCls
 231  
      *            the {@link Annotation} that must be present on a field to be matched
 232  
      * @return an array of Fields (possibly empty).
 233  
      * @throws IllegalArgumentException
 234  
      *            if the class or annotation are {@code null}
 235  
      * @since 3.4
 236  
      */
 237  
     public static Field[] getFieldsWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
 238  5
         final List<Field> annotatedFieldsList = getFieldsListWithAnnotation(cls, annotationCls);
 239  2
         return annotatedFieldsList.toArray(new Field[annotatedFieldsList.size()]);
 240  
     }
 241  
 
 242  
     /**
 243  
      * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
 244  
      * @param cls
 245  
      *            the {@link Class} to query
 246  
      * @param annotationCls
 247  
      *            the {@link Annotation} that must be present on a field to be matched
 248  
      * @return a list of Fields (possibly empty).
 249  
      * @throws IllegalArgumentException
 250  
      *            if the class or annotation are {@code null}
 251  
      * @since 3.4
 252  
      */
 253  
     public static List<Field> getFieldsListWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
 254  10
         Validate.isTrue(annotationCls != null, "The annotation class must not be null");
 255  6
         final List<Field> allFields = getAllFieldsList(cls);
 256  4
         final List<Field> annotatedFields = new ArrayList<Field>();
 257  4
         for (final Field field : allFields) {
 258  16
             if (field.getAnnotation(annotationCls) != null) {
 259  4
                 annotatedFields.add(field);
 260  
             }
 261  16
         }
 262  4
         return annotatedFields;
 263  
     }
 264  
 
 265  
     /**
 266  
      * Reads an accessible {@code static} {@link Field}.
 267  
      * 
 268  
      * @param field
 269  
      *            to read
 270  
      * @return the field value
 271  
      * @throws IllegalArgumentException
 272  
      *             if the field is {@code null}, or not {@code static}
 273  
      * @throws IllegalAccessException
 274  
      *             if the field is not accessible
 275  
      */
 276  
     public static Object readStaticField(final Field field) throws IllegalAccessException {
 277  7
         return readStaticField(field, false);
 278  
     }
 279  
 
 280  
     /**
 281  
      * Reads a static {@link Field}.
 282  
      * 
 283  
      * @param field
 284  
      *            to read
 285  
      * @param forceAccess
 286  
      *            whether to break scope restrictions using the
 287  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
 288  
      * @return the field value
 289  
      * @throws IllegalArgumentException
 290  
      *             if the field is {@code null} or not {@code static}
 291  
      * @throws IllegalAccessException
 292  
      *             if the field is not made accessible
 293  
      */
 294  
     public static Object readStaticField(final Field field, final boolean forceAccess) throws IllegalAccessException {
 295  21
         Validate.isTrue(field != null, "The field must not be null");
 296  19
         Validate.isTrue(Modifier.isStatic(field.getModifiers()), "The field '%s' is not static", field.getName());
 297  15
         return readField(field, (Object) null, forceAccess);
 298  
     }
 299  
 
 300  
     /**
 301  
      * Reads the named {@code public static} {@link Field}. Superclasses will be considered.
 302  
      * 
 303  
      * @param cls
 304  
      *            the {@link Class} to reflect, must not be {@code null}
 305  
      * @param fieldName
 306  
      *            the field name to obtain
 307  
      * @return the value of the field
 308  
      * @throws IllegalArgumentException
 309  
      *             if the class is {@code null}, or the field name is blank or empty, is not {@code static}, or could
 310  
      *             not be found
 311  
      * @throws IllegalAccessException
 312  
      *             if the field is not accessible
 313  
      */
 314  
     public static Object readStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
 315  10
         return readStaticField(cls, fieldName, false);
 316  
     }
 317  
 
 318  
     /**
 319  
      * Reads the named {@code static} {@link Field}. Superclasses will be considered.
 320  
      * 
 321  
      * @param cls
 322  
      *            the {@link Class} to reflect, must not be {@code null}
 323  
      * @param fieldName
 324  
      *            the field name to obtain
 325  
      * @param forceAccess
 326  
      *            whether to break scope restrictions using the
 327  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 328  
      *            match {@code public} fields.
 329  
      * @return the Field object
 330  
      * @throws IllegalArgumentException
 331  
      *             if the class is {@code null}, or the field name is blank or empty, is not {@code static}, or could
 332  
      *             not be found
 333  
      * @throws IllegalAccessException
 334  
      *             if the field is not made accessible
 335  
      */
 336  
     public static Object readStaticField(final Class<?> cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
 337  20
         final Field field = getField(cls, fieldName, forceAccess);
 338  12
         Validate.isTrue(field != null, "Cannot locate field '%s' on %s", fieldName, cls);
 339  
         // already forced access above, don't repeat it here:
 340  10
         return readStaticField(field, false);
 341  
     }
 342  
 
 343  
     /**
 344  
      * Gets the value of a {@code static} {@link Field} by name. The field must be {@code public}. Only the specified
 345  
      * class will be considered.
 346  
      * 
 347  
      * @param cls
 348  
      *            the {@link Class} to reflect, must not be {@code null}
 349  
      * @param fieldName
 350  
      *            the field name to obtain
 351  
      * @return the value of the field
 352  
      * @throws IllegalArgumentException
 353  
      *             if the class is {@code null}, or the field name is blank or empty, is not {@code static}, or could
 354  
      *             not be found
 355  
      * @throws IllegalAccessException
 356  
      *             if the field is not accessible
 357  
      */
 358  
     public static Object readDeclaredStaticField(final Class<?> cls, final String fieldName) throws IllegalAccessException {
 359  4
         return readDeclaredStaticField(cls, fieldName, false);
 360  
     }
 361  
 
 362  
     /**
 363  
      * Gets the value of a {@code static} {@link Field} by name. Only the specified class will be considered.
 364  
      * 
 365  
      * @param cls
 366  
      *            the {@link Class} to reflect, must not be {@code null}
 367  
      * @param fieldName
 368  
      *            the field name to obtain
 369  
      * @param forceAccess
 370  
      *            whether to break scope restrictions using the
 371  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 372  
      *            match {@code public} fields.
 373  
      * @return the Field object
 374  
      * @throws IllegalArgumentException
 375  
      *             if the class is {@code null}, or the field name is blank or empty, is not {@code static}, or could
 376  
      *             not be found
 377  
      * @throws IllegalAccessException
 378  
      *             if the field is not made accessible
 379  
      */
 380  
     public static Object readDeclaredStaticField(final Class<?> cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
 381  8
         final Field field = getDeclaredField(cls, fieldName, forceAccess);
 382  8
         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
 383  
         // already forced access above, don't repeat it here:
 384  3
         return readStaticField(field, false);
 385  
     }
 386  
 
 387  
     /**
 388  
      * Reads an accessible {@link Field}.
 389  
      * 
 390  
      * @param field
 391  
      *            the field to use
 392  
      * @param target
 393  
      *            the object to call on, may be {@code null} for {@code static} fields
 394  
      * @return the field value
 395  
      * @throws IllegalArgumentException
 396  
      *             if the field is {@code null}
 397  
      * @throws IllegalAccessException
 398  
      *             if the field is not accessible
 399  
      */
 400  
     public static Object readField(final Field field, final Object target) throws IllegalAccessException {
 401  13
         return readField(field, target, false);
 402  
     }
 403  
 
 404  
     /**
 405  
      * Reads a {@link Field}.
 406  
      * 
 407  
      * @param field
 408  
      *            the field to use
 409  
      * @param target
 410  
      *            the object to call on, may be {@code null} for {@code static} fields
 411  
      * @param forceAccess
 412  
      *            whether to break scope restrictions using the
 413  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method.
 414  
      * @return the field value
 415  
      * @throws IllegalArgumentException
 416  
      *             if the field is {@code null}
 417  
      * @throws IllegalAccessException
 418  
      *             if the field is not made accessible
 419  
      */
 420  
     public static Object readField(final Field field, final Object target, final boolean forceAccess) throws IllegalAccessException {
 421  101
         Validate.isTrue(field != null, "The field must not be null");
 422  99
         if (forceAccess && !field.isAccessible()) {
 423  4
             field.setAccessible(true);
 424  
         } else {
 425  95
             MemberUtils.setAccessibleWorkaround(field);
 426  
         }
 427  99
         return field.get(target);
 428  
     }
 429  
 
 430  
     /**
 431  
      * Reads the named {@code public} {@link Field}. Superclasses will be considered.
 432  
      * 
 433  
      * @param target
 434  
      *            the object to reflect, must not be {@code null}
 435  
      * @param fieldName
 436  
      *            the field name to obtain
 437  
      * @return the value of the field
 438  
      * @throws IllegalArgumentException
 439  
      *             if the class is {@code null}, or the field name is blank or empty or could not be found
 440  
      * @throws IllegalAccessException
 441  
      *             if the named field is not {@code public}
 442  
      */
 443  
     public static Object readField(final Object target, final String fieldName) throws IllegalAccessException {
 444  22
         return readField(target, fieldName, false);
 445  
     }
 446  
 
 447  
     /**
 448  
      * Reads the named {@link Field}. Superclasses will be considered.
 449  
      * 
 450  
      * @param target
 451  
      *            the object to reflect, must not be {@code null}
 452  
      * @param fieldName
 453  
      *            the field name to obtain
 454  
      * @param forceAccess
 455  
      *            whether to break scope restrictions using the
 456  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 457  
      *            match {@code public} fields.
 458  
      * @return the field value
 459  
      * @throws IllegalArgumentException
 460  
      *             if {@code target} is {@code null}, or the field name is blank or empty or could not be found
 461  
      * @throws IllegalAccessException
 462  
      *             if the named field is not made accessible
 463  
      */
 464  
     public static Object readField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
 465  50
         Validate.isTrue(target != null, "target object must not be null");
 466  48
         final Class<?> cls = target.getClass();
 467  48
         final Field field = getField(cls, fieldName, forceAccess);
 468  42
         Validate.isTrue(field != null, "Cannot locate field %s on %s", fieldName, cls);
 469  
         // already forced access above, don't repeat it here:
 470  36
         return readField(field, target, false);
 471  
     }
 472  
 
 473  
     /**
 474  
      * Reads the named {@code public} {@link Field}. Only the class of the specified object will be considered.
 475  
      * 
 476  
      * @param target
 477  
      *            the object to reflect, must not be {@code null}
 478  
      * @param fieldName
 479  
      *            the field name to obtain
 480  
      * @return the value of the field
 481  
      * @throws IllegalArgumentException
 482  
      *             if {@code target} is {@code null}, or the field name is blank or empty or could not be found
 483  
      * @throws IllegalAccessException
 484  
      *             if the named field is not {@code public}
 485  
      */
 486  
     public static Object readDeclaredField(final Object target, final String fieldName) throws IllegalAccessException {
 487  20
         return readDeclaredField(target, fieldName, false);
 488  
     }
 489  
 
 490  
     /**
 491  
      * Gets a {@link Field} value by name. Only the class of the specified object will be considered.
 492  
      * 
 493  
      * @param target
 494  
      *            the object to reflect, must not be {@code null}
 495  
      * @param fieldName
 496  
      *            the field name to obtain
 497  
      * @param forceAccess
 498  
      *            whether to break scope restrictions using the
 499  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 500  
      *            match public fields.
 501  
      * @return the Field object
 502  
      * @throws IllegalArgumentException
 503  
      *             if {@code target} is {@code null}, or the field name is blank or empty or could not be found
 504  
      * @throws IllegalAccessException
 505  
      *             if the field is not made accessible
 506  
      */
 507  
     public static Object readDeclaredField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException {
 508  44
         Validate.isTrue(target != null, "target object must not be null");
 509  42
         final Class<?> cls = target.getClass();
 510  42
         final Field field = getDeclaredField(cls, fieldName, forceAccess);
 511  36
         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls, fieldName);
 512  
         // already forced access above, don't repeat it here:
 513  24
         return readField(field, target, false);
 514  
     }
 515  
 
 516  
     /**
 517  
      * Writes a {@code public static} {@link Field}.
 518  
      * 
 519  
      * @param field
 520  
      *            to write
 521  
      * @param value
 522  
      *            to set
 523  
      * @throws IllegalArgumentException
 524  
      *             if the field is {@code null} or not {@code static}, or {@code value} is not assignable
 525  
      * @throws IllegalAccessException
 526  
      *             if the field is not {@code public} or is {@code final}
 527  
      */
 528  
     public static void writeStaticField(final Field field, final Object value) throws IllegalAccessException {
 529  8
         writeStaticField(field, value, false);
 530  1
     }
 531  
 
 532  
     /**
 533  
      * Writes a static {@link Field}.
 534  
      * 
 535  
      * @param field
 536  
      *            to write
 537  
      * @param value
 538  
      *            to set
 539  
      * @param forceAccess
 540  
      *            whether to break scope restrictions using the
 541  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 542  
      *            match {@code public} fields.
 543  
      * @throws IllegalArgumentException
 544  
      *             if the field is {@code null} or not {@code static}, or {@code value} is not assignable
 545  
      * @throws IllegalAccessException
 546  
      *             if the field is not made accessible or is {@code final}
 547  
      */
 548  
     public static void writeStaticField(final Field field, final Object value, final boolean forceAccess) throws IllegalAccessException {
 549  27
         Validate.isTrue(field != null, "The field must not be null");
 550  27
         Validate.isTrue(Modifier.isStatic(field.getModifiers()), "The field %s.%s is not static", field.getDeclaringClass().getName(),
 551  
                 field.getName());
 552  27
         writeField(field, (Object) null, value, forceAccess);
 553  11
     }
 554  
 
 555  
     /**
 556  
      * Writes a named {@code public static} {@link Field}. Superclasses will be considered.
 557  
      * 
 558  
      * @param cls
 559  
      *            {@link Class} on which the field is to be found
 560  
      * @param fieldName
 561  
      *            to write
 562  
      * @param value
 563  
      *            to set
 564  
      * @throws IllegalArgumentException
 565  
      *             if {@code cls} is {@code null}, the field name is blank or empty, the field cannot be located or is
 566  
      *             not {@code static}, or {@code value} is not assignable
 567  
      * @throws IllegalAccessException
 568  
      *             if the field is not {@code public} or is {@code final}
 569  
      */
 570  
     public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
 571  9
         writeStaticField(cls, fieldName, value, false);
 572  2
     }
 573  
 
 574  
     /**
 575  
      * Writes a named {@code static} {@link Field}. Superclasses will be considered.
 576  
      * 
 577  
      * @param cls
 578  
      *            {@link Class} on which the field is to be found
 579  
      * @param fieldName
 580  
      *            to write
 581  
      * @param value
 582  
      *            to set
 583  
      * @param forceAccess
 584  
      *            whether to break scope restrictions using the
 585  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 586  
      *            match {@code public} fields.
 587  
      * @throws IllegalArgumentException
 588  
      *             if {@code cls} is {@code null}, the field name is blank or empty, the field cannot be located or is
 589  
      *             not {@code static}, or {@code value} is not assignable
 590  
      * @throws IllegalAccessException
 591  
      *             if the field is not made accessible or is {@code final}
 592  
      */
 593  
     public static void writeStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
 594  
             throws IllegalAccessException {
 595  17
         final Field field = getField(cls, fieldName, forceAccess);
 596  17
         Validate.isTrue(field != null, "Cannot locate field %s on %s", fieldName, cls);
 597  
         // already forced access above, don't repeat it here:
 598  11
         writeStaticField(field, value, false);
 599  6
     }
 600  
 
 601  
     /**
 602  
      * Writes a named {@code public static} {@link Field}. Only the specified class will be considered.
 603  
      * 
 604  
      * @param cls
 605  
      *            {@link Class} on which the field is to be found
 606  
      * @param fieldName
 607  
      *            to write
 608  
      * @param value
 609  
      *            to set
 610  
      * @throws IllegalArgumentException
 611  
      *             if {@code cls} is {@code null}, the field name is blank or empty, the field cannot be located or is
 612  
      *             not {@code static}, or {@code value} is not assignable
 613  
      * @throws IllegalAccessException
 614  
      *             if the field is not {@code public} or is {@code final}
 615  
      */
 616  
     public static void writeDeclaredStaticField(final Class<?> cls, final String fieldName, final Object value) throws IllegalAccessException {
 617  7
         writeDeclaredStaticField(cls, fieldName, value, false);
 618  0
     }
 619  
 
 620  
     /**
 621  
      * Writes a named {@code static} {@link Field}. Only the specified class will be considered.
 622  
      * 
 623  
      * @param cls
 624  
      *            {@link Class} on which the field is to be found
 625  
      * @param fieldName
 626  
      *            to write
 627  
      * @param value
 628  
      *            to set
 629  
      * @param forceAccess
 630  
      *            whether to break scope restrictions using the {@code AccessibleObject#setAccessible(boolean)} method.
 631  
      *            {@code false} will only match {@code public} fields.
 632  
      * @throws IllegalArgumentException
 633  
      *             if {@code cls} is {@code null}, the field name is blank or empty, the field cannot be located or is
 634  
      *             not {@code static}, or {@code value} is not assignable
 635  
      * @throws IllegalAccessException
 636  
      *             if the field is not made accessible or is {@code final}
 637  
      */
 638  
     public static void writeDeclaredStaticField(final Class<?> cls, final String fieldName, final Object value, final boolean forceAccess)
 639  
             throws IllegalAccessException {
 640  15
         final Field field = getDeclaredField(cls, fieldName, forceAccess);
 641  15
         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
 642  
         // already forced access above, don't repeat it here:
 643  9
         writeField(field, (Object) null, value, false);
 644  4
     }
 645  
 
 646  
     /**
 647  
      * Writes an accessible {@link Field}.
 648  
      * 
 649  
      * @param field
 650  
      *            to write
 651  
      * @param target
 652  
      *            the object to call on, may be {@code null} for {@code static} fields
 653  
      * @param value
 654  
      *            to set
 655  
      * @throws IllegalAccessException
 656  
      *             if the field or target is {@code null}, the field is not accessible or is {@code final}, or
 657  
      *             {@code value} is not assignable
 658  
      */
 659  
     public static void writeField(final Field field, final Object target, final Object value) throws IllegalAccessException {
 660  4
         writeField(field, target, value, false);
 661  1
     }
 662  
 
 663  
     /**
 664  
      * Writes a {@link Field}.
 665  
      * 
 666  
      * @param field
 667  
      *            to write
 668  
      * @param target
 669  
      *            the object to call on, may be {@code null} for {@code static} fields
 670  
      * @param value
 671  
      *            to set
 672  
      * @param forceAccess
 673  
      *            whether to break scope restrictions using the
 674  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 675  
      *            match {@code public} fields.
 676  
      * @throws IllegalArgumentException
 677  
      *             if the field is {@code null} or {@code value} is not assignable
 678  
      * @throws IllegalAccessException
 679  
      *             if the field is not made accessible or is {@code final}
 680  
      */
 681  
     public static void writeField(final Field field, final Object target, final Object value, final boolean forceAccess)
 682  
             throws IllegalAccessException {
 683  74
         Validate.isTrue(field != null, "The field must not be null");
 684  74
         if (forceAccess && !field.isAccessible()) {
 685  12
             field.setAccessible(true);
 686  
         } else {
 687  62
             MemberUtils.setAccessibleWorkaround(field);
 688  
         }
 689  74
         field.set(target, value);
 690  50
     }
 691  
 
 692  
     /**
 693  
      * Removes the final modifier from a {@link Field}.
 694  
      * 
 695  
      * @param field
 696  
      *            to remove the final modifier
 697  
      * @throws IllegalArgumentException
 698  
      *             if the field is {@code null}
 699  
      * @since 3.2
 700  
      */
 701  
     public static void removeFinalModifier(final Field field) {
 702  1
         removeFinalModifier(field, true);
 703  1
     }
 704  
 
 705  
     /**
 706  
      * Removes the final modifier from a {@link Field}.
 707  
      * 
 708  
      * @param field
 709  
      *            to remove the final modifier
 710  
      * @param forceAccess
 711  
      *            whether to break scope restrictions using the
 712  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 713  
      *            match {@code public} fields.
 714  
      * @throws IllegalArgumentException
 715  
      *             if the field is {@code null}
 716  
      * @since 3.3
 717  
      */
 718  
     public static void removeFinalModifier(final Field field, final boolean forceAccess) {
 719  4
         Validate.isTrue(field != null, "The field must not be null");
 720  
 
 721  
         try {
 722  4
             if (Modifier.isFinal(field.getModifiers())) {
 723  
                 // Do all JREs implement Field with a private ivar called "modifiers"?
 724  4
                 final Field modifiersField = Field.class.getDeclaredField("modifiers");
 725  4
                 final boolean doForceAccess = forceAccess && !modifiersField.isAccessible();
 726  4
                 if (doForceAccess) {
 727  2
                     modifiersField.setAccessible(true);
 728  
                 }
 729  
                 try {
 730  4
                     modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
 731  
                 } finally {
 732  4
                     if (doForceAccess) {
 733  2
                         modifiersField.setAccessible(false);
 734  
                     }
 735  
                 }
 736  
             }
 737  0
         } catch (final NoSuchFieldException ignored) {
 738  
             // The field class contains always a modifiers field
 739  2
         } catch (final IllegalAccessException ignored) {
 740  
             // The modifiers field is made accessible
 741  2
         }
 742  4
     }
 743  
 
 744  
     /**
 745  
      * Writes a {@code public} {@link Field}. Superclasses will be considered.
 746  
      * 
 747  
      * @param target
 748  
      *            the object to reflect, must not be {@code null}
 749  
      * @param fieldName
 750  
      *            the field name to obtain
 751  
      * @param value
 752  
      *            to set
 753  
      * @throws IllegalArgumentException
 754  
      *             if {@code target} is {@code null}, {@code fieldName} is blank or empty or could not be found, or
 755  
      *             {@code value} is not assignable
 756  
      * @throws IllegalAccessException
 757  
      *             if the field is not accessible
 758  
      */
 759  
     public static void writeField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
 760  12
         writeField(target, fieldName, value, false);
 761  6
     }
 762  
 
 763  
     /**
 764  
      * Writes a {@link Field}. Superclasses will be considered.
 765  
      * 
 766  
      * @param target
 767  
      *            the object to reflect, must not be {@code null}
 768  
      * @param fieldName
 769  
      *            the field name to obtain
 770  
      * @param value
 771  
      *            to set
 772  
      * @param forceAccess
 773  
      *            whether to break scope restrictions using the
 774  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 775  
      *            match {@code public} fields.
 776  
      * @throws IllegalArgumentException
 777  
      *             if {@code target} is {@code null}, {@code fieldName} is blank or empty or could not be found, or
 778  
      *             {@code value} is not assignable
 779  
      * @throws IllegalAccessException
 780  
      *             if the field is not made accessible
 781  
      */
 782  
     public static void writeField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
 783  
             throws IllegalAccessException {
 784  24
         Validate.isTrue(target != null, "target object must not be null");
 785  24
         final Class<?> cls = target.getClass();
 786  24
         final Field field = getField(cls, fieldName, forceAccess);
 787  24
         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
 788  
         // already forced access above, don't repeat it here:
 789  18
         writeField(field, target, value, false);
 790  18
     }
 791  
 
 792  
     /**
 793  
      * Writes a {@code public} {@link Field}. Only the specified class will be considered.
 794  
      * 
 795  
      * @param target
 796  
      *            the object to reflect, must not be {@code null}
 797  
      * @param fieldName
 798  
      *            the field name to obtain
 799  
      * @param value
 800  
      *            to set
 801  
      * @throws IllegalArgumentException
 802  
      *             if {@code target} is {@code null}, {@code fieldName} is blank or empty or could not be found, or
 803  
      *             {@code value} is not assignable
 804  
      * @throws IllegalAccessException
 805  
      *             if the field is not made accessible
 806  
      */
 807  
     public static void writeDeclaredField(final Object target, final String fieldName, final Object value) throws IllegalAccessException {
 808  12
         writeDeclaredField(target, fieldName, value, false);
 809  4
     }
 810  
 
 811  
     /**
 812  
      * Writes a {@code public} {@link Field}. Only the specified class will be considered.
 813  
      * 
 814  
      * @param target
 815  
      *            the object to reflect, must not be {@code null}
 816  
      * @param fieldName
 817  
      *            the field name to obtain
 818  
      * @param value
 819  
      *            to set
 820  
      * @param forceAccess
 821  
      *            whether to break scope restrictions using the
 822  
      *            {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only
 823  
      *            match {@code public} fields.
 824  
      * @throws IllegalArgumentException
 825  
      *             if {@code target} is {@code null}, {@code fieldName} is blank or empty or could not be found, or
 826  
      *             {@code value} is not assignable
 827  
      * @throws IllegalAccessException
 828  
      *             if the field is not made accessible
 829  
      */
 830  
     public static void writeDeclaredField(final Object target, final String fieldName, final Object value, final boolean forceAccess)
 831  
             throws IllegalAccessException {
 832  24
         Validate.isTrue(target != null, "target object must not be null");
 833  24
         final Class<?> cls = target.getClass();
 834  24
         final Field field = getDeclaredField(cls, fieldName, forceAccess);
 835  24
         Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName);
 836  
         // already forced access above, don't repeat it here:
 837  12
         writeField(field, target, value, false);
 838  12
     }
 839  
 }