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 */ 017 018package org.apache.commons.lang3.builder; 019 020import java.lang.reflect.AccessibleObject; 021import java.lang.reflect.Field; 022import java.lang.reflect.Modifier; 023import java.util.Arrays; 024import java.util.Collection; 025import java.util.Comparator; 026import java.util.Objects; 027 028import org.apache.commons.lang3.ArraySorter; 029import org.apache.commons.lang3.ArrayUtils; 030import org.apache.commons.lang3.ClassUtils; 031import org.apache.commons.lang3.stream.Streams; 032 033/** 034 * Assists in implementing {@link Object#toString()} methods using reflection. 035 * 036 * <p> 037 * This class uses reflection to determine the fields to append. Because these fields are usually private, the class 038 * uses {@link java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], boolean)} to 039 * change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions are 040 * set up correctly. 041 * </p> 042 * <p> 043 * Using reflection to access (private) fields circumvents any synchronization protection guarding access to these 044 * fields. If a toString method cannot safely read a field, you should exclude it from the toString method, or use 045 * synchronization consistent with the class' lock management around the invocation of the method. Take special care to 046 * exclude non-thread-safe collection classes, because these classes may throw ConcurrentModificationException if 047 * modified while the toString method is executing. 048 * </p> 049 * <p> 050 * A typical invocation for this method would look like: 051 * </p> 052 * <pre> 053 * public String toString() { 054 * return ReflectionToStringBuilder.toString(this); 055 * } 056 * </pre> 057 * <p> 058 * You can also use the builder to debug 3rd party objects: 059 * </p> 060 * <pre> 061 * System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject)); 062 * </pre> 063 * <p> 064 * A subclass can control field output by overriding the methods: 065 * </p> 066 * <ul> 067 * <li>{@link #accept(java.lang.reflect.Field)}</li> 068 * <li>{@link #getValue(java.lang.reflect.Field)}</li> 069 * </ul> 070 * <p> 071 * For example, this method does <i>not</i> include the {@code password} field in the returned {@link String}: 072 * </p> 073 * <pre> 074 * public String toString() { 075 * return (new ReflectionToStringBuilder(this) { 076 * protected boolean accept(Field f) { 077 * return super.accept(f) && !f.getName().equals("password"); 078 * } 079 * }).toString(); 080 * } 081 * </pre> 082 * <p> 083 * Alternatively the {@link ToStringExclude} annotation can be used to exclude fields from being incorporated in the 084 * result. 085 * </p> 086 * <p> 087 * It is also possible to use the {@link ToStringSummary} annotation to output the summary information instead of the 088 * detailed information of a field. 089 * </p> 090 * <p> 091 * The exact format of the {@code toString} is determined by the {@link ToStringStyle} passed into the constructor. 092 * </p> 093 * 094 * <p> 095 * <b>Note:</b> the default {@link ToStringStyle} will only do a "shallow" formatting, i.e. composed objects are not 096 * further traversed. To get "deep" formatting, use an instance of {@link RecursiveToStringStyle}. 097 * </p> 098 * 099 * @since 2.0 100 */ 101public class ReflectionToStringBuilder extends ToStringBuilder { 102 103 /** 104 * Converts the given Collection into an array of Strings. The returned array does not contain {@code null} 105 * entries. Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} if an array element 106 * is {@code null}. 107 * 108 * @param collection 109 * The collection to convert 110 * @return A new array of Strings. 111 */ 112 static String[] toNoNullStringArray(final Collection<String> collection) { 113 if (collection == null) { 114 return ArrayUtils.EMPTY_STRING_ARRAY; 115 } 116 return toNoNullStringArray(collection.toArray()); 117 } 118 119 /** 120 * Returns a new array of Strings without null elements. Internal method used to normalize exclude lists 121 * (arrays and collections). Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} 122 * if an array element is {@code null}. 123 * 124 * @param array 125 * The array to check 126 * @return The given array or a new array without null. 127 */ 128 static String[] toNoNullStringArray(final Object[] array) { 129 return Streams.nonNull(array).map(Objects::toString).toArray(String[]::new); 130 } 131 132 /** 133 * Builds a {@code toString} value using the default {@link ToStringStyle} through reflection. 134 * 135 * <p> 136 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 137 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 138 * also not as efficient as testing explicitly. 139 * </p> 140 * 141 * <p> 142 * Transient members will be not be included, as they are likely derived. Static fields will not be included. 143 * Superclass fields will be appended. 144 * </p> 145 * 146 * @param object 147 * the Object to be output 148 * @return the String result 149 * @throws IllegalArgumentException 150 * if the Object is {@code null} 151 * 152 * @see ToStringExclude 153 * @see ToStringSummary 154 */ 155 public static String toString(final Object object) { 156 return toString(object, null, false, false, null); 157 } 158 159 /** 160 * Builds a {@code toString} value through reflection. 161 * 162 * <p> 163 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 164 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 165 * also not as efficient as testing explicitly. 166 * </p> 167 * 168 * <p> 169 * Transient members will be not be included, as they are likely derived. Static fields will not be included. 170 * Superclass fields will be appended. 171 * </p> 172 * 173 * <p> 174 * If the style is {@code null}, the default {@link ToStringStyle} is used. 175 * </p> 176 * 177 * @param object 178 * the Object to be output 179 * @param style 180 * the style of the {@code toString} to create, may be {@code null} 181 * @return the String result 182 * @throws IllegalArgumentException 183 * if the Object or {@link ToStringStyle} is {@code null} 184 * 185 * @see ToStringExclude 186 * @see ToStringSummary 187 */ 188 public static String toString(final Object object, final ToStringStyle style) { 189 return toString(object, style, false, false, null); 190 } 191 192 /** 193 * Builds a {@code toString} value through reflection. 194 * 195 * <p> 196 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 197 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 198 * also not as efficient as testing explicitly. 199 * </p> 200 * 201 * <p> 202 * If the {@code outputTransients} is {@code true}, transient members will be output, otherwise they 203 * are ignored, as they are likely derived fields, and not part of the value of the Object. 204 * </p> 205 * 206 * <p> 207 * Static fields will not be included. Superclass fields will be appended. 208 * </p> 209 * 210 * <p> 211 * If the style is {@code null}, the default {@link ToStringStyle} is used. 212 * </p> 213 * 214 * @param object 215 * the Object to be output 216 * @param style 217 * the style of the {@code toString} to create, may be {@code null} 218 * @param outputTransients 219 * whether to include transient fields 220 * @return the String result 221 * @throws IllegalArgumentException 222 * if the Object is {@code null} 223 * 224 * @see ToStringExclude 225 * @see ToStringSummary 226 */ 227 public static String toString(final Object object, final ToStringStyle style, final boolean outputTransients) { 228 return toString(object, style, outputTransients, false, null); 229 } 230 231 /** 232 * Builds a {@code toString} value through reflection. 233 * 234 * <p> 235 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 236 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 237 * also not as efficient as testing explicitly. 238 * </p> 239 * 240 * <p> 241 * If the {@code outputTransients} is {@code true}, transient fields will be output, otherwise they 242 * are ignored, as they are likely derived fields, and not part of the value of the Object. 243 * </p> 244 * 245 * <p> 246 * If the {@code outputStatics} is {@code true}, static fields will be output, otherwise they are 247 * ignored. 248 * </p> 249 * 250 * <p> 251 * Static fields will not be included. Superclass fields will be appended. 252 * </p> 253 * 254 * <p> 255 * If the style is {@code null}, the default {@link ToStringStyle} is used. 256 * </p> 257 * 258 * @param object 259 * the Object to be output 260 * @param style 261 * the style of the {@code toString} to create, may be {@code null} 262 * @param outputTransients 263 * whether to include transient fields 264 * @param outputStatics 265 * whether to include static fields 266 * @return the String result 267 * @throws IllegalArgumentException 268 * if the Object is {@code null} 269 * 270 * @see ToStringExclude 271 * @see ToStringSummary 272 * @since 2.1 273 */ 274 public static String toString(final Object object, final ToStringStyle style, final boolean outputTransients, final boolean outputStatics) { 275 return toString(object, style, outputTransients, outputStatics, null); 276 } 277 278 /** 279 * Builds a {@code toString} value through reflection. 280 * 281 * <p> 282 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 283 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 284 * also not as efficient as testing explicitly. 285 * </p> 286 * 287 * <p> 288 * If the {@code outputTransients} is {@code true}, transient fields will be output, otherwise they 289 * are ignored, as they are likely derived fields, and not part of the value of the Object. 290 * </p> 291 * 292 * <p> 293 * If the {@code outputStatics} is {@code true}, static fields will be output, otherwise they are 294 * ignored. 295 * </p> 296 * 297 * <p> 298 * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as 299 * {@code java.lang.Object}. 300 * </p> 301 * 302 * <p> 303 * If the style is {@code null}, the default {@link ToStringStyle} is used. 304 * </p> 305 * 306 * @param <T> 307 * the type of the object 308 * @param object 309 * the Object to be output 310 * @param style 311 * the style of the {@code toString} to create, may be {@code null} 312 * @param outputTransients 313 * whether to include transient fields 314 * @param outputStatics 315 * whether to include static fields 316 * @param excludeNullValues 317 * whether to exclude fields whose values are null 318 * @param reflectUpToClass 319 * the superclass to reflect up to (inclusive), may be {@code null} 320 * @return the String result 321 * @throws IllegalArgumentException 322 * if the Object is {@code null} 323 * 324 * @see ToStringExclude 325 * @see ToStringSummary 326 * @since 3.6 327 */ 328 public static <T> String toString( 329 final T object, final ToStringStyle style, final boolean outputTransients, 330 final boolean outputStatics, final boolean excludeNullValues, final Class<? super T> reflectUpToClass) { 331 return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics, excludeNullValues) 332 .toString(); 333 } 334 335 /** 336 * Builds a {@code toString} value through reflection. 337 * 338 * <p> 339 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 340 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 341 * also not as efficient as testing explicitly. 342 * </p> 343 * 344 * <p> 345 * If the {@code outputTransients} is {@code true}, transient fields will be output, otherwise they 346 * are ignored, as they are likely derived fields, and not part of the value of the Object. 347 * </p> 348 * 349 * <p> 350 * If the {@code outputStatics} is {@code true}, static fields will be output, otherwise they are 351 * ignored. 352 * </p> 353 * 354 * <p> 355 * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as 356 * {@code java.lang.Object}. 357 * </p> 358 * 359 * <p> 360 * If the style is {@code null}, the default {@link ToStringStyle} is used. 361 * </p> 362 * 363 * @param <T> 364 * the type of the object 365 * @param object 366 * the Object to be output 367 * @param style 368 * the style of the {@code toString} to create, may be {@code null} 369 * @param outputTransients 370 * whether to include transient fields 371 * @param outputStatics 372 * whether to include static fields 373 * @param reflectUpToClass 374 * the superclass to reflect up to (inclusive), may be {@code null} 375 * @return the String result 376 * @throws IllegalArgumentException 377 * if the Object is {@code null} 378 * 379 * @see ToStringExclude 380 * @see ToStringSummary 381 * @since 2.1 382 */ 383 public static <T> String toString( 384 final T object, final ToStringStyle style, final boolean outputTransients, 385 final boolean outputStatics, final Class<? super T> reflectUpToClass) { 386 return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics) 387 .toString(); 388 } 389 390 /** 391 * Builds a String for a toString method excluding the given field names. 392 * 393 * @param object 394 * The object to "toString". 395 * @param excludeFieldNames 396 * The field names to exclude. Null excludes nothing. 397 * @return The toString value. 398 */ 399 public static String toStringExclude(final Object object, final Collection<String> excludeFieldNames) { 400 return toStringExclude(object, toNoNullStringArray(excludeFieldNames)); 401 } 402 403 /** 404 * Builds a String for a toString method excluding the given field names. 405 * 406 * @param object 407 * The object to "toString". 408 * @param excludeFieldNames 409 * The field names to exclude 410 * @return The toString value. 411 */ 412 public static String toStringExclude(final Object object, final String... excludeFieldNames) { 413 return new ReflectionToStringBuilder(object).setExcludeFieldNames(excludeFieldNames).toString(); 414 } 415 416 417 /** 418 * Builds a String for a toString method including the given field names. 419 * 420 * @param object 421 * The object to "toString". 422 * @param includeFieldNames 423 * {@code null} or empty means all fields are included. All fields are included by default. This method will override the default behavior. 424 * @return The toString value. 425 * @since 3.13.0 426 */ 427 public static String toStringInclude(final Object object, final Collection<String> includeFieldNames) { 428 return toStringInclude(object, toNoNullStringArray(includeFieldNames)); 429 } 430 431 /** 432 * Builds a String for a toString method including the given field names. 433 * 434 * @param object 435 * The object to "toString". 436 * @param includeFieldNames 437 * The field names to include. {@code null} or empty means all fields are included. All fields are included by default. This method will override the default 438 * behavior. 439 * @return The toString value. 440 * @since 3.13.0 441 */ 442 public static String toStringInclude(final Object object, final String... includeFieldNames) { 443 return new ReflectionToStringBuilder(object).setIncludeFieldNames(includeFieldNames).toString(); 444 } 445 446 /** 447 * Whether or not to append static fields. 448 */ 449 private boolean appendStatics; 450 451 /** 452 * Whether or not to append transient fields. 453 */ 454 private boolean appendTransients; 455 456 /** 457 * Whether or not to append fields that are null. 458 */ 459 private boolean excludeNullValues; 460 461 /** 462 * Which field names to exclude from output. Intended for fields like {@code "password"}. 463 * 464 * @since 3.0 this is protected instead of private 465 */ 466 protected String[] excludeFieldNames; 467 468 /** 469 * Field names that will be included in the output. All fields are included by default. 470 * 471 * @since 3.13.0 472 */ 473 protected String[] includeFieldNames; 474 475 /** 476 * The last super class to stop appending fields for. 477 */ 478 private Class<?> upToClass; 479 480 /** 481 * Constructs a new instance. 482 * 483 * <p> 484 * This constructor outputs using the default style set with {@code setDefaultStyle}. 485 * </p> 486 * 487 * @param object 488 * the Object to build a {@code toString} for, must not be {@code null} 489 */ 490 public ReflectionToStringBuilder(final Object object) { 491 super(object); 492 } 493 494 /** 495 * Constructs a new instance. 496 * 497 * <p> 498 * If the style is {@code null}, the default style is used. 499 * </p> 500 * 501 * @param object 502 * the Object to build a {@code toString} for, must not be {@code null} 503 * @param style 504 * the style of the {@code toString} to create, may be {@code null} 505 */ 506 public ReflectionToStringBuilder(final Object object, final ToStringStyle style) { 507 super(object, style); 508 } 509 510 /** 511 * Constructs a new instance. 512 * 513 * <p> 514 * If the style is {@code null}, the default style is used. 515 * </p> 516 * 517 * <p> 518 * If the buffer is {@code null}, a new one is created. 519 * </p> 520 * 521 * @param object 522 * the Object to build a {@code toString} for 523 * @param style 524 * the style of the {@code toString} to create, may be {@code null} 525 * @param buffer 526 * the {@link StringBuffer} to populate, may be {@code null} 527 */ 528 public ReflectionToStringBuilder(final Object object, final ToStringStyle style, final StringBuffer buffer) { 529 super(object, style, buffer); 530 } 531 532 /** 533 * Constructs a new instance. 534 * 535 * @param <T> 536 * the type of the object 537 * @param object 538 * the Object to build a {@code toString} for 539 * @param style 540 * the style of the {@code toString} to create, may be {@code null} 541 * @param buffer 542 * the {@link StringBuffer} to populate, may be {@code null} 543 * @param reflectUpToClass 544 * the superclass to reflect up to (inclusive), may be {@code null} 545 * @param outputTransients 546 * whether to include transient fields 547 * @param outputStatics 548 * whether to include static fields 549 * @since 2.1 550 */ 551 public <T> ReflectionToStringBuilder( 552 final T object, final ToStringStyle style, final StringBuffer buffer, 553 final Class<? super T> reflectUpToClass, final boolean outputTransients, final boolean outputStatics) { 554 super(object, style, buffer); 555 this.setUpToClass(reflectUpToClass); 556 this.setAppendTransients(outputTransients); 557 this.setAppendStatics(outputStatics); 558 } 559 560 /** 561 * Constructs a new instance. 562 * 563 * @param <T> 564 * the type of the object 565 * @param object 566 * the Object to build a {@code toString} for 567 * @param style 568 * the style of the {@code toString} to create, may be {@code null} 569 * @param buffer 570 * the {@link StringBuffer} to populate, may be {@code null} 571 * @param reflectUpToClass 572 * the superclass to reflect up to (inclusive), may be {@code null} 573 * @param outputTransients 574 * whether to include transient fields 575 * @param outputStatics 576 * whether to include static fields 577 * @param excludeNullValues 578 * whether to exclude fields who value is null 579 * @since 3.6 580 */ 581 public <T> ReflectionToStringBuilder( 582 final T object, final ToStringStyle style, final StringBuffer buffer, 583 final Class<? super T> reflectUpToClass, final boolean outputTransients, final boolean outputStatics, 584 final boolean excludeNullValues) { 585 super(object, style, buffer); 586 this.setUpToClass(reflectUpToClass); 587 this.setAppendTransients(outputTransients); 588 this.setAppendStatics(outputStatics); 589 this.setExcludeNullValues(excludeNullValues); 590 } 591 592 /** 593 * Returns whether or not to append the given {@link Field}. 594 * <ul> 595 * <li>Transient fields are appended only if {@link #isAppendTransients()} returns {@code true}. 596 * <li>Static fields are appended only if {@link #isAppendStatics()} returns {@code true}. 597 * <li>Inner class fields are not appended.</li> 598 * </ul> 599 * 600 * @param field 601 * The Field to test. 602 * @return Whether or not to append the given {@link Field}. 603 */ 604 protected boolean accept(final Field field) { 605 if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) { 606 // Reject field from inner class. 607 return false; 608 } 609 if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) { 610 // Reject transient fields. 611 return false; 612 } 613 if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) { 614 // Reject static fields. 615 return false; 616 } 617 618 if (this.excludeFieldNames != null 619 && Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) { 620 // Reject fields from the getExcludeFieldNames list. 621 return false; 622 } 623 624 if (ArrayUtils.isNotEmpty(includeFieldNames)) { 625 // Accept fields from the getIncludeFieldNames list. {@code null} or empty means all fields are included. All fields are included by default. 626 return Arrays.binarySearch(this.includeFieldNames, field.getName()) >= 0; 627 } 628 629 return !field.isAnnotationPresent(ToStringExclude.class); 630 } 631 632 /** 633 * Appends the fields and values defined by the given object of the given Class. 634 * 635 * <p> 636 * If a cycle is detected as an object is "toString()'ed", such an object is rendered as if 637 * {@code Object.toString()} had been called and not implemented by the object. 638 * </p> 639 * 640 * @param clazz 641 * The class of object parameter 642 */ 643 protected void appendFieldsIn(final Class<?> clazz) { 644 if (clazz.isArray()) { 645 this.reflectionAppendArray(this.getObject()); 646 return; 647 } 648 // The elements in the returned array are not sorted and are not in any particular order. 649 final Field[] fields = ArraySorter.sort(clazz.getDeclaredFields(), Comparator.comparing(Field::getName)); 650 AccessibleObject.setAccessible(fields, true); 651 for (final Field field : fields) { 652 final String fieldName = field.getName(); 653 if (this.accept(field)) { 654 try { 655 // Warning: Field.get(Object) creates wrappers objects 656 // for primitive types. 657 final Object fieldValue = this.getValue(field); 658 if (!excludeNullValues || fieldValue != null) { 659 this.append(fieldName, fieldValue, !field.isAnnotationPresent(ToStringSummary.class)); 660 } 661 } catch (final IllegalAccessException e) { 662 // this can't happen. Would get a Security exception instead throw a runtime exception in case the 663 // impossible happens. 664 throw new IllegalStateException(e); 665 } 666 } 667 } 668 } 669 670 /** 671 * Gets the excludeFieldNames. 672 * 673 * @return the excludeFieldNames. 674 */ 675 public String[] getExcludeFieldNames() { 676 return this.excludeFieldNames.clone(); 677 } 678 679 /** 680 * Gets the includeFieldNames 681 * 682 * @return the includeFieldNames. 683 * @since 3.13.0 684 */ 685 public String[] getIncludeFieldNames() { 686 return this.includeFieldNames.clone(); 687 } 688 689 /** 690 * Gets the last super class to stop appending fields for. 691 * 692 * @return The last super class to stop appending fields for. 693 */ 694 public Class<?> getUpToClass() { 695 return this.upToClass; 696 } 697 698 /** 699 * Calls {@code java.lang.reflect.Field.get(Object)}. 700 * 701 * @param field 702 * The Field to query. 703 * @return The Object from the given Field. 704 * 705 * @throws IllegalArgumentException 706 * see {@link java.lang.reflect.Field#get(Object)} 707 * @throws IllegalAccessException 708 * see {@link java.lang.reflect.Field#get(Object)} 709 * 710 * @see java.lang.reflect.Field#get(Object) 711 */ 712 protected Object getValue(final Field field) throws IllegalAccessException { 713 return field.get(this.getObject()); 714 } 715 716 /** 717 * Gets whether or not to append static fields. 718 * 719 * @return Whether or not to append static fields. 720 * @since 2.1 721 */ 722 public boolean isAppendStatics() { 723 return this.appendStatics; 724 } 725 726 /** 727 * Gets whether or not to append transient fields. 728 * 729 * @return Whether or not to append transient fields. 730 */ 731 public boolean isAppendTransients() { 732 return this.appendTransients; 733 } 734 735 /** 736 * Gets whether or not to append fields whose values are null. 737 * 738 * @return Whether or not to append fields whose values are null. 739 * @since 3.6 740 */ 741 public boolean isExcludeNullValues() { 742 return this.excludeNullValues; 743 } 744 745 /** 746 * Appends to the {@code toString} an {@link Object} array. 747 * 748 * @param array 749 * the array to add to the {@code toString} 750 * @return this 751 */ 752 public ReflectionToStringBuilder reflectionAppendArray(final Object array) { 753 this.getStyle().reflectionAppendArrayDetail(this.getStringBuffer(), null, array); 754 return this; 755 } 756 757 /** 758 * Sets whether or not to append static fields. 759 * 760 * @param appendStatics 761 * Whether or not to append static fields. 762 * @since 2.1 763 */ 764 public void setAppendStatics(final boolean appendStatics) { 765 this.appendStatics = appendStatics; 766 } 767 768 /** 769 * Sets whether or not to append transient fields. 770 * 771 * @param appendTransients 772 * Whether or not to append transient fields. 773 */ 774 public void setAppendTransients(final boolean appendTransients) { 775 this.appendTransients = appendTransients; 776 } 777 778 /** 779 * Sets the field names to exclude. 780 * 781 * @param excludeFieldNamesParam 782 * The excludeFieldNames to excluding from toString or {@code null}. 783 * @return {@code this} 784 */ 785 public ReflectionToStringBuilder setExcludeFieldNames(final String... excludeFieldNamesParam) { 786 if (excludeFieldNamesParam == null) { 787 this.excludeFieldNames = null; 788 } else { 789 // clone and remove nulls 790 this.excludeFieldNames = ArraySorter.sort(toNoNullStringArray(excludeFieldNamesParam)); 791 } 792 return this; 793 } 794 795 /** 796 * Sets whether or not to append fields whose values are null. 797 * 798 * @param excludeNullValues 799 * Whether or not to append fields whose values are null. 800 * @since 3.6 801 */ 802 public void setExcludeNullValues(final boolean excludeNullValues) { 803 this.excludeNullValues = excludeNullValues; 804 } 805 806 /** 807 * Sets the field names to include. {@code null} or empty means all fields are included. All fields are included by default. This method will override the default behavior. 808 * 809 * @param includeFieldNamesParam 810 * The includeFieldNames that must be on toString or {@code null}. 811 * @return {@code this} 812 * @since 3.13.0 813 */ 814 public ReflectionToStringBuilder setIncludeFieldNames(final String... includeFieldNamesParam) { 815 if (includeFieldNamesParam == null) { 816 this.includeFieldNames = null; 817 } else { 818 // clone and remove nulls 819 this.includeFieldNames = ArraySorter.sort(toNoNullStringArray(includeFieldNamesParam)); 820 } 821 return this; 822 } 823 824 /** 825 * Sets the last super class to stop appending fields for. 826 * 827 * @param clazz 828 * The last super class to stop appending fields for. 829 */ 830 public void setUpToClass(final Class<?> clazz) { 831 if (clazz != null) { 832 final Object object = getObject(); 833 if (object != null && !clazz.isInstance(object)) { 834 throw new IllegalArgumentException("Specified class is not a superclass of the object"); 835 } 836 } 837 this.upToClass = clazz; 838 } 839 840 /** 841 * Gets the String built by this builder. 842 * 843 * @return the built string 844 */ 845 @Override 846 public String toString() { 847 if (this.getObject() == null) { 848 return this.getStyle().getNullText(); 849 } 850 851 validate(); 852 853 Class<?> clazz = this.getObject().getClass(); 854 this.appendFieldsIn(clazz); 855 while (clazz.getSuperclass() != null && clazz != this.getUpToClass()) { 856 clazz = clazz.getSuperclass(); 857 this.appendFieldsIn(clazz); 858 } 859 return super.toString(); 860 } 861 862 /** 863 * Validates that include and exclude names do not intersect. 864 */ 865 private void validate() { 866 if (ArrayUtils.containsAny(this.excludeFieldNames, (Object[]) this.includeFieldNames)) { 867 ToStringStyle.unregister(this.getObject()); 868 throw new IllegalStateException("includeFieldNames and excludeFieldNames must not intersect"); 869 } 870 } 871 872}