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