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