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