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 * https://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.io.Serializable; 021import java.lang.reflect.Array; 022import java.util.Collection; 023import java.util.Map; 024import java.util.Map.Entry; 025import java.util.Objects; 026import java.util.WeakHashMap; 027 028import org.apache.commons.lang3.ClassUtils; 029import org.apache.commons.lang3.ObjectUtils; 030import org.apache.commons.lang3.StringEscapeUtils; 031import org.apache.commons.lang3.StringUtils; 032import org.apache.commons.lang3.Strings; 033 034/** 035 * Controls {@link String} formatting for {@link ToStringBuilder}. The main public interface is always via {@link ToStringBuilder}. 036 * 037 * <p> 038 * These classes are intended to be used as <em>singletons</em>. There is no need to instantiate a new style each time. A program will generally use one of the 039 * predefined constants on this class. Alternatively, the {@link StandardToStringStyle} class can be used to set the individual settings. Thus most styles can 040 * be achieved without subclassing. 041 * </p> 042 * 043 * <p> 044 * If required, a subclass can override as many or as few of the methods as it requires. Each object type (from {@code boolean} to {@code long} to 045 * {@link Object} to {@code int[]}) has its own methods to output it. Most have two versions, detail and summary. 046 * 047 * <p> 048 * For example, the detail version of the array based methods will output the whole array, whereas the summary method will just output the array length. 049 * </p> 050 * 051 * <p> 052 * If you want to format the output of certain objects, such as dates, you must create a subclass and override a method. 053 * </p> 054 * 055 * <pre> 056 * public class MyStyle extends ToStringStyle { 057 * 058 * protected void appendDetail(StringBuffer buffer, String fieldName, Object value) { 059 * if (value instanceof Date) { 060 * value = new SimpleDateFormat("yyyy-MM-dd").format(value); 061 * } 062 * buffer.append(value); 063 * } 064 * } 065 * </pre> 066 * 067 * @since 1.0 068 */ 069@SuppressWarnings("deprecation") // StringEscapeUtils 070public abstract class ToStringStyle implements Serializable { 071 072 /** 073 * Default {@link ToStringStyle}. 074 * 075 * <p> 076 * This is an inner class rather than using {@link StandardToStringStyle} to ensure its immutability. 077 * </p> 078 */ 079 private static final class DefaultToStringStyle extends ToStringStyle { 080 081 /** 082 * Required for serialization support. 083 * 084 * @see Serializable 085 */ 086 private static final long serialVersionUID = 1L; 087 088 /** 089 * Constructs a new instance. 090 * 091 * <p> 092 * Use the static constant rather than instantiating. 093 * </p> 094 */ 095 DefaultToStringStyle() { 096 } 097 098 /** 099 * Ensure Singleton after serialization. 100 * 101 * @return the singleton. 102 */ 103 private Object readResolve() { 104 return DEFAULT_STYLE; 105 } 106 } 107 108 /** 109 * {@link ToStringStyle} that outputs with JSON format. 110 * 111 * <p> 112 * This is an inner class rather than using {@link StandardToStringStyle} to ensure its immutability. 113 * </p> 114 * 115 * @since 3.4 116 * @see <a href="https://www.json.org/">json.org</a> 117 */ 118 private static final class JsonToStringStyle extends ToStringStyle { 119 120 private static final long serialVersionUID = 1L; 121 private static final String FIELD_NAME_QUOTE = "\""; 122 123 /** 124 * Constructs a new instance. 125 * 126 * <p> 127 * Use the static constant rather than instantiating. 128 * </p> 129 */ 130 JsonToStringStyle() { 131 setUseClassName(false); 132 setUseIdentityHashCode(false); 133 setContentStart("{"); 134 setContentEnd("}"); 135 setArrayStart("["); 136 setArrayEnd("]"); 137 setFieldSeparator(","); 138 setFieldNameValueSeparator(":"); 139 setNullText("null"); 140 setSummaryObjectStartText("\"<"); 141 setSummaryObjectEndText(">\""); 142 setSizeStartText("\"<size="); 143 setSizeEndText(">\""); 144 } 145 146 @Override 147 public void append(final StringBuffer buffer, final String fieldName, final boolean[] array, final Boolean fullDetail) { 148 checkAppendInput(fieldName, fullDetail); 149 super.append(buffer, fieldName, array, fullDetail); 150 } 151 152 @Override 153 public void append(final StringBuffer buffer, final String fieldName, final byte[] array, final Boolean fullDetail) { 154 checkAppendInput(fieldName, fullDetail); 155 super.append(buffer, fieldName, array, fullDetail); 156 } 157 158 @Override 159 public void append(final StringBuffer buffer, final String fieldName, final char[] array, final Boolean fullDetail) { 160 checkAppendInput(fieldName, fullDetail); 161 super.append(buffer, fieldName, array, fullDetail); 162 } 163 164 @Override 165 public void append(final StringBuffer buffer, final String fieldName, final double[] array, final Boolean fullDetail) { 166 checkAppendInput(fieldName, fullDetail); 167 super.append(buffer, fieldName, array, fullDetail); 168 } 169 170 @Override 171 public void append(final StringBuffer buffer, final String fieldName, final float[] array, final Boolean fullDetail) { 172 checkAppendInput(fieldName, fullDetail); 173 super.append(buffer, fieldName, array, fullDetail); 174 } 175 176 @Override 177 public void append(final StringBuffer buffer, final String fieldName, final int[] array, final Boolean fullDetail) { 178 checkAppendInput(fieldName, fullDetail); 179 super.append(buffer, fieldName, array, fullDetail); 180 } 181 182 @Override 183 public void append(final StringBuffer buffer, final String fieldName, final long[] array, final Boolean fullDetail) { 184 checkAppendInput(fieldName, fullDetail); 185 super.append(buffer, fieldName, array, fullDetail); 186 } 187 188 @Override 189 public void append(final StringBuffer buffer, final String fieldName, final Object value, final Boolean fullDetail) { 190 checkAppendInput(fieldName, fullDetail); 191 super.append(buffer, fieldName, value, fullDetail); 192 } 193 194 @Override 195 public void append(final StringBuffer buffer, final String fieldName, final Object[] array, final Boolean fullDetail) { 196 checkAppendInput(fieldName, fullDetail); 197 super.append(buffer, fieldName, array, fullDetail); 198 } 199 200 @Override 201 public void append(final StringBuffer buffer, final String fieldName, final short[] array, final Boolean fullDetail) { 202 checkAppendInput(fieldName, fullDetail); 203 super.append(buffer, fieldName, array, fullDetail); 204 } 205 206 @Override 207 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char value) { 208 appendValueAsString(buffer, String.valueOf(value)); 209 } 210 211 @Override 212 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection<?> coll) { 213 if (coll != null && !coll.isEmpty()) { 214 buffer.append(getArrayStart()); 215 int i = 0; 216 for (final Object item : coll) { 217 appendDetail(buffer, fieldName, i++, item); 218 } 219 buffer.append(getArrayEnd()); 220 return; 221 } 222 buffer.append(coll); 223 } 224 225 @Override 226 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Map<?, ?> map) { 227 if (map != null && !map.isEmpty()) { 228 buffer.append(getContentStart()); 229 boolean firstItem = true; 230 for (final Entry<?, ?> entry : map.entrySet()) { 231 final String keyStr = Objects.toString(entry.getKey(), null); 232 if (keyStr != null) { 233 if (firstItem) { 234 firstItem = false; 235 } else { 236 appendFieldEnd(buffer, keyStr); 237 } 238 appendFieldStart(buffer, keyStr); 239 final Object value = entry.getValue(); 240 if (value == null) { 241 appendNullText(buffer, keyStr); 242 } else { 243 appendInternal(buffer, keyStr, value, true); 244 } 245 } 246 } 247 buffer.append(getContentEnd()); 248 return; 249 } 250 buffer.append(map); 251 } 252 253 @Override 254 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { 255 if (value == null) { 256 appendNullText(buffer, fieldName); 257 return; 258 } 259 if (value instanceof String || value instanceof Character) { 260 appendValueAsString(buffer, value.toString()); 261 return; 262 } 263 if (value instanceof Number || value instanceof Boolean) { 264 buffer.append(value); 265 return; 266 } 267 final String valueAsString = value.toString(); 268 if (isJsonObject(valueAsString) || isJsonArray(valueAsString)) { 269 buffer.append(value); 270 return; 271 } 272 appendDetail(buffer, fieldName, valueAsString); 273 } 274 275 @Override 276 protected void appendFieldStart(final StringBuffer buffer, final String fieldName) { 277 checkFieldName(fieldName); 278 super.appendFieldStart(buffer, FIELD_NAME_QUOTE + StringEscapeUtils.escapeJson(fieldName) + FIELD_NAME_QUOTE); 279 } 280 281 /** 282 * Appends the given String enclosed in double-quotes to the given StringBuffer. 283 * 284 * @param buffer the StringBuffer to append the value to. 285 * @param value the value to append. 286 */ 287 private void appendValueAsString(final StringBuffer buffer, final String value) { 288 buffer.append('"').append(StringEscapeUtils.escapeJson(value)).append('"'); 289 } 290 291 private void checkAppendInput(final String fieldName, final Boolean fullDetail) { 292 checkFieldName(fieldName); 293 checkIsFullDetail(fullDetail); 294 } 295 296 private void checkFieldName(final String fieldName) { 297 if (fieldName == null) { 298 throw new UnsupportedOperationException("Field names are mandatory when using JsonToStringStyle"); 299 } 300 } 301 302 private void checkIsFullDetail(final Boolean fullDetail) { 303 if (!isFullDetail(fullDetail)) { 304 throw new UnsupportedOperationException("FullDetail must be true when using JsonToStringStyle"); 305 } 306 } 307 308 private boolean isJsonArray(final String valueAsString) { 309 return valueAsString.startsWith(getArrayStart()) && valueAsString.endsWith(getArrayEnd()); 310 } 311 312 private boolean isJsonObject(final String valueAsString) { 313 return valueAsString.startsWith(getContentStart()) && valueAsString.endsWith(getContentEnd()); 314 } 315 316 /** 317 * Ensure Singleton after serialization. 318 * 319 * @return the singleton 320 */ 321 private Object readResolve() { 322 return JSON_STYLE; 323 } 324 } 325 326 /** 327 * {@link ToStringStyle} that outputs on multiple lines. 328 * 329 * <p> 330 * This is an inner class rather than using {@link StandardToStringStyle} to ensure its immutability. 331 * </p> 332 */ 333 private static final class MultiLineToStringStyle extends ToStringStyle { 334 335 private static final long serialVersionUID = 1L; 336 337 /** 338 * Constructs a new instance. 339 * 340 * <p> 341 * Use the static constant rather than instantiating. 342 * </p> 343 */ 344 MultiLineToStringStyle() { 345 setContentStart("["); 346 setFieldSeparator(System.lineSeparator() + " "); 347 setFieldSeparatorAtStart(true); 348 setContentEnd(System.lineSeparator() + "]"); 349 } 350 351 /** 352 * Ensure Singleton after serialization. 353 * 354 * @return the singleton. 355 */ 356 private Object readResolve() { 357 return MULTI_LINE_STYLE; 358 } 359 } 360 361 /** 362 * {@link ToStringStyle} that does not print out the class name and identity hash code but prints content start and field names. 363 * 364 * <p> 365 * This is an inner class rather than using {@link StandardToStringStyle} to ensure its immutability. 366 * </p> 367 */ 368 private static final class NoClassNameToStringStyle extends ToStringStyle { 369 370 private static final long serialVersionUID = 1L; 371 372 /** 373 * Constructs a new instance. 374 * 375 * <p> 376 * Use the static constant rather than instantiating. 377 * </p> 378 */ 379 NoClassNameToStringStyle() { 380 setUseClassName(false); 381 setUseIdentityHashCode(false); 382 } 383 384 /** 385 * Ensure Singleton after serialization. 386 * 387 * @return the singleton 388 */ 389 private Object readResolve() { 390 return NO_CLASS_NAME_STYLE; 391 } 392 } 393 394 /** 395 * {@link ToStringStyle} that does not print out the field names. 396 * 397 * <p> 398 * This is an inner class rather than using {@link StandardToStringStyle} to ensure its immutability. 399 * </p> 400 */ 401 private static final class NoFieldNameToStringStyle extends ToStringStyle { 402 403 private static final long serialVersionUID = 1L; 404 405 /** 406 * Constructs a new instance. 407 * 408 * <p> 409 * Use the static constant rather than instantiating. 410 * </p> 411 */ 412 NoFieldNameToStringStyle() { 413 setUseFieldNames(false); 414 } 415 416 /** 417 * Ensure Singleton after serialization. 418 * 419 * @return the singleton 420 */ 421 private Object readResolve() { 422 return NO_FIELD_NAMES_STYLE; 423 } 424 } 425 426 /** 427 * {@link ToStringStyle} that prints out the short class name and no identity hash code. 428 * 429 * <p> 430 * This is an inner class rather than using {@link StandardToStringStyle} to ensure its immutability. 431 * </p> 432 */ 433 private static final class ShortPrefixToStringStyle extends ToStringStyle { 434 435 private static final long serialVersionUID = 1L; 436 437 /** 438 * Constructs a new instance. 439 * 440 * <p> 441 * Use the static constant rather than instantiating. 442 * </p> 443 */ 444 ShortPrefixToStringStyle() { 445 setUseShortClassName(true); 446 setUseIdentityHashCode(false); 447 } 448 449 /** 450 * Ensure {@code Singleton} after serialization. 451 * 452 * @return the singleton. 453 */ 454 private Object readResolve() { 455 return SHORT_PREFIX_STYLE; 456 } 457 } 458 459 /** 460 * {@link ToStringStyle} that does not print out the class name, identity hash code, content start or field name. 461 * 462 * <p> 463 * This is an inner class rather than using {@link StandardToStringStyle} to ensure its immutability. 464 * </p> 465 */ 466 private static final class SimpleToStringStyle extends ToStringStyle { 467 468 private static final long serialVersionUID = 1L; 469 470 /** 471 * Constructs a new instance. 472 * 473 * <p> 474 * Use the static constant rather than instantiating. 475 * </p> 476 */ 477 SimpleToStringStyle() { 478 setUseClassName(false); 479 setUseIdentityHashCode(false); 480 setUseFieldNames(false); 481 setContentStart(StringUtils.EMPTY); 482 setContentEnd(StringUtils.EMPTY); 483 } 484 485 /** 486 * Ensure <code>Singleton</ode> after serialization. 487 * 488 * @return the singleton 489 */ 490 private Object readResolve() { 491 return SIMPLE_STYLE; 492 } 493 } 494 495 /** 496 * Serialization version ID. 497 */ 498 private static final long serialVersionUID = -2587890625525655916L; 499 500 /** 501 * The default toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 502 * 503 * <pre> 504 * Person@182f0db[name=John Doe,age=33,smoker=false] 505 * </pre> 506 */ 507 public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle(); 508 509 /** 510 * The multi line toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 511 * 512 * <pre> 513 * Person@182f0db[ 514 * name=John Doe 515 * age=33 516 * smoker=false 517 * ] 518 * </pre> 519 */ 520 public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle(); 521 522 /** 523 * The no field names toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 524 * 525 * <pre> 526 * Person@182f0db[John Doe,33,false] 527 * </pre> 528 */ 529 public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle(); 530 531 /** 532 * The short prefix toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 533 * 534 * <pre> 535 * Person[name=John Doe,age=33,smoker=false] 536 * </pre> 537 * 538 * @since 2.1 539 */ 540 public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle(); 541 542 /** 543 * The simple toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 544 * 545 * <pre> 546 * John Doe,33,false 547 * </pre> 548 */ 549 public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle(); 550 551 /** 552 * The no class name toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 553 * 554 * <pre> 555 * [name=John Doe,age=33,smoker=false] 556 * </pre> 557 * 558 * @since 3.4 559 */ 560 public static final ToStringStyle NO_CLASS_NAME_STYLE = new NoClassNameToStringStyle(); 561 562 /** 563 * The JSON toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 564 * 565 * <pre> 566 * {"name": "John Doe", "age": 33, "smoker": true} 567 * </pre> 568 * 569 * <strong>Note:</strong> Since field names are mandatory in JSON, this ToStringStyle will throw an {@link UnsupportedOperationException} if no field name 570 * is passed in while appending. Furthermore This ToStringStyle will only generate valid JSON if referenced objects also produce JSON when calling 571 * {@code toString()} on them. 572 * 573 * @since 3.4 574 * @see <a href="https://www.json.org/">json.org</a> 575 */ 576 public static final ToStringStyle JSON_STYLE = new JsonToStringStyle(); 577 578 /** 579 * A registry of objects used by {@code reflectionToString} methods to detect cyclical object references and avoid infinite loops. 580 */ 581 private static final ThreadLocal<WeakHashMap<Object, Object>> REGISTRY = ThreadLocal.withInitial(WeakHashMap::new); 582 /* 583 * Note that objects of this class are generally shared between threads, so an instance variable would not be suitable here. 584 * 585 * In normal use the registry should always be left empty, because the caller should call toString() which will clean up. 586 * 587 * See LANG-792 588 */ 589 590 /** 591 * Gets the registry of objects being traversed by the {@code reflectionToString} methods in the current thread. 592 * 593 * @return Set the registry of objects being traversed. 594 */ 595 public static Map<Object, Object> getRegistry() { 596 return REGISTRY.get(); 597 } 598 599 /** 600 * Tests whether the registry contains the given object. Used by the reflection methods to avoid infinite loops. 601 * 602 * @param value The object to lookup in the registry. 603 * @return boolean {@code true} if the registry contains the given object. 604 */ 605 static boolean isRegistered(final Object value) { 606 return getRegistry().containsKey(value); 607 } 608 609 /** 610 * Registers the given object. Used by the reflection methods to avoid infinite loops. 611 * 612 * @param value The object to register. 613 */ 614 static void register(final Object value) { 615 if (value != null) { 616 getRegistry().put(value, null); 617 } 618 } 619 620 /** 621 * Unregisters the given object. 622 * 623 * <p> 624 * Used by the reflection methods to avoid infinite loops. 625 * </p> 626 * 627 * @param value The object to unregister. 628 */ 629 static void unregister(final Object value) { 630 if (value != null) { 631 final Map<Object, Object> m = getRegistry(); 632 m.remove(value); 633 if (m.isEmpty()) { 634 REGISTRY.remove(); 635 } 636 } 637 } 638 639 /** 640 * Whether to use the field names, the default is {@code true}. 641 */ 642 private boolean useFieldNames = true; 643 644 /** 645 * Whether to use the class name, the default is {@code true}. 646 */ 647 private boolean useClassName = true; 648 649 /** 650 * Whether to use short class names, the default is {@code false}. 651 */ 652 private boolean useShortClassName; 653 654 /** 655 * Whether to use the identity hash code, the default is {@code true}. 656 */ 657 private boolean useIdentityHashCode = true; 658 659 /** 660 * The content start {@code '['}. 661 */ 662 private String contentStart = "["; 663 664 /** 665 * The content end {@code ']'}. 666 */ 667 private String contentEnd = "]"; 668 669 /** 670 * The field name value separator {@code '='}. 671 */ 672 private String fieldNameValueSeparator = "="; 673 674 /** 675 * Whether the field separator should be added before any other fields. 676 */ 677 private boolean fieldSeparatorAtStart; 678 679 /** 680 * Whether the field separator should be added after any other fields. 681 */ 682 private boolean fieldSeparatorAtEnd; 683 684 /** 685 * The field separator {@code ','}. 686 */ 687 private String fieldSeparator = ","; 688 689 /** 690 * The array start <code>'{'</code>. 691 */ 692 private String arrayStart = "{"; 693 694 /** 695 * The array separator {@code ','}. 696 */ 697 private String arraySeparator = ","; 698 699 /** 700 * The detail for array content. 701 */ 702 private boolean arrayContentDetail = true; 703 704 /** 705 * The array end {@code '}'}. 706 */ 707 private String arrayEnd = "}"; 708 709 /** 710 * The value to use when fullDetail is {@code null}, the default value is {@code true}. 711 */ 712 private boolean defaultFullDetail = true; 713 714 /** 715 * The {@code null} text {@code "<null>"}. 716 */ 717 private String nullText = "<null>"; 718 719 /** 720 * The summary size text start {@code "<size="}. 721 */ 722 private String sizeStartText = "<size="; 723 724 /** 725 * The summary size text start {@code ">"}. 726 */ 727 private String sizeEndText = ">"; 728 729 /** 730 * The summary object text start {@code "<"}. 731 */ 732 private String summaryObjectStartText = "<"; 733 734 /** 735 * The summary object text start {@code ">"}. 736 */ 737 private String summaryObjectEndText = ">"; 738 739 /** 740 * Constructs a new instance. 741 */ 742 protected ToStringStyle() { 743 } 744 745 /** 746 * Appends to the {@code toString} a {@code boolean} value. 747 * 748 * @param buffer the {@link StringBuffer} to populate. 749 * @param fieldName the field name. 750 * @param value the value to add to the {@code toString}. 751 */ 752 public void append(final StringBuffer buffer, final String fieldName, final boolean value) { 753 appendFieldStart(buffer, fieldName); 754 appendDetail(buffer, fieldName, value); 755 appendFieldEnd(buffer, fieldName); 756 } 757 758 /** 759 * Appends to the {@code toString} a {@code boolean} array. 760 * 761 * @param buffer the {@link StringBuffer} to populate. 762 * @param fieldName the field name. 763 * @param array the array to add to the toString. 764 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 765 */ 766 public void append(final StringBuffer buffer, final String fieldName, final boolean[] array, final Boolean fullDetail) { 767 appendFieldStart(buffer, fieldName); 768 if (array == null) { 769 appendNullText(buffer, fieldName); 770 } else if (isFullDetail(fullDetail)) { 771 appendDetail(buffer, fieldName, array); 772 } else { 773 appendSummary(buffer, fieldName, array); 774 } 775 appendFieldEnd(buffer, fieldName); 776 } 777 778 /** 779 * Appends to the {@code toString} a {@code byte} value. 780 * 781 * @param buffer the {@link StringBuffer} to populate. 782 * @param fieldName the field name. 783 * @param value the value to add to the {@code toString}. 784 */ 785 public void append(final StringBuffer buffer, final String fieldName, final byte value) { 786 appendFieldStart(buffer, fieldName); 787 appendDetail(buffer, fieldName, value); 788 appendFieldEnd(buffer, fieldName); 789 } 790 791 /** 792 * Appends to the {@code toString} a {@code byte} array. 793 * 794 * @param buffer the {@link StringBuffer} to populate. 795 * @param fieldName the field name. 796 * @param array the array to add to the {@code toString}. 797 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 798 */ 799 public void append(final StringBuffer buffer, final String fieldName, final byte[] array, final Boolean fullDetail) { 800 appendFieldStart(buffer, fieldName); 801 if (array == null) { 802 appendNullText(buffer, fieldName); 803 } else if (isFullDetail(fullDetail)) { 804 appendDetail(buffer, fieldName, array); 805 } else { 806 appendSummary(buffer, fieldName, array); 807 } 808 appendFieldEnd(buffer, fieldName); 809 } 810 811 /** 812 * Appends to the {@code toString} a {@code char} value. 813 * 814 * @param buffer the {@link StringBuffer} to populate. 815 * @param fieldName the field name. 816 * @param value the value to add to the {@code toString}. 817 */ 818 public void append(final StringBuffer buffer, final String fieldName, final char value) { 819 appendFieldStart(buffer, fieldName); 820 appendDetail(buffer, fieldName, value); 821 appendFieldEnd(buffer, fieldName); 822 } 823 824 /** 825 * Appends to the {@code toString} a {@code char} array. 826 * 827 * @param buffer the {@link StringBuffer} to populate. 828 * @param fieldName the field name. 829 * @param array the array to add to the {@code toString}. 830 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 831 */ 832 public void append(final StringBuffer buffer, final String fieldName, final char[] array, final Boolean fullDetail) { 833 appendFieldStart(buffer, fieldName); 834 if (array == null) { 835 appendNullText(buffer, fieldName); 836 } else if (isFullDetail(fullDetail)) { 837 appendDetail(buffer, fieldName, array); 838 } else { 839 appendSummary(buffer, fieldName, array); 840 } 841 appendFieldEnd(buffer, fieldName); 842 } 843 844 /** 845 * Appends to the {@code toString} a {@code double} value. 846 * 847 * @param buffer the {@link StringBuffer} to populate. 848 * @param fieldName the field name. 849 * @param value the value to add to the {@code toString}. 850 */ 851 public void append(final StringBuffer buffer, final String fieldName, final double value) { 852 appendFieldStart(buffer, fieldName); 853 appendDetail(buffer, fieldName, value); 854 appendFieldEnd(buffer, fieldName); 855 } 856 857 /** 858 * Appends to the {@code toString} a {@code double} array. 859 * 860 * @param buffer the {@link StringBuffer} to populate. 861 * @param fieldName the field name. 862 * @param array the array to add to the toString. 863 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 864 */ 865 public void append(final StringBuffer buffer, final String fieldName, final double[] array, final Boolean fullDetail) { 866 appendFieldStart(buffer, fieldName); 867 if (array == null) { 868 appendNullText(buffer, fieldName); 869 } else if (isFullDetail(fullDetail)) { 870 appendDetail(buffer, fieldName, array); 871 } else { 872 appendSummary(buffer, fieldName, array); 873 } 874 appendFieldEnd(buffer, fieldName); 875 } 876 877 /** 878 * Appends to the {@code toString} a {@code float} value. 879 * 880 * @param buffer the {@link StringBuffer} to populate. 881 * @param fieldName the field name. 882 * @param value the value to add to the {@code toString}. 883 */ 884 public void append(final StringBuffer buffer, final String fieldName, final float value) { 885 appendFieldStart(buffer, fieldName); 886 appendDetail(buffer, fieldName, value); 887 appendFieldEnd(buffer, fieldName); 888 } 889 890 /** 891 * Appends to the {@code toString} a {@code float} array. 892 * 893 * @param buffer the {@link StringBuffer} to populate. 894 * @param fieldName the field name. 895 * @param array the array to add to the toString. 896 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 897 */ 898 public void append(final StringBuffer buffer, final String fieldName, final float[] array, final Boolean fullDetail) { 899 appendFieldStart(buffer, fieldName); 900 if (array == null) { 901 appendNullText(buffer, fieldName); 902 } else if (isFullDetail(fullDetail)) { 903 appendDetail(buffer, fieldName, array); 904 } else { 905 appendSummary(buffer, fieldName, array); 906 } 907 appendFieldEnd(buffer, fieldName); 908 } 909 910 /** 911 * Appends to the {@code toString} an {@code int} value. 912 * 913 * @param buffer the {@link StringBuffer} to populate. 914 * @param fieldName the field name. 915 * @param value the value to add to the {@code toString}. 916 */ 917 public void append(final StringBuffer buffer, final String fieldName, final int value) { 918 appendFieldStart(buffer, fieldName); 919 appendDetail(buffer, fieldName, value); 920 appendFieldEnd(buffer, fieldName); 921 } 922 923 /** 924 * Appends to the {@code toString} an {@code int} array. 925 * 926 * @param buffer the {@link StringBuffer} to populate. 927 * @param fieldName the field name. 928 * @param array the array to add to the {@code toString}. 929 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 930 */ 931 public void append(final StringBuffer buffer, final String fieldName, final int[] array, final Boolean fullDetail) { 932 appendFieldStart(buffer, fieldName); 933 if (array == null) { 934 appendNullText(buffer, fieldName); 935 } else if (isFullDetail(fullDetail)) { 936 appendDetail(buffer, fieldName, array); 937 } else { 938 appendSummary(buffer, fieldName, array); 939 } 940 appendFieldEnd(buffer, fieldName); 941 } 942 943 /** 944 * Appends to the {@code toString} a {@code long} value. 945 * 946 * @param buffer the {@link StringBuffer} to populate. 947 * @param fieldName the field name. 948 * @param value the value to add to the {@code toString}. 949 */ 950 public void append(final StringBuffer buffer, final String fieldName, final long value) { 951 appendFieldStart(buffer, fieldName); 952 appendDetail(buffer, fieldName, value); 953 appendFieldEnd(buffer, fieldName); 954 } 955 956 /** 957 * Appends to the {@code toString} a {@code long} array. 958 * 959 * @param buffer the {@link StringBuffer} to populate. 960 * @param fieldName the field name. 961 * @param array the array to add to the {@code toString}. 962 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 963 */ 964 public void append(final StringBuffer buffer, final String fieldName, final long[] array, final Boolean fullDetail) { 965 appendFieldStart(buffer, fieldName); 966 if (array == null) { 967 appendNullText(buffer, fieldName); 968 } else if (isFullDetail(fullDetail)) { 969 appendDetail(buffer, fieldName, array); 970 } else { 971 appendSummary(buffer, fieldName, array); 972 } 973 appendFieldEnd(buffer, fieldName); 974 } 975 976 /** 977 * Appends to the {@code toString} an {@link Object} value, printing the full {@code toString} of the {@link Object} passed in. 978 * 979 * @param buffer the {@link StringBuffer} to populate. 980 * @param fieldName the field name. 981 * @param value the value to add to the {@code toString}. 982 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 983 */ 984 public void append(final StringBuffer buffer, final String fieldName, final Object value, final Boolean fullDetail) { 985 appendFieldStart(buffer, fieldName); 986 if (value == null) { 987 appendNullText(buffer, fieldName); 988 } else { 989 appendInternal(buffer, fieldName, value, isFullDetail(fullDetail)); 990 } 991 appendFieldEnd(buffer, fieldName); 992 } 993 994 /** 995 * Appends to the {@code toString} an {@link Object} array. 996 * 997 * @param buffer the {@link StringBuffer} to populate. 998 * @param fieldName the field name. 999 * @param array the array to add to the toString. 1000 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 1001 */ 1002 public void append(final StringBuffer buffer, final String fieldName, final Object[] array, final Boolean fullDetail) { 1003 appendFieldStart(buffer, fieldName); 1004 if (array == null) { 1005 appendNullText(buffer, fieldName); 1006 } else if (isFullDetail(fullDetail)) { 1007 appendDetail(buffer, fieldName, array); 1008 } else { 1009 appendSummary(buffer, fieldName, array); 1010 } 1011 appendFieldEnd(buffer, fieldName); 1012 } 1013 1014 /** 1015 * Appends to the {@code toString} a {@code short} value. 1016 * 1017 * @param buffer the {@link StringBuffer} to populate. 1018 * @param fieldName the field name. 1019 * @param value the value to add to the {@code toString}. 1020 */ 1021 public void append(final StringBuffer buffer, final String fieldName, final short value) { 1022 appendFieldStart(buffer, fieldName); 1023 appendDetail(buffer, fieldName, value); 1024 appendFieldEnd(buffer, fieldName); 1025 } 1026 1027 /** 1028 * Appends to the {@code toString} a {@code short} array. 1029 * 1030 * @param buffer the {@link StringBuffer} to populate. 1031 * @param fieldName the field name. 1032 * @param array the array to add to the {@code toString}. 1033 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 1034 */ 1035 public void append(final StringBuffer buffer, final String fieldName, final short[] array, final Boolean fullDetail) { 1036 appendFieldStart(buffer, fieldName); 1037 if (array == null) { 1038 appendNullText(buffer, fieldName); 1039 } else if (isFullDetail(fullDetail)) { 1040 appendDetail(buffer, fieldName, array); 1041 } else { 1042 appendSummary(buffer, fieldName, array); 1043 } 1044 appendFieldEnd(buffer, fieldName); 1045 } 1046 1047 /** 1048 * Appends to the {@code toString} the class name. 1049 * 1050 * @param buffer the {@link StringBuffer} to populate. 1051 * @param object the {@link Object} whose name to output. 1052 */ 1053 protected void appendClassName(final StringBuffer buffer, final Object object) { 1054 if (isUseClassName() && object != null) { 1055 register(object); 1056 if (isUseShortClassName()) { 1057 buffer.append(getShortClassName(object.getClass())); 1058 } else { 1059 buffer.append(object.getClass().getName()); 1060 } 1061 } 1062 } 1063 1064 /** 1065 * Appends to the {@code toString} the content end. 1066 * 1067 * @param buffer the {@link StringBuffer} to populate. 1068 */ 1069 protected void appendContentEnd(final StringBuffer buffer) { 1070 buffer.append(getContentEnd()); 1071 } 1072 1073 /** 1074 * Appends to the {@code toString} the content start. 1075 * 1076 * @param buffer the {@link StringBuffer} to populate. 1077 */ 1078 protected void appendContentStart(final StringBuffer buffer) { 1079 buffer.append(getContentStart()); 1080 } 1081 1082 /** 1083 * Appends to the {@code toString} an {@link Object} value that has been detected to participate in a cycle. This implementation will print the standard 1084 * string value of the value. 1085 * 1086 * @param buffer the {@link StringBuffer} to populate. 1087 * @param fieldName the field name, typically not used as already appended 1088 * @param value the value to add to the {@code toString}, not {@code null}. 1089 * @since 2.2 1090 */ 1091 protected void appendCyclicObject(final StringBuffer buffer, final String fieldName, final Object value) { 1092 ObjectUtils.identityToString(buffer, value); 1093 } 1094 1095 /** 1096 * Appends to the {@code toString} a {@code boolean} value. 1097 * 1098 * @param buffer the {@link StringBuffer} to populate. 1099 * @param fieldName the field name, typically not used as already appended. 1100 * @param value the value to add to the {@code toString}. 1101 */ 1102 protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean value) { 1103 buffer.append(value); 1104 } 1105 1106 /** 1107 * Appends to the {@code toString} the detail of a {@code boolean} array. 1108 * 1109 * @param buffer the {@link StringBuffer} to populate. 1110 * @param fieldName the field name, typically not used as already appended. 1111 * @param array the array to add to the {@code toString}, not {@code null}. 1112 */ 1113 protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) { 1114 buffer.append(getArrayStart()); 1115 for (int i = 0; i < array.length; i++) { 1116 if (i > 0) { 1117 buffer.append(getArraySeparator()); 1118 } 1119 appendDetail(buffer, fieldName, array[i]); 1120 } 1121 buffer.append(getArrayEnd()); 1122 } 1123 1124 /** 1125 * Appends to the {@code toString} a {@code byte} value. 1126 * 1127 * @param buffer the {@link StringBuffer} to populate. 1128 * @param fieldName the field name, typically not used as already appended. 1129 * @param value the value to add to the {@code toString}. 1130 */ 1131 protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte value) { 1132 buffer.append(value); 1133 } 1134 1135 /** 1136 * Appends to the {@code toString} the detail of a {@code byte} array. 1137 * 1138 * @param buffer the {@link StringBuffer} to populate. 1139 * @param fieldName the field name, typically not used as already appended. 1140 * @param array the array to add to the {@code toString}, not {@code null}. 1141 */ 1142 protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) { 1143 buffer.append(getArrayStart()); 1144 for (int i = 0; i < array.length; i++) { 1145 if (i > 0) { 1146 buffer.append(getArraySeparator()); 1147 } 1148 appendDetail(buffer, fieldName, array[i]); 1149 } 1150 buffer.append(getArrayEnd()); 1151 } 1152 1153 /** 1154 * Appends to the {@code toString} a {@code char} value. 1155 * 1156 * @param buffer the {@link StringBuffer} to populate. 1157 * @param fieldName the field name, typically not used as already appended. 1158 * @param value the value to add to the {@code toString}. 1159 */ 1160 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char value) { 1161 buffer.append(value); 1162 } 1163 1164 /** 1165 * Appends to the {@code toString} the detail of a {@code char} array. 1166 * 1167 * @param buffer the {@link StringBuffer} to populate. 1168 * @param fieldName the field name, typically not used as already appended. 1169 * @param array the array to add to the {@code toString}, not {@code null}. 1170 */ 1171 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) { 1172 buffer.append(getArrayStart()); 1173 for (int i = 0; i < array.length; i++) { 1174 if (i > 0) { 1175 buffer.append(getArraySeparator()); 1176 } 1177 appendDetail(buffer, fieldName, array[i]); 1178 } 1179 buffer.append(getArrayEnd()); 1180 } 1181 1182 /** 1183 * Appends to the {@code toString} a {@link Collection}. 1184 * 1185 * @param buffer the {@link StringBuffer} to populate. 1186 * @param fieldName the field name, typically not used as already appended. 1187 * @param coll the {@link Collection} to add to the {@code toString}, not {@code null}. 1188 */ 1189 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection<?> coll) { 1190 buffer.append(coll); 1191 } 1192 1193 /** 1194 * Appends to the {@code toString} a {@code double} value. 1195 * 1196 * @param buffer the {@link StringBuffer} to populate. 1197 * @param fieldName the field name, typically not used as already appended. 1198 * @param value the value to add to the {@code toString}. 1199 */ 1200 protected void appendDetail(final StringBuffer buffer, final String fieldName, final double value) { 1201 buffer.append(value); 1202 } 1203 1204 /** 1205 * Appends to the {@code toString} the detail of a {@code double} array. 1206 * 1207 * @param buffer the {@link StringBuffer} to populate. 1208 * @param fieldName the field name, typically not used as already appended 1209 * @param array the array to add to the {@code toString}, not {@code null}. 1210 */ 1211 protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) { 1212 buffer.append(getArrayStart()); 1213 for (int i = 0; i < array.length; i++) { 1214 if (i > 0) { 1215 buffer.append(getArraySeparator()); 1216 } 1217 appendDetail(buffer, fieldName, array[i]); 1218 } 1219 buffer.append(getArrayEnd()); 1220 } 1221 1222 /** 1223 * Appends to the {@code toString} a {@code float} value. 1224 * 1225 * @param buffer the {@link StringBuffer} to populate. 1226 * @param fieldName the field name, typically not used as already appended. 1227 * @param value the value to add to the {@code toString}. 1228 */ 1229 protected void appendDetail(final StringBuffer buffer, final String fieldName, final float value) { 1230 buffer.append(value); 1231 } 1232 1233 /** 1234 * Appends to the {@code toString} the detail of a {@code float} array. 1235 * 1236 * @param buffer the {@link StringBuffer} to populate. 1237 * @param fieldName the field name, typically not used as already appended. 1238 * @param array the array to add to the {@code toString}, not {@code null}. 1239 */ 1240 protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) { 1241 buffer.append(getArrayStart()); 1242 for (int i = 0; i < array.length; i++) { 1243 if (i > 0) { 1244 buffer.append(getArraySeparator()); 1245 } 1246 appendDetail(buffer, fieldName, array[i]); 1247 } 1248 buffer.append(getArrayEnd()); 1249 } 1250 1251 /** 1252 * Appends to the {@code toString} an {@code int} value. 1253 * 1254 * @param buffer the {@link StringBuffer} to populate. 1255 * @param fieldName the field name, typically not used as already appended. 1256 * @param value the value to add to the {@code toString}. 1257 */ 1258 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int value) { 1259 buffer.append(value); 1260 } 1261 1262 /** 1263 * Appends to the {@code toString} the detail of an {@link Object} array item. 1264 * 1265 * @param buffer the {@link StringBuffer} to populate. 1266 * @param fieldName the field name, typically not used as already appended. 1267 * @param i the array item index to add. 1268 * @param item the array item to add. 1269 * @since 3.11 1270 */ 1271 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int i, final Object item) { 1272 if (i > 0) { 1273 buffer.append(getArraySeparator()); 1274 } 1275 if (item == null) { 1276 appendNullText(buffer, fieldName); 1277 } else { 1278 appendInternal(buffer, fieldName, item, isArrayContentDetail()); 1279 } 1280 } 1281 1282 /** 1283 * Appends to the {@code toString} the detail of an {@code int} array. 1284 * 1285 * @param buffer the {@link StringBuffer} to populate. 1286 * @param fieldName the field name, typically not used as already appended. 1287 * @param array the array to add to the {@code toString}, not {@code null}. 1288 */ 1289 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) { 1290 buffer.append(getArrayStart()); 1291 for (int i = 0; i < array.length; i++) { 1292 if (i > 0) { 1293 buffer.append(getArraySeparator()); 1294 } 1295 appendDetail(buffer, fieldName, array[i]); 1296 } 1297 buffer.append(getArrayEnd()); 1298 } 1299 1300 /** 1301 * Appends to the {@code toString} a {@code long} value. 1302 * 1303 * @param buffer the {@link StringBuffer} to populate. 1304 * @param fieldName the field name, typically not used as already appended. 1305 * @param value the value to add to the {@code toString}. 1306 */ 1307 protected void appendDetail(final StringBuffer buffer, final String fieldName, final long value) { 1308 buffer.append(value); 1309 } 1310 1311 /** 1312 * Appends to the {@code toString} the detail of a {@code long} array. 1313 * 1314 * @param buffer the {@link StringBuffer} to populate. 1315 * @param fieldName the field name, typically not used as already appended. 1316 * @param array the array to add to the {@code toString}, not {@code null}. 1317 */ 1318 protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) { 1319 buffer.append(getArrayStart()); 1320 for (int i = 0; i < array.length; i++) { 1321 if (i > 0) { 1322 buffer.append(getArraySeparator()); 1323 } 1324 appendDetail(buffer, fieldName, array[i]); 1325 } 1326 buffer.append(getArrayEnd()); 1327 } 1328 1329 /** 1330 * Appends to the {@code toString} a {@link Map}. 1331 * 1332 * @param buffer the {@link StringBuffer} to populate. 1333 * @param fieldName the field name, typically not used as already appended. 1334 * @param map the {@link Map} to add to the {@code toString}, not {@code null}. 1335 */ 1336 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Map<?, ?> map) { 1337 buffer.append(map); 1338 } 1339 1340 /** 1341 * Appends to the {@code toString} an {@link Object} value, printing the full detail of the {@link Object}. 1342 * 1343 * @param buffer the {@link StringBuffer} to populate. 1344 * @param fieldName the field name, typically not used as already appended. 1345 * @param value the value to add to the {@code toString}, not {@code null}. 1346 */ 1347 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { 1348 buffer.append(value); 1349 } 1350 1351 /** 1352 * Appends to the {@code toString} the detail of an {@link Object} array. 1353 * 1354 * @param buffer the {@link StringBuffer} to populate. 1355 * @param fieldName the field name, typically not used as already appended. 1356 * @param array the array to add to the {@code toString}, not {@code null}. 1357 */ 1358 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) { 1359 buffer.append(getArrayStart()); 1360 for (int i = 0; i < array.length; i++) { 1361 appendDetail(buffer, fieldName, i, array[i]); 1362 } 1363 buffer.append(getArrayEnd()); 1364 } 1365 1366 /** 1367 * Appends to the {@code toString} a {@code short} value. 1368 * 1369 * @param buffer the {@link StringBuffer} to populate. 1370 * @param fieldName the field name, typically not used as already appended. 1371 * @param value the value to add to the {@code toString}. 1372 */ 1373 protected void appendDetail(final StringBuffer buffer, final String fieldName, final short value) { 1374 buffer.append(value); 1375 } 1376 1377 /** 1378 * Appends to the {@code toString} the detail of a {@code short} array. 1379 * 1380 * @param buffer the {@link StringBuffer} to populate. 1381 * @param fieldName the field name, typically not used as already appended. 1382 * @param array the array to add to the {@code toString}, not {@code null}. 1383 */ 1384 protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) { 1385 buffer.append(getArrayStart()); 1386 for (int i = 0; i < array.length; i++) { 1387 if (i > 0) { 1388 buffer.append(getArraySeparator()); 1389 } 1390 appendDetail(buffer, fieldName, array[i]); 1391 } 1392 buffer.append(getArrayEnd()); 1393 } 1394 1395 /** 1396 * Appends to the {@code toString} the end of data indicator. 1397 * 1398 * @param buffer the {@link StringBuffer} to populate. 1399 * @param object the {@link Object} to build a {@code toString} for. 1400 */ 1401 public void appendEnd(final StringBuffer buffer, final Object object) { 1402 if (!isFieldSeparatorAtEnd()) { 1403 removeLastFieldSeparator(buffer); 1404 } 1405 appendContentEnd(buffer); 1406 unregister(object); 1407 } 1408 1409 /** 1410 * Appends to the {@code toString} the field end. 1411 * 1412 * @param buffer the {@link StringBuffer} to populate. 1413 * @param fieldName the field name, typically not used as already appended. 1414 */ 1415 protected void appendFieldEnd(final StringBuffer buffer, final String fieldName) { 1416 appendFieldSeparator(buffer); 1417 } 1418 1419 /** 1420 * Appends to the {@code toString} the field separator. 1421 * 1422 * @param buffer the {@link StringBuffer} to populate. 1423 */ 1424 protected void appendFieldSeparator(final StringBuffer buffer) { 1425 buffer.append(getFieldSeparator()); 1426 } 1427 1428 /** 1429 * Appends to the {@code toString} the field start. 1430 * 1431 * @param buffer the {@link StringBuffer} to populate. 1432 * @param fieldName the field name. 1433 */ 1434 protected void appendFieldStart(final StringBuffer buffer, final String fieldName) { 1435 if (isUseFieldNames() && fieldName != null) { 1436 buffer.append(fieldName); 1437 buffer.append(getFieldNameValueSeparator()); 1438 } 1439 } 1440 1441 /** 1442 * Appends the {@link System#identityHashCode(java.lang.Object)}. 1443 * 1444 * @param buffer the {@link StringBuffer} to populate. 1445 * @param object the {@link Object} whose id to output. 1446 */ 1447 protected void appendIdentityHashCode(final StringBuffer buffer, final Object object) { 1448 if (isUseIdentityHashCode() && object != null) { 1449 register(object); 1450 buffer.append('@'); 1451 buffer.append(ObjectUtils.identityHashCodeHex(object)); 1452 } 1453 } 1454 1455 /** 1456 * Appends to the {@code toString} an {@link Object}, correctly interpreting its type. 1457 * 1458 * <p> 1459 * This method performs the main lookup by Class type to correctly route arrays, {@link Collection}s, {@link Map}s and {@link Objects} to the appropriate 1460 * method. 1461 * </p> 1462 * 1463 * <p> 1464 * Either detail or summary views can be specified. 1465 * </p> 1466 * 1467 * <p> 1468 * If a cycle is detected, an object will be appended with the {@code Object.toString()} format. 1469 * </p> 1470 * 1471 * @param buffer the {@link StringBuffer} to populate. 1472 * @param fieldName the field name, typically not used as already appended. 1473 * @param value the value to add to the {@code toString}, not {@code null}. 1474 * @param detail output detail or not. 1475 */ 1476 protected void appendInternal(final StringBuffer buffer, final String fieldName, final Object value, final boolean detail) { 1477 if (isRegistered(value) && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) { 1478 appendCyclicObject(buffer, fieldName, value); 1479 return; 1480 } 1481 register(value); 1482 try { 1483 if (value instanceof Collection<?>) { 1484 if (detail) { 1485 appendDetail(buffer, fieldName, (Collection<?>) value); 1486 } else { 1487 appendSummarySize(buffer, fieldName, ((Collection<?>) value).size()); 1488 } 1489 } else if (value instanceof Map<?, ?>) { 1490 if (detail) { 1491 appendDetail(buffer, fieldName, (Map<?, ?>) value); 1492 } else { 1493 appendSummarySize(buffer, fieldName, ((Map<?, ?>) value).size()); 1494 } 1495 } else if (value instanceof long[]) { 1496 if (detail) { 1497 appendDetail(buffer, fieldName, (long[]) value); 1498 } else { 1499 appendSummary(buffer, fieldName, (long[]) value); 1500 } 1501 } else if (value instanceof int[]) { 1502 if (detail) { 1503 appendDetail(buffer, fieldName, (int[]) value); 1504 } else { 1505 appendSummary(buffer, fieldName, (int[]) value); 1506 } 1507 } else if (value instanceof short[]) { 1508 if (detail) { 1509 appendDetail(buffer, fieldName, (short[]) value); 1510 } else { 1511 appendSummary(buffer, fieldName, (short[]) value); 1512 } 1513 } else if (value instanceof byte[]) { 1514 if (detail) { 1515 appendDetail(buffer, fieldName, (byte[]) value); 1516 } else { 1517 appendSummary(buffer, fieldName, (byte[]) value); 1518 } 1519 } else if (value instanceof char[]) { 1520 if (detail) { 1521 appendDetail(buffer, fieldName, (char[]) value); 1522 } else { 1523 appendSummary(buffer, fieldName, (char[]) value); 1524 } 1525 } else if (value instanceof double[]) { 1526 if (detail) { 1527 appendDetail(buffer, fieldName, (double[]) value); 1528 } else { 1529 appendSummary(buffer, fieldName, (double[]) value); 1530 } 1531 } else if (value instanceof float[]) { 1532 if (detail) { 1533 appendDetail(buffer, fieldName, (float[]) value); 1534 } else { 1535 appendSummary(buffer, fieldName, (float[]) value); 1536 } 1537 } else if (value instanceof boolean[]) { 1538 if (detail) { 1539 appendDetail(buffer, fieldName, (boolean[]) value); 1540 } else { 1541 appendSummary(buffer, fieldName, (boolean[]) value); 1542 } 1543 } else if (ObjectUtils.isArray(value)) { 1544 if (detail) { 1545 appendDetail(buffer, fieldName, (Object[]) value); 1546 } else { 1547 appendSummary(buffer, fieldName, (Object[]) value); 1548 } 1549 } else if (detail) { 1550 appendDetail(buffer, fieldName, value); 1551 } else { 1552 appendSummary(buffer, fieldName, value); 1553 } 1554 } finally { 1555 unregister(value); 1556 } 1557 } 1558 1559 /** 1560 * Appends to the {@code toString} an indicator for {@code null}. 1561 * 1562 * <p> 1563 * The default indicator is {@code "<null>"}. 1564 * </p> 1565 * 1566 * @param buffer the {@link StringBuffer} to populate. 1567 * @param fieldName the field name, typically not used as already appended. 1568 */ 1569 protected void appendNullText(final StringBuffer buffer, final String fieldName) { 1570 buffer.append(getNullText()); 1571 } 1572 1573 /** 1574 * Appends to the {@code toString} the start of data indicator. 1575 * 1576 * @param buffer the {@link StringBuffer} to populate. 1577 * @param object the {@link Object} to build a {@code toString} for. 1578 */ 1579 public void appendStart(final StringBuffer buffer, final Object object) { 1580 if (object != null) { 1581 appendClassName(buffer, object); 1582 appendIdentityHashCode(buffer, object); 1583 appendContentStart(buffer); 1584 if (isFieldSeparatorAtStart()) { 1585 appendFieldSeparator(buffer); 1586 } 1587 } 1588 } 1589 1590 /** 1591 * Appends to the {@code toString} a summary of a {@code boolean} array. 1592 * 1593 * @param buffer the {@link StringBuffer} to populate. 1594 * @param fieldName the field name, typically not used as already appended. 1595 * @param array the array to add to the {@code toString}, not {@code null}. 1596 */ 1597 protected void appendSummary(final StringBuffer buffer, final String fieldName, final boolean[] array) { 1598 appendSummarySize(buffer, fieldName, array.length); 1599 } 1600 1601 /** 1602 * Appends to the {@code toString} a summary of a {@code byte} array. 1603 * 1604 * @param buffer the {@link StringBuffer} to populate. 1605 * @param fieldName the field name, typically not used as already appended. 1606 * @param array the array to add to the {@code toString}, not {@code null}. 1607 */ 1608 protected void appendSummary(final StringBuffer buffer, final String fieldName, final byte[] array) { 1609 appendSummarySize(buffer, fieldName, array.length); 1610 } 1611 1612 /** 1613 * Appends to the {@code toString} a summary of a {@code char} array. 1614 * 1615 * @param buffer the {@link StringBuffer} to populate. 1616 * @param fieldName the field name, typically not used as already appended. 1617 * @param array the array to add to the {@code toString}, not {@code null}. 1618 */ 1619 protected void appendSummary(final StringBuffer buffer, final String fieldName, final char[] array) { 1620 appendSummarySize(buffer, fieldName, array.length); 1621 } 1622 1623 /** 1624 * Appends to the {@code toString} a summary of a {@code double} array. 1625 * 1626 * @param buffer the {@link StringBuffer} to populate 1627 * @param fieldName the field name, typically not used as already appended 1628 * @param array the array to add to the {@code toString}, not {@code null} 1629 */ 1630 protected void appendSummary(final StringBuffer buffer, final String fieldName, final double[] array) { 1631 appendSummarySize(buffer, fieldName, array.length); 1632 } 1633 1634 /** 1635 * Appends to the {@code toString} a summary of a {@code float} array. 1636 * 1637 * @param buffer the {@link StringBuffer} to populate. 1638 * @param fieldName the field name, typically not used as already appended. 1639 * @param array the array to add to the {@code toString}, not {@code null}. 1640 */ 1641 protected void appendSummary(final StringBuffer buffer, final String fieldName, final float[] array) { 1642 appendSummarySize(buffer, fieldName, array.length); 1643 } 1644 1645 /** 1646 * Appends to the {@code toString} a summary of an {@code int} array. 1647 * 1648 * @param buffer the {@link StringBuffer} to populate. 1649 * @param fieldName the field name, typically not used as already appended. 1650 * @param array the array to add to the {@code toString}, not {@code null}. 1651 */ 1652 protected void appendSummary(final StringBuffer buffer, final String fieldName, final int[] array) { 1653 appendSummarySize(buffer, fieldName, array.length); 1654 } 1655 1656 /** 1657 * Appends to the {@code toString} a summary of a {@code long} array. 1658 * 1659 * @param buffer the {@link StringBuffer} to populate. 1660 * @param fieldName the field name, typically not used as already appended. 1661 * @param array the array to add to the {@code toString}, not {@code null}. 1662 */ 1663 protected void appendSummary(final StringBuffer buffer, final String fieldName, final long[] array) { 1664 appendSummarySize(buffer, fieldName, array.length); 1665 } 1666 1667 /** 1668 * Appends to the {@code toString} an {@link Object} value, printing a summary of the {@link Object}. 1669 * 1670 * @param buffer the {@link StringBuffer} to populate. 1671 * @param fieldName the field name, typically not used as already appended. 1672 * @param value the value to add to the {@code toString}, not {@code null}. 1673 */ 1674 protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object value) { 1675 buffer.append(getSummaryObjectStartText()); 1676 buffer.append(getShortClassName(value.getClass())); 1677 buffer.append(getSummaryObjectEndText()); 1678 } 1679 1680 /** 1681 * Appends to the {@code toString} a summary of an {@link Object} array. 1682 * 1683 * @param buffer the {@link StringBuffer} to populate. 1684 * @param fieldName the field name, typically not used as already appended. 1685 * @param array the array to add to the {@code toString}, not {@code null}. 1686 */ 1687 protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object[] array) { 1688 appendSummarySize(buffer, fieldName, array.length); 1689 } 1690 1691 /** 1692 * Appends to the {@code toString} a summary of a {@code short} array. 1693 * 1694 * @param buffer the {@link StringBuffer} to populate. 1695 * @param fieldName the field name, typically not used as already appended. 1696 * @param array the array to add to the {@code toString}, not {@code null}. 1697 */ 1698 protected void appendSummary(final StringBuffer buffer, final String fieldName, final short[] array) { 1699 appendSummarySize(buffer, fieldName, array.length); 1700 } 1701 1702 /** 1703 * Appends to the {@code toString} a size summary. 1704 * 1705 * <p> 1706 * The size summary is used to summarize the contents of {@link Collection}s, {@link Map}s and arrays. 1707 * </p> 1708 * 1709 * <p> 1710 * The output consists of a prefix, the passed in size and a suffix. 1711 * </p> 1712 * 1713 * <p> 1714 * The default format is {@code "<size=n>"}. 1715 * </p> 1716 * 1717 * @param buffer the {@link StringBuffer} to populate. 1718 * @param fieldName the field name, typically not used as already appended. 1719 * @param size the size to append. 1720 */ 1721 protected void appendSummarySize(final StringBuffer buffer, final String fieldName, final int size) { 1722 buffer.append(getSizeStartText()); 1723 buffer.append(size); 1724 buffer.append(getSizeEndText()); 1725 } 1726 1727 /** 1728 * Appends to the {@code toString} the superclass toString. 1729 * <p> 1730 * NOTE: It assumes that the toString has been created from the same ToStringStyle. 1731 * </p> 1732 * 1733 * <p> 1734 * A {@code null} {@code superToString} is ignored. 1735 * </p> 1736 * 1737 * @param buffer the {@link StringBuffer} to populate. 1738 * @param superToString the {@code super.toString()}. 1739 * @since 2.0 1740 */ 1741 public void appendSuper(final StringBuffer buffer, final String superToString) { 1742 appendToString(buffer, superToString); 1743 } 1744 1745 /** 1746 * Appends to the {@code toString} another toString. 1747 * <p> 1748 * NOTE: It assumes that the toString has been created from the same ToStringStyle. 1749 * </p> 1750 * 1751 * <p> 1752 * A {@code null} {@code toString} is ignored. 1753 * </p> 1754 * 1755 * @param buffer the {@link StringBuffer} to populate. 1756 * @param toString the additional {@code toString}. 1757 * @since 2.0 1758 */ 1759 public void appendToString(final StringBuffer buffer, final String toString) { 1760 if (toString != null) { 1761 final int pos1 = toString.indexOf(getContentStart()) + getContentStart().length(); 1762 final int pos2 = toString.lastIndexOf(getContentEnd()); 1763 if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) { 1764 if (isFieldSeparatorAtStart()) { 1765 removeLastFieldSeparator(buffer); 1766 } 1767 buffer.append(toString, pos1, pos2); 1768 appendFieldSeparator(buffer); 1769 } 1770 } 1771 } 1772 1773 /** 1774 * Gets the array end text. 1775 * 1776 * @return the current array end text. 1777 */ 1778 protected String getArrayEnd() { 1779 return arrayEnd; 1780 } 1781 1782 /** 1783 * Gets the array separator text. 1784 * 1785 * @return the current array separator text. 1786 */ 1787 protected String getArraySeparator() { 1788 return arraySeparator; 1789 } 1790 1791 /** 1792 * Gets the array start text. 1793 * 1794 * @return the current array start text. 1795 */ 1796 protected String getArrayStart() { 1797 return arrayStart; 1798 } 1799 1800 /** 1801 * Gets the content end text. 1802 * 1803 * @return the current content end text. 1804 */ 1805 protected String getContentEnd() { 1806 return contentEnd; 1807 } 1808 1809 /** 1810 * Gets the content start text. 1811 * 1812 * @return the current content start text. 1813 */ 1814 protected String getContentStart() { 1815 return contentStart; 1816 } 1817 1818 /** 1819 * Gets the field name value separator text. 1820 * 1821 * @return the current field name value separator text. 1822 */ 1823 protected String getFieldNameValueSeparator() { 1824 return fieldNameValueSeparator; 1825 } 1826 1827 /** 1828 * Gets the field separator text. 1829 * 1830 * @return the current field separator text. 1831 */ 1832 protected String getFieldSeparator() { 1833 return fieldSeparator; 1834 } 1835 1836 /** 1837 * Gets the text to output when {@code null} found. 1838 * 1839 * @return the current text to output when null found. 1840 */ 1841 protected String getNullText() { 1842 return nullText; 1843 } 1844 1845 /** 1846 * Gets the short class name for a class. 1847 * 1848 * <p> 1849 * The short class name is the class name excluding the package name. 1850 * </p> 1851 * 1852 * @param cls the {@link Class} to get the short name of. 1853 * @return the short name. 1854 */ 1855 protected String getShortClassName(final Class<?> cls) { 1856 return ClassUtils.getShortClassName(cls); 1857 } 1858 1859 /** 1860 * Gets the end text to output when a {@link Collection}, {@link Map} or array size is output. 1861 * 1862 * <p> 1863 * This is output after the size value. 1864 * </p> 1865 * 1866 * @return the current end of size text. 1867 */ 1868 protected String getSizeEndText() { 1869 return sizeEndText; 1870 } 1871 1872 /** 1873 * Gets the start text to output when a {@link Collection}, {@link Map} or array size is output. 1874 * 1875 * <p> 1876 * This is output before the size value. 1877 * </p> 1878 * 1879 * @return the current start of size text. 1880 */ 1881 protected String getSizeStartText() { 1882 return sizeStartText; 1883 } 1884 1885 /** 1886 * Gets the end text to output when an {@link Object} is output in summary mode. 1887 * 1888 * <p> 1889 * This is output after the size value. 1890 * </p> 1891 * 1892 * @return the current end of summary text. 1893 */ 1894 protected String getSummaryObjectEndText() { 1895 return summaryObjectEndText; 1896 } 1897 1898 /** 1899 * Gets the start text to output when an {@link Object} is output in summary mode. 1900 * 1901 * <p> 1902 * This is output before the size value. 1903 * </p> 1904 * 1905 * @return the current start of summary text. 1906 */ 1907 protected String getSummaryObjectStartText() { 1908 return summaryObjectStartText; 1909 } 1910 1911 /** 1912 * Gets whether to output array content detail. 1913 * 1914 * @return the current array content detail setting. 1915 */ 1916 protected boolean isArrayContentDetail() { 1917 return arrayContentDetail; 1918 } 1919 1920 /** 1921 * Gets whether to use full detail when the caller doesn't specify. 1922 * 1923 * @return the current defaultFullDetail flag. 1924 */ 1925 protected boolean isDefaultFullDetail() { 1926 return defaultFullDetail; 1927 } 1928 1929 /** 1930 * Gets whether the field separator should be added at the end of each buffer. 1931 * 1932 * @return fieldSeparatorAtEnd flag. 1933 * @since 2.0 1934 */ 1935 protected boolean isFieldSeparatorAtEnd() { 1936 return fieldSeparatorAtEnd; 1937 } 1938 1939 /** 1940 * Gets whether the field separator should be added at the start of each buffer. 1941 * 1942 * @return the fieldSeparatorAtStart flag. 1943 * @since 2.0 1944 */ 1945 protected boolean isFieldSeparatorAtStart() { 1946 return fieldSeparatorAtStart; 1947 } 1948 1949 /** 1950 * Is this field to be output in full detail. 1951 * 1952 * <p> 1953 * This method converts a detail request into a detail level. The calling code may request full detail ({@code true}), but a subclass might ignore that and 1954 * always return {@code false}. The calling code may pass in {@code null} indicating that it doesn't care about the detail level. In this case the default 1955 * detail level is used. 1956 * </p> 1957 * 1958 * @param fullDetailRequest the detail level requested. 1959 * @return whether full detail is to be shown. 1960 */ 1961 protected boolean isFullDetail(final Boolean fullDetailRequest) { 1962 if (fullDetailRequest == null) { 1963 return isDefaultFullDetail(); 1964 } 1965 return fullDetailRequest.booleanValue(); 1966 } 1967 1968 // Setters and getters for the customizable parts of the style 1969 // These methods are not expected to be overridden, except to make public 1970 // (They are not public so that immutable subclasses can be written) 1971 /** 1972 * Gets whether to use the class name. 1973 * 1974 * @return the current useClassName flag. 1975 */ 1976 protected boolean isUseClassName() { 1977 return useClassName; 1978 } 1979 1980 /** 1981 * Gets whether to use the field names passed in. 1982 * 1983 * @return the current useFieldNames flag. 1984 */ 1985 protected boolean isUseFieldNames() { 1986 return useFieldNames; 1987 } 1988 1989 /** 1990 * Gets whether to use the identity hash code. 1991 * 1992 * @return the current useIdentityHashCode flag. 1993 */ 1994 protected boolean isUseIdentityHashCode() { 1995 return useIdentityHashCode; 1996 } 1997 1998 /** 1999 * Gets whether to output short or long class names. 2000 * 2001 * @return the current useShortClassName flag. 2002 * @since 2.0 2003 */ 2004 protected boolean isUseShortClassName() { 2005 return useShortClassName; 2006 } 2007 2008 /** 2009 * Appends to the {@code toString} the detail of an array type. 2010 * 2011 * @param buffer the {@link StringBuffer} to populate. 2012 * @param fieldName the field name, typically not used as already appended. 2013 * @param array the array to add to the {@code toString}, not {@code null}. 2014 * @since 2.0 2015 */ 2016 protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) { 2017 buffer.append(getArrayStart()); 2018 final int length = Array.getLength(array); 2019 for (int i = 0; i < length; i++) { 2020 appendDetail(buffer, fieldName, i, Array.get(array, i)); 2021 } 2022 buffer.append(getArrayEnd()); 2023 } 2024 2025 /** 2026 * Remove the last field separator from the buffer. 2027 * 2028 * @param buffer the {@link StringBuffer} to populate. 2029 * @since 2.0 2030 */ 2031 protected void removeLastFieldSeparator(final StringBuffer buffer) { 2032 if (Strings.CS.endsWith(buffer, getFieldSeparator())) { 2033 buffer.setLength(buffer.length() - getFieldSeparator().length()); 2034 } 2035 } 2036 2037 /** 2038 * Sets whether to output array content detail. 2039 * 2040 * @param arrayContentDetail the new arrayContentDetail flag. 2041 */ 2042 protected void setArrayContentDetail(final boolean arrayContentDetail) { 2043 this.arrayContentDetail = arrayContentDetail; 2044 } 2045 2046 /** 2047 * Sets the array end text. 2048 * 2049 * <p> 2050 * {@code null} is accepted, but will be converted to an empty String. 2051 * </p> 2052 * 2053 * @param arrayEnd the new array end text. 2054 */ 2055 protected void setArrayEnd(final String arrayEnd) { 2056 this.arrayEnd = ObjectUtils.toString(arrayEnd); 2057 } 2058 2059 /** 2060 * Sets the array separator text. 2061 * 2062 * <p> 2063 * {@code null} is accepted, but will be converted to an empty String. 2064 * </p> 2065 * 2066 * @param arraySeparator the new array separator text. 2067 */ 2068 protected void setArraySeparator(final String arraySeparator) { 2069 this.arraySeparator = ObjectUtils.toString(arraySeparator); 2070 } 2071 2072 /** 2073 * Sets the array start text. 2074 * 2075 * <p> 2076 * {@code null} is accepted, but will be converted to an empty String. 2077 * </p> 2078 * 2079 * @param arrayStart the new array start text. 2080 */ 2081 protected void setArrayStart(final String arrayStart) { 2082 this.arrayStart = ObjectUtils.toString(arrayStart); 2083 } 2084 2085 /** 2086 * Sets the content end text. 2087 * 2088 * <p> 2089 * {@code null} is accepted, but will be converted to an empty String. 2090 * </p> 2091 * 2092 * @param contentEnd the new content end text. 2093 */ 2094 protected void setContentEnd(final String contentEnd) { 2095 this.contentEnd = ObjectUtils.toString(contentEnd); 2096 } 2097 2098 /** 2099 * Sets the content start text. 2100 * 2101 * <p> 2102 * {@code null} is accepted, but will be converted to an empty String. 2103 * </p> 2104 * 2105 * @param contentStart the new content start text. 2106 */ 2107 protected void setContentStart(final String contentStart) { 2108 this.contentStart = ObjectUtils.toString(contentStart); 2109 } 2110 2111 /** 2112 * Sets whether to use full detail when the caller doesn't specify. 2113 * 2114 * @param defaultFullDetail the new defaultFullDetail flag. 2115 */ 2116 protected void setDefaultFullDetail(final boolean defaultFullDetail) { 2117 this.defaultFullDetail = defaultFullDetail; 2118 } 2119 2120 /** 2121 * Sets the field name value separator text. 2122 * 2123 * <p> 2124 * {@code null} is accepted, but will be converted to an empty String. 2125 * </p> 2126 * 2127 * @param fieldNameValueSeparator the new field name value separator text. 2128 */ 2129 protected void setFieldNameValueSeparator(final String fieldNameValueSeparator) { 2130 this.fieldNameValueSeparator = ObjectUtils.toString(fieldNameValueSeparator); 2131 } 2132 2133 /** 2134 * Sets the field separator text. 2135 * 2136 * <p> 2137 * {@code null} is accepted, but will be converted to an empty String. 2138 * </p> 2139 * 2140 * @param fieldSeparator the new field separator text. 2141 */ 2142 protected void setFieldSeparator(final String fieldSeparator) { 2143 this.fieldSeparator = ObjectUtils.toString(fieldSeparator); 2144 } 2145 2146 /** 2147 * Sets whether the field separator should be added at the end of each buffer. 2148 * 2149 * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag. 2150 * @since 2.0 2151 */ 2152 protected void setFieldSeparatorAtEnd(final boolean fieldSeparatorAtEnd) { 2153 this.fieldSeparatorAtEnd = fieldSeparatorAtEnd; 2154 } 2155 2156 /** 2157 * Sets whether the field separator should be added at the start of each buffer. 2158 * 2159 * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag. 2160 * @since 2.0 2161 */ 2162 protected void setFieldSeparatorAtStart(final boolean fieldSeparatorAtStart) { 2163 this.fieldSeparatorAtStart = fieldSeparatorAtStart; 2164 } 2165 2166 /** 2167 * Sets the text to output when {@code null} found. 2168 * 2169 * <p> 2170 * {@code null} is accepted, but will be converted to an empty String. 2171 * </p> 2172 * 2173 * @param nullText the new text to output when null found. 2174 */ 2175 protected void setNullText(final String nullText) { 2176 this.nullText = ObjectUtils.toString(nullText); 2177 } 2178 2179 /** 2180 * Sets the end text to output when a {@link Collection}, {@link Map} or array size is output. 2181 * 2182 * <p> 2183 * This is output after the size value. 2184 * </p> 2185 * 2186 * <p> 2187 * {@code null} is accepted, but will be converted to an empty String. 2188 * </p> 2189 * 2190 * @param sizeEndText the new end of size text. 2191 */ 2192 protected void setSizeEndText(final String sizeEndText) { 2193 this.sizeEndText = ObjectUtils.toString(sizeEndText); 2194 } 2195 2196 /** 2197 * Sets the start text to output when a {@link Collection}, {@link Map} or array size is output. 2198 * 2199 * <p> 2200 * This is output before the size value. 2201 * </p> 2202 * 2203 * <p> 2204 * {@code null} is accepted, but will be converted to an empty String. 2205 * </p> 2206 * 2207 * @param sizeStartText the new start of size text. 2208 */ 2209 protected void setSizeStartText(final String sizeStartText) { 2210 this.sizeStartText = ObjectUtils.toString(sizeStartText); 2211 } 2212 2213 /** 2214 * Sets the end text to output when an {@link Object} is output in summary mode. 2215 * 2216 * <p> 2217 * This is output after the size value. 2218 * </p> 2219 * 2220 * <p> 2221 * {@code null} is accepted, but will be converted to an empty String. 2222 * </p> 2223 * 2224 * @param summaryObjectEndText the new end of summary text. 2225 */ 2226 protected void setSummaryObjectEndText(final String summaryObjectEndText) { 2227 this.summaryObjectEndText = ObjectUtils.toString(summaryObjectEndText); 2228 } 2229 2230 /** 2231 * Sets the start text to output when an {@link Object} is output in summary mode. 2232 * 2233 * <p> 2234 * This is output before the size value. 2235 * </p> 2236 * 2237 * <p> 2238 * {@code null} is accepted, but will be converted to an empty String. 2239 * </p> 2240 * 2241 * @param summaryObjectStartText the new start of summary text. 2242 */ 2243 protected void setSummaryObjectStartText(final String summaryObjectStartText) { 2244 this.summaryObjectStartText = ObjectUtils.toString(summaryObjectStartText); 2245 } 2246 2247 /** 2248 * Sets whether to use the class name. 2249 * 2250 * @param useClassName the new useClassName flag. 2251 */ 2252 protected void setUseClassName(final boolean useClassName) { 2253 this.useClassName = useClassName; 2254 } 2255 2256 /** 2257 * Sets whether to use the field names passed in. 2258 * 2259 * @param useFieldNames the new useFieldNames flag. 2260 */ 2261 protected void setUseFieldNames(final boolean useFieldNames) { 2262 this.useFieldNames = useFieldNames; 2263 } 2264 2265 /** 2266 * Sets whether to use the identity hash code. 2267 * 2268 * @param useIdentityHashCode the new useIdentityHashCode flag. 2269 */ 2270 protected void setUseIdentityHashCode(final boolean useIdentityHashCode) { 2271 this.useIdentityHashCode = useIdentityHashCode; 2272 } 2273 2274 /** 2275 * Sets whether to output short or long class names. 2276 * 2277 * @param useShortClassName the new useShortClassName flag. 2278 * @since 2.0 2279 */ 2280 protected void setUseShortClassName(final boolean useShortClassName) { 2281 this.useShortClassName = useShortClassName; 2282 } 2283}