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