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.ArrayUtils; 030import org.apache.commons.lang3.ClassUtils; 031import org.apache.commons.lang3.Validate; 032 033/** 034 * <p> 035 * Assists in implementing {@link Object#toString()} methods using reflection. 036 * </p> 037 * <p> 038 * This class uses reflection to determine the fields to append. Because these fields are usually private, the class 039 * uses {@link java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], boolean)} to 040 * change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions are 041 * set up correctly. 042 * </p> 043 * <p> 044 * Using reflection to access (private) fields circumvents any synchronization protection guarding access to these 045 * fields. If a toString method cannot safely read a field, you should exclude it from the toString method, or use 046 * synchronization consistent with the class' lock management around the invocation of the method. Take special care to 047 * exclude non-thread-safe collection classes, because these classes may throw ConcurrentModificationException if 048 * modified while the toString method is executing. 049 * </p> 050 * <p> 051 * A typical invocation for this method would look like: 052 * </p> 053 * <pre> 054 * public String toString() { 055 * return ReflectionToStringBuilder.toString(this); 056 * } 057 * </pre> 058 * <p> 059 * You can also use the builder to debug 3rd party objects: 060 * </p> 061 * <pre> 062 * System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject)); 063 * </pre> 064 * <p> 065 * A subclass can control field output by overriding the methods: 066 * </p> 067 * <ul> 068 * <li>{@link #accept(java.lang.reflect.Field)}</li> 069 * <li>{@link #getValue(java.lang.reflect.Field)}</li> 070 * </ul> 071 * <p> 072 * For example, this method does <i>not</i> include the {@code password} field in the returned {@code String}: 073 * </p> 074 * <pre> 075 * public String toString() { 076 * return (new ReflectionToStringBuilder(this) { 077 * protected boolean accept(Field f) { 078 * return super.accept(f) && !f.getName().equals("password"); 079 * } 080 * }).toString(); 081 * } 082 * </pre> 083 * <p> 084 * Alternatively the {@link ToStringExclude} annotation can be used to exclude fields from being incorporated in the 085 * result. 086 * </p> 087 * <p> 088 * It is also possible to use the {@link ToStringSummary} annotation to output the summary information instead of the 089 * detailed information of a field. 090 * </p> 091 * <p> 092 * The exact format of the {@code toString} is determined by the {@link ToStringStyle} passed into the constructor. 093 * </p> 094 * 095 * <p> 096 * <b>Note:</b> the default {@link ToStringStyle} will only do a "shallow" formatting, i.e. composed objects are not 097 * further traversed. To get "deep" formatting, use an instance of {@link RecursiveToStringStyle}. 098 * </p> 099 * 100 * @since 2.0 101 */ 102public class ReflectionToStringBuilder extends ToStringBuilder { 103 104 /** 105 * <p> 106 * Builds a {@code toString} value using the default {@code ToStringStyle} through reflection. 107 * </p> 108 * 109 * <p> 110 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 111 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 112 * also not as efficient as testing explicitly. 113 * </p> 114 * 115 * <p> 116 * Transient members will be not be included, as they are likely derived. Static fields will not be included. 117 * Superclass fields will be appended. 118 * </p> 119 * 120 * @param object 121 * the Object to be output 122 * @return the String result 123 * @throws IllegalArgumentException 124 * if the Object is {@code null} 125 * 126 * @see ToStringExclude 127 * @see ToStringSummary 128 */ 129 public static String toString(final Object object) { 130 return toString(object, null, false, false, null); 131 } 132 133 /** 134 * <p> 135 * Builds a {@code toString} value through reflection. 136 * </p> 137 * 138 * <p> 139 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 140 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 141 * also not as efficient as testing explicitly. 142 * </p> 143 * 144 * <p> 145 * Transient members will be not be included, as they are likely derived. Static fields will not be included. 146 * Superclass fields will be appended. 147 * </p> 148 * 149 * <p> 150 * If the style is {@code null}, the default {@code ToStringStyle} is used. 151 * </p> 152 * 153 * @param object 154 * the Object to be output 155 * @param style 156 * the style of the {@code toString} to create, may be {@code null} 157 * @return the String result 158 * @throws IllegalArgumentException 159 * if the Object or {@code ToStringStyle} is {@code null} 160 * 161 * @see ToStringExclude 162 * @see ToStringSummary 163 */ 164 public static String toString(final Object object, final ToStringStyle style) { 165 return toString(object, style, false, false, null); 166 } 167 168 /** 169 * <p> 170 * Builds a {@code toString} value through reflection. 171 * </p> 172 * 173 * <p> 174 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 175 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 176 * also not as efficient as testing explicitly. 177 * </p> 178 * 179 * <p> 180 * If the {@code outputTransients} is {@code true}, transient members will be output, otherwise they 181 * are ignored, as they are likely derived fields, and not part of the value of the Object. 182 * </p> 183 * 184 * <p> 185 * Static fields will not be included. Superclass fields will be appended. 186 * </p> 187 * 188 * <p> 189 * If the style is {@code null}, the default {@code ToStringStyle} is used. 190 * </p> 191 * 192 * @param object 193 * the Object to be output 194 * @param style 195 * the style of the {@code toString} to create, may be {@code null} 196 * @param outputTransients 197 * whether to include transient fields 198 * @return the String result 199 * @throws IllegalArgumentException 200 * if the Object is {@code null} 201 * 202 * @see ToStringExclude 203 * @see ToStringSummary 204 */ 205 public static String toString(final Object object, final ToStringStyle style, final boolean outputTransients) { 206 return toString(object, style, outputTransients, false, null); 207 } 208 209 /** 210 * <p> 211 * Builds a {@code toString} value through reflection. 212 * </p> 213 * 214 * <p> 215 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 216 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 217 * also not as efficient as testing explicitly. 218 * </p> 219 * 220 * <p> 221 * If the {@code outputTransients} is {@code true}, transient fields will be output, otherwise they 222 * are ignored, as they are likely derived fields, and not part of the value of the Object. 223 * </p> 224 * 225 * <p> 226 * If the {@code outputStatics} is {@code true}, static fields will be output, otherwise they are 227 * ignored. 228 * </p> 229 * 230 * <p> 231 * Static fields will not be included. Superclass fields will be appended. 232 * </p> 233 * 234 * <p> 235 * If the style is {@code null}, the default {@code ToStringStyle} is used. 236 * </p> 237 * 238 * @param object 239 * the Object to be output 240 * @param style 241 * the style of the {@code toString} to create, may be {@code null} 242 * @param outputTransients 243 * whether to include transient fields 244 * @param outputStatics 245 * whether to include static fields 246 * @return the String result 247 * @throws IllegalArgumentException 248 * if the Object is {@code null} 249 * 250 * @see ToStringExclude 251 * @see ToStringSummary 252 * @since 2.1 253 */ 254 public static String toString(final Object object, final ToStringStyle style, final boolean outputTransients, final boolean outputStatics) { 255 return toString(object, style, outputTransients, outputStatics, null); 256 } 257 258 /** 259 * <p> 260 * Builds a {@code toString} value through reflection. 261 * </p> 262 * 263 * <p> 264 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 265 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 266 * also not as efficient as testing explicitly. 267 * </p> 268 * 269 * <p> 270 * If the {@code outputTransients} is {@code true}, transient fields will be output, otherwise they 271 * are ignored, as they are likely derived fields, and not part of the value of the Object. 272 * </p> 273 * 274 * <p> 275 * If the {@code outputStatics} is {@code true}, static fields will be output, otherwise they are 276 * ignored. 277 * </p> 278 * 279 * <p> 280 * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as 281 * {@code java.lang.Object}. 282 * </p> 283 * 284 * <p> 285 * If the style is {@code null}, the default {@code ToStringStyle} is used. 286 * </p> 287 * 288 * @param <T> 289 * the type of the object 290 * @param object 291 * the Object to be output 292 * @param style 293 * the style of the {@code toString} to create, may be {@code null} 294 * @param outputTransients 295 * whether to include transient fields 296 * @param outputStatics 297 * whether to include static fields 298 * @param reflectUpToClass 299 * the superclass to reflect up to (inclusive), may be {@code null} 300 * @return the String result 301 * @throws IllegalArgumentException 302 * if the Object is {@code null} 303 * 304 * @see ToStringExclude 305 * @see ToStringSummary 306 * @since 2.1 307 */ 308 public static <T> String toString( 309 final T object, final ToStringStyle style, final boolean outputTransients, 310 final boolean outputStatics, final Class<? super T> reflectUpToClass) { 311 return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics) 312 .toString(); 313 } 314 315 /** 316 * <p> 317 * Builds a {@code toString} value through reflection. 318 * </p> 319 * 320 * <p> 321 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will 322 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 323 * also not as efficient as testing explicitly. 324 * </p> 325 * 326 * <p> 327 * If the {@code outputTransients} is {@code true}, transient fields will be output, otherwise they 328 * are ignored, as they are likely derived fields, and not part of the value of the Object. 329 * </p> 330 * 331 * <p> 332 * If the {@code outputStatics} is {@code true}, static fields will be output, otherwise they are 333 * ignored. 334 * </p> 335 * 336 * <p> 337 * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as 338 * {@code java.lang.Object}. 339 * </p> 340 * 341 * <p> 342 * If the style is {@code null}, the default {@code ToStringStyle} is used. 343 * </p> 344 * 345 * @param <T> 346 * the type of the object 347 * @param object 348 * the Object to be output 349 * @param style 350 * the style of the {@code toString} to create, may be {@code null} 351 * @param outputTransients 352 * whether to include transient fields 353 * @param outputStatics 354 * whether to include static fields 355 * @param excludeNullValues 356 * whether to exclude fields whose values are null 357 * @param reflectUpToClass 358 * the superclass to reflect up to (inclusive), may be {@code null} 359 * @return the String result 360 * @throws IllegalArgumentException 361 * if the Object is {@code null} 362 * 363 * @see ToStringExclude 364 * @see ToStringSummary 365 * @since 3.6 366 */ 367 public static <T> String toString( 368 final T object, final ToStringStyle style, final boolean outputTransients, 369 final boolean outputStatics, final boolean excludeNullValues, final Class<? super T> reflectUpToClass) { 370 return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics, excludeNullValues) 371 .toString(); 372 } 373 374 /** 375 * Builds a String for a toString method excluding the given field names. 376 * 377 * @param object 378 * The object to "toString". 379 * @param excludeFieldNames 380 * The field names to exclude. Null excludes nothing. 381 * @return The toString value. 382 */ 383 public static String toStringExclude(final Object object, final Collection<String> excludeFieldNames) { 384 return toStringExclude(object, toNoNullStringArray(excludeFieldNames)); 385 } 386 387 /** 388 * Converts the given Collection into an array of Strings. The returned array does not contain {@code null} 389 * entries. Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} if an array element 390 * is {@code null}. 391 * 392 * @param collection 393 * The collection to convert 394 * @return A new array of Strings. 395 */ 396 static String[] toNoNullStringArray(final Collection<String> collection) { 397 if (collection == null) { 398 return ArrayUtils.EMPTY_STRING_ARRAY; 399 } 400 return toNoNullStringArray(collection.toArray()); 401 } 402 403 /** 404 * Returns a new array of Strings without null elements. Internal method used to normalize exclude lists 405 * (arrays and collections). Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} 406 * if an array element is {@code null}. 407 * 408 * @param array 409 * The array to check 410 * @return The given array or a new array without null. 411 */ 412 static String[] toNoNullStringArray(final Object[] array) { 413 final List<String> list = new ArrayList<>(array.length); 414 for (final Object e : array) { 415 if (e != null) { 416 list.add(e.toString()); 417 } 418 } 419 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); 420 } 421 422 423 /** 424 * Builds a String for a toString method excluding the given field names. 425 * 426 * @param object 427 * The object to "toString". 428 * @param excludeFieldNames 429 * The field names to exclude 430 * @return The toString value. 431 */ 432 public static String toStringExclude(final Object object, final String... excludeFieldNames) { 433 return new ReflectionToStringBuilder(object).setExcludeFieldNames(excludeFieldNames).toString(); 434 } 435 436 private static Object checkNotNull(final Object obj) { 437 return Validate.notNull(obj, "The Object passed in should not be null."); 438 } 439 440 /** 441 * Whether or not to append static fields. 442 */ 443 private boolean appendStatics = false; 444 445 /** 446 * Whether or not to append transient fields. 447 */ 448 private boolean appendTransients = false; 449 450 /** 451 * Whether or not to append fields that are null. 452 */ 453 private boolean excludeNullValues; 454 455 /** 456 * Which field names to exclude from output. Intended for fields like {@code "password"}. 457 * 458 * @since 3.0 this is protected instead of private 459 */ 460 protected String[] excludeFieldNames; 461 462 /** 463 * The last super class to stop appending fields for. 464 */ 465 private Class<?> upToClass = null; 466 467 /** 468 * <p> 469 * Constructor. 470 * </p> 471 * 472 * <p> 473 * This constructor outputs using the default style set with {@code setDefaultStyle}. 474 * </p> 475 * 476 * @param object 477 * the Object to build a {@code toString} for, must not be {@code null} 478 * @throws IllegalArgumentException 479 * if the Object passed in is {@code null} 480 */ 481 public ReflectionToStringBuilder(final Object object) { 482 super(checkNotNull(object)); 483 } 484 485 /** 486 * <p> 487 * Constructor. 488 * </p> 489 * 490 * <p> 491 * If the style is {@code null}, the default style is used. 492 * </p> 493 * 494 * @param object 495 * the Object to build a {@code toString} for, must not be {@code null} 496 * @param style 497 * the style of the {@code toString} to create, may be {@code null} 498 * @throws IllegalArgumentException 499 * if the Object passed in is {@code null} 500 */ 501 public ReflectionToStringBuilder(final Object object, final ToStringStyle style) { 502 super(checkNotNull(object), style); 503 } 504 505 /** 506 * <p> 507 * Constructor. 508 * </p> 509 * 510 * <p> 511 * If the style is {@code null}, the default style is used. 512 * </p> 513 * 514 * <p> 515 * If the buffer is {@code null}, a new one is created. 516 * </p> 517 * 518 * @param object 519 * the Object to build a {@code toString} for 520 * @param style 521 * the style of the {@code toString} to create, may be {@code null} 522 * @param buffer 523 * the {@code StringBuffer} to populate, may be {@code null} 524 * @throws IllegalArgumentException 525 * if the Object passed in is {@code null} 526 */ 527 public ReflectionToStringBuilder(final Object object, final ToStringStyle style, final StringBuffer buffer) { 528 super(checkNotNull(object), style, buffer); 529 } 530 531 /** 532 * Constructor. 533 * 534 * @param <T> 535 * the type of the object 536 * @param object 537 * the Object to build a {@code toString} for 538 * @param style 539 * the style of the {@code toString} to create, may be {@code null} 540 * @param buffer 541 * the {@code StringBuffer} to populate, may be {@code null} 542 * @param reflectUpToClass 543 * the superclass to reflect up to (inclusive), may be {@code null} 544 * @param outputTransients 545 * whether to include transient fields 546 * @param outputStatics 547 * whether to include static fields 548 * @since 2.1 549 */ 550 public <T> ReflectionToStringBuilder( 551 final T object, final ToStringStyle style, final StringBuffer buffer, 552 final Class<? super T> reflectUpToClass, final boolean outputTransients, final boolean outputStatics) { 553 super(checkNotNull(object), style, buffer); 554 this.setUpToClass(reflectUpToClass); 555 this.setAppendTransients(outputTransients); 556 this.setAppendStatics(outputStatics); 557 } 558 559 /** 560 * Constructor. 561 * 562 * @param <T> 563 * the type of the object 564 * @param object 565 * the Object to build a {@code toString} for 566 * @param style 567 * the style of the {@code toString} to create, may be {@code null} 568 * @param buffer 569 * the {@code StringBuffer} to populate, may be {@code null} 570 * @param reflectUpToClass 571 * the superclass to reflect up to (inclusive), may be {@code null} 572 * @param outputTransients 573 * whether to include transient fields 574 * @param outputStatics 575 * whether to include static fields 576 * @param excludeNullValues 577 * whether to exclude fields who value is null 578 * @since 3.6 579 */ 580 public <T> ReflectionToStringBuilder( 581 final T object, final ToStringStyle style, final StringBuffer buffer, 582 final Class<? super T> reflectUpToClass, final boolean outputTransients, final boolean outputStatics, 583 final boolean excludeNullValues) { 584 super(checkNotNull(object), style, buffer); 585 this.setUpToClass(reflectUpToClass); 586 this.setAppendTransients(outputTransients); 587 this.setAppendStatics(outputStatics); 588 this.setExcludeNullValues(excludeNullValues); 589 } 590 591 /** 592 * Returns whether or not to append the given {@code Field}. 593 * <ul> 594 * <li>Transient fields are appended only if {@link #isAppendTransients()} returns {@code true}. 595 * <li>Static fields are appended only if {@link #isAppendStatics()} returns {@code true}. 596 * <li>Inner class fields are not appended.</li> 597 * </ul> 598 * 599 * @param field 600 * The Field to test. 601 * @return Whether or not to append the given {@code Field}. 602 */ 603 protected boolean accept(final Field field) { 604 if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) { 605 // Reject field from inner class. 606 return false; 607 } 608 if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) { 609 // Reject transient fields. 610 return false; 611 } 612 if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) { 613 // Reject static fields. 614 return false; 615 } 616 if (this.excludeFieldNames != null 617 && Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) { 618 // Reject fields from the getExcludeFieldNames list. 619 return false; 620 } 621 return !field.isAnnotationPresent(ToStringExclude.class); 622 } 623 624 /** 625 * <p> 626 * Appends the fields and values defined by the given object of the given Class. 627 * </p> 628 * 629 * <p> 630 * If a cycle is detected as an object is "toString()'ed", such an object is rendered as if 631 * {@code Object.toString()} had been called and not implemented by the object. 632 * </p> 633 * 634 * @param clazz 635 * The class of object parameter 636 */ 637 protected void appendFieldsIn(final Class<?> clazz) { 638 if (clazz.isArray()) { 639 this.reflectionAppendArray(this.getObject()); 640 return; 641 } 642 // The elements in the returned array are not sorted and are not in any particular order. 643 final Field[] fields = clazz.getDeclaredFields(); 644 Arrays.sort(fields, 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 = toNoNullStringArray(excludeFieldNamesParam); 805 Arrays.sort(this.excludeFieldNames); 806 } 807 return this; 808 } 809 810 /** 811 * <p> 812 * Sets the last super class to stop appending fields for. 813 * </p> 814 * 815 * @param clazz 816 * The last super class to stop appending fields for. 817 */ 818 public void setUpToClass(final Class<?> clazz) { 819 if (clazz != null) { 820 final Object object = getObject(); 821 if (object != null && !clazz.isInstance(object)) { 822 throw new IllegalArgumentException("Specified class is not a superclass of the object"); 823 } 824 } 825 this.upToClass = clazz; 826 } 827 828 /** 829 * <p> 830 * Gets the String built by this builder. 831 * </p> 832 * 833 * @return the built string 834 */ 835 @Override 836 public String toString() { 837 if (this.getObject() == null) { 838 return this.getStyle().getNullText(); 839 } 840 Class<?> clazz = this.getObject().getClass(); 841 this.appendFieldsIn(clazz); 842 while (clazz.getSuperclass() != null && clazz != this.getUpToClass()) { 843 clazz = clazz.getSuperclass(); 844 this.appendFieldsIn(clazz); 845 } 846 return super.toString(); 847 } 848 849}