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 * The default toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 501 * 502 * <pre> 503 * Person@182f0db[name=John Doe,age=33,smoker=false] 504 * </pre> 505 */ 506 public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle(); 507 /** 508 * The multi line toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 509 * 510 * <pre> 511 * Person@182f0db[ 512 * name=John Doe 513 * age=33 514 * smoker=false 515 * ] 516 * </pre> 517 */ 518 public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle(); 519 /** 520 * The no field names toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 521 * 522 * <pre> 523 * Person@182f0db[John Doe,33,false] 524 * </pre> 525 */ 526 public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle(); 527 /** 528 * The short prefix toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 529 * 530 * <pre> 531 * Person[name=John Doe,age=33,smoker=false] 532 * </pre> 533 * 534 * @since 2.1 535 */ 536 public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle(); 537 /** 538 * The simple toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 539 * 540 * <pre> 541 * John Doe,33,false 542 * </pre> 543 */ 544 public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle(); 545 /** 546 * The no class name toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 547 * 548 * <pre> 549 * [name=John Doe,age=33,smoker=false] 550 * </pre> 551 * 552 * @since 3.4 553 */ 554 public static final ToStringStyle NO_CLASS_NAME_STYLE = new NoClassNameToStringStyle(); 555 /** 556 * The JSON toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this: 557 * 558 * <pre> 559 * {"name": "John Doe", "age": 33, "smoker": true} 560 * </pre> 561 * 562 * <strong>Note:</strong> Since field names are mandatory in JSON, this ToStringStyle will throw an {@link UnsupportedOperationException} if no field name 563 * is passed in while appending. Furthermore This ToStringStyle will only generate valid JSON if referenced objects also produce JSON when calling 564 * {@code toString()} on them. 565 * 566 * @since 3.4 567 * @see <a href="https://www.json.org/">json.org</a> 568 */ 569 public static final ToStringStyle JSON_STYLE = new JsonToStringStyle(); 570 /** 571 * A registry of objects used by {@code reflectionToString} methods to detect cyclical object references and avoid infinite loops. 572 */ 573 private static final ThreadLocal<WeakHashMap<Object, Object>> REGISTRY = ThreadLocal.withInitial(WeakHashMap::new); 574 /* 575 * Note that objects of this class are generally shared between threads, so an instance variable would not be suitable here. 576 * 577 * In normal use the registry should always be left empty, because the caller should call toString() which will clean up. 578 * 579 * See LANG-792 580 */ 581 582 /** 583 * Gets the registry of objects being traversed by the {@code reflectionToString} methods in the current thread. 584 * 585 * @return Set the registry of objects being traversed. 586 */ 587 public static Map<Object, Object> getRegistry() { 588 return REGISTRY.get(); 589 } 590 591 /** 592 * Tests whether the registry contains the given object. Used by the reflection methods to avoid infinite loops. 593 * 594 * @param value The object to lookup in the registry. 595 * @return boolean {@code true} if the registry contains the given object. 596 */ 597 static boolean isRegistered(final Object value) { 598 return getRegistry().containsKey(value); 599 } 600 601 /** 602 * Registers the given object. Used by the reflection methods to avoid infinite loops. 603 * 604 * @param value The object to register. 605 */ 606 static void register(final Object value) { 607 if (value != null) { 608 getRegistry().put(value, null); 609 } 610 } 611 612 /** 613 * Unregisters the given object. 614 * 615 * <p> 616 * Used by the reflection methods to avoid infinite loops. 617 * </p> 618 * 619 * @param value The object to unregister. 620 */ 621 static void unregister(final Object value) { 622 if (value != null) { 623 final Map<Object, Object> m = getRegistry(); 624 m.remove(value); 625 if (m.isEmpty()) { 626 REGISTRY.remove(); 627 } 628 } 629 } 630 631 /** 632 * Whether to use the field names, the default is {@code true}. 633 */ 634 private boolean useFieldNames = true; 635 /** 636 * Whether to use the class name, the default is {@code true}. 637 */ 638 private boolean useClassName = true; 639 /** 640 * Whether to use short class names, the default is {@code false}. 641 */ 642 private boolean useShortClassName; 643 /** 644 * Whether to use the identity hash code, the default is {@code true}. 645 */ 646 private boolean useIdentityHashCode = true; 647 /** 648 * The content start {@code '['}. 649 */ 650 private String contentStart = "["; 651 /** 652 * The content end {@code ']'}. 653 */ 654 private String contentEnd = "]"; 655 /** 656 * The field name value separator {@code '='}. 657 */ 658 private String fieldNameValueSeparator = "="; 659 /** 660 * Whether the field separator should be added before any other fields. 661 */ 662 private boolean fieldSeparatorAtStart; 663 /** 664 * Whether the field separator should be added after any other fields. 665 */ 666 private boolean fieldSeparatorAtEnd; 667 /** 668 * The field separator {@code ','}. 669 */ 670 private String fieldSeparator = ","; 671 /** 672 * The array start <code>'{'</code>. 673 */ 674 private String arrayStart = "{"; 675 /** 676 * The array separator {@code ','}. 677 */ 678 private String arraySeparator = ","; 679 /** 680 * The detail for array content. 681 */ 682 private boolean arrayContentDetail = true; 683 /** 684 * The array end {@code '}'}. 685 */ 686 private String arrayEnd = "}"; 687 /** 688 * The value to use when fullDetail is {@code null}, the default value is {@code true}. 689 */ 690 private boolean defaultFullDetail = true; 691 /** 692 * The {@code null} text {@code "<null>"}. 693 */ 694 private String nullText = "<null>"; 695 /** 696 * The summary size text start {@code "<size="}. 697 */ 698 private String sizeStartText = "<size="; 699 /** 700 * The summary size text start {@code ">"}. 701 */ 702 private String sizeEndText = ">"; 703 /** 704 * The summary object text start {@code "<"}. 705 */ 706 private String summaryObjectStartText = "<"; 707 /** 708 * The summary object text start {@code ">"}. 709 */ 710 private String summaryObjectEndText = ">"; 711 712 /** 713 * Constructs a new instance. 714 */ 715 protected ToStringStyle() { 716 } 717 718 /** 719 * Appends to the {@code toString} a {@code boolean} value. 720 * 721 * @param buffer the {@link StringBuffer} to populate. 722 * @param fieldName the field name. 723 * @param value the value to add to the {@code toString}. 724 */ 725 public void append(final StringBuffer buffer, final String fieldName, final boolean value) { 726 appendFieldStart(buffer, fieldName); 727 appendDetail(buffer, fieldName, value); 728 appendFieldEnd(buffer, fieldName); 729 } 730 731 /** 732 * Appends to the {@code toString} a {@code boolean} array. 733 * 734 * @param buffer the {@link StringBuffer} to populate. 735 * @param fieldName the field name. 736 * @param array the array to add to the toString. 737 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 738 */ 739 public void append(final StringBuffer buffer, final String fieldName, final boolean[] array, final Boolean fullDetail) { 740 appendFieldStart(buffer, fieldName); 741 if (array == null) { 742 appendNullText(buffer, fieldName); 743 } else if (isFullDetail(fullDetail)) { 744 appendDetail(buffer, fieldName, array); 745 } else { 746 appendSummary(buffer, fieldName, array); 747 } 748 appendFieldEnd(buffer, fieldName); 749 } 750 751 /** 752 * Appends to the {@code toString} a {@code byte} value. 753 * 754 * @param buffer the {@link StringBuffer} to populate. 755 * @param fieldName the field name. 756 * @param value the value to add to the {@code toString}. 757 */ 758 public void append(final StringBuffer buffer, final String fieldName, final byte value) { 759 appendFieldStart(buffer, fieldName); 760 appendDetail(buffer, fieldName, value); 761 appendFieldEnd(buffer, fieldName); 762 } 763 764 /** 765 * Appends to the {@code toString} a {@code byte} array. 766 * 767 * @param buffer the {@link StringBuffer} to populate. 768 * @param fieldName the field name. 769 * @param array the array to add to the {@code toString}. 770 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 771 */ 772 public void append(final StringBuffer buffer, final String fieldName, final byte[] array, final Boolean fullDetail) { 773 appendFieldStart(buffer, fieldName); 774 if (array == null) { 775 appendNullText(buffer, fieldName); 776 } else if (isFullDetail(fullDetail)) { 777 appendDetail(buffer, fieldName, array); 778 } else { 779 appendSummary(buffer, fieldName, array); 780 } 781 appendFieldEnd(buffer, fieldName); 782 } 783 784 /** 785 * Appends to the {@code toString} a {@code char} value. 786 * 787 * @param buffer the {@link StringBuffer} to populate. 788 * @param fieldName the field name. 789 * @param value the value to add to the {@code toString}. 790 */ 791 public void append(final StringBuffer buffer, final String fieldName, final char value) { 792 appendFieldStart(buffer, fieldName); 793 appendDetail(buffer, fieldName, value); 794 appendFieldEnd(buffer, fieldName); 795 } 796 797 /** 798 * Appends to the {@code toString} a {@code char} array. 799 * 800 * @param buffer the {@link StringBuffer} to populate. 801 * @param fieldName the field name. 802 * @param array the array to add to the {@code toString}. 803 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 804 */ 805 public void append(final StringBuffer buffer, final String fieldName, final char[] array, final Boolean fullDetail) { 806 appendFieldStart(buffer, fieldName); 807 if (array == null) { 808 appendNullText(buffer, fieldName); 809 } else if (isFullDetail(fullDetail)) { 810 appendDetail(buffer, fieldName, array); 811 } else { 812 appendSummary(buffer, fieldName, array); 813 } 814 appendFieldEnd(buffer, fieldName); 815 } 816 817 /** 818 * Appends to the {@code toString} a {@code double} value. 819 * 820 * @param buffer the {@link StringBuffer} to populate. 821 * @param fieldName the field name. 822 * @param value the value to add to the {@code toString}. 823 */ 824 public void append(final StringBuffer buffer, final String fieldName, final double value) { 825 appendFieldStart(buffer, fieldName); 826 appendDetail(buffer, fieldName, value); 827 appendFieldEnd(buffer, fieldName); 828 } 829 830 /** 831 * Appends to the {@code toString} a {@code double} array. 832 * 833 * @param buffer the {@link StringBuffer} to populate. 834 * @param fieldName the field name. 835 * @param array the array to add to the toString. 836 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 837 */ 838 public void append(final StringBuffer buffer, final String fieldName, final double[] array, final Boolean fullDetail) { 839 appendFieldStart(buffer, fieldName); 840 if (array == null) { 841 appendNullText(buffer, fieldName); 842 } else if (isFullDetail(fullDetail)) { 843 appendDetail(buffer, fieldName, array); 844 } else { 845 appendSummary(buffer, fieldName, array); 846 } 847 appendFieldEnd(buffer, fieldName); 848 } 849 850 /** 851 * Appends to the {@code toString} a {@code float} value. 852 * 853 * @param buffer the {@link StringBuffer} to populate. 854 * @param fieldName the field name. 855 * @param value the value to add to the {@code toString}. 856 */ 857 public void append(final StringBuffer buffer, final String fieldName, final float value) { 858 appendFieldStart(buffer, fieldName); 859 appendDetail(buffer, fieldName, value); 860 appendFieldEnd(buffer, fieldName); 861 } 862 863 /** 864 * Appends to the {@code toString} a {@code float} array. 865 * 866 * @param buffer the {@link StringBuffer} to populate. 867 * @param fieldName the field name. 868 * @param array the array to add to the toString. 869 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 870 */ 871 public void append(final StringBuffer buffer, final String fieldName, final float[] array, final Boolean fullDetail) { 872 appendFieldStart(buffer, fieldName); 873 if (array == null) { 874 appendNullText(buffer, fieldName); 875 } else if (isFullDetail(fullDetail)) { 876 appendDetail(buffer, fieldName, array); 877 } else { 878 appendSummary(buffer, fieldName, array); 879 } 880 appendFieldEnd(buffer, fieldName); 881 } 882 883 /** 884 * Appends to the {@code toString} an {@code int} value. 885 * 886 * @param buffer the {@link StringBuffer} to populate. 887 * @param fieldName the field name. 888 * @param value the value to add to the {@code toString}. 889 */ 890 public void append(final StringBuffer buffer, final String fieldName, final int value) { 891 appendFieldStart(buffer, fieldName); 892 appendDetail(buffer, fieldName, value); 893 appendFieldEnd(buffer, fieldName); 894 } 895 896 /** 897 * Appends to the {@code toString} an {@code int} array. 898 * 899 * @param buffer the {@link StringBuffer} to populate. 900 * @param fieldName the field name. 901 * @param array the array to add to the {@code toString}. 902 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 903 */ 904 public void append(final StringBuffer buffer, final String fieldName, final int[] array, final Boolean fullDetail) { 905 appendFieldStart(buffer, fieldName); 906 if (array == null) { 907 appendNullText(buffer, fieldName); 908 } else if (isFullDetail(fullDetail)) { 909 appendDetail(buffer, fieldName, array); 910 } else { 911 appendSummary(buffer, fieldName, array); 912 } 913 appendFieldEnd(buffer, fieldName); 914 } 915 916 /** 917 * Appends to the {@code toString} a {@code long} value. 918 * 919 * @param buffer the {@link StringBuffer} to populate. 920 * @param fieldName the field name. 921 * @param value the value to add to the {@code toString}. 922 */ 923 public void append(final StringBuffer buffer, final String fieldName, final long value) { 924 appendFieldStart(buffer, fieldName); 925 appendDetail(buffer, fieldName, value); 926 appendFieldEnd(buffer, fieldName); 927 } 928 929 /** 930 * Appends to the {@code toString} a {@code long} array. 931 * 932 * @param buffer the {@link StringBuffer} to populate. 933 * @param fieldName the field name. 934 * @param array the array to add to the {@code toString}. 935 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 936 */ 937 public void append(final StringBuffer buffer, final String fieldName, final long[] array, final Boolean fullDetail) { 938 appendFieldStart(buffer, fieldName); 939 if (array == null) { 940 appendNullText(buffer, fieldName); 941 } else if (isFullDetail(fullDetail)) { 942 appendDetail(buffer, fieldName, array); 943 } else { 944 appendSummary(buffer, fieldName, array); 945 } 946 appendFieldEnd(buffer, fieldName); 947 } 948 949 /** 950 * Appends to the {@code toString} an {@link Object} value, printing the full {@code toString} of the {@link Object} passed in. 951 * 952 * @param buffer the {@link StringBuffer} to populate. 953 * @param fieldName the field name. 954 * @param value the value to add to the {@code toString}. 955 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 956 */ 957 public void append(final StringBuffer buffer, final String fieldName, final Object value, final Boolean fullDetail) { 958 appendFieldStart(buffer, fieldName); 959 if (value == null) { 960 appendNullText(buffer, fieldName); 961 } else { 962 appendInternal(buffer, fieldName, value, isFullDetail(fullDetail)); 963 } 964 appendFieldEnd(buffer, fieldName); 965 } 966 967 /** 968 * Appends to the {@code toString} an {@link Object} array. 969 * 970 * @param buffer the {@link StringBuffer} to populate. 971 * @param fieldName the field name. 972 * @param array the array to add to the toString. 973 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 974 */ 975 public void append(final StringBuffer buffer, final String fieldName, final Object[] array, final Boolean fullDetail) { 976 appendFieldStart(buffer, fieldName); 977 if (array == null) { 978 appendNullText(buffer, fieldName); 979 } else if (isFullDetail(fullDetail)) { 980 appendDetail(buffer, fieldName, array); 981 } else { 982 appendSummary(buffer, fieldName, array); 983 } 984 appendFieldEnd(buffer, fieldName); 985 } 986 987 /** 988 * Appends to the {@code toString} a {@code short} value. 989 * 990 * @param buffer the {@link StringBuffer} to populate. 991 * @param fieldName the field name. 992 * @param value the value to add to the {@code toString}. 993 */ 994 public void append(final StringBuffer buffer, final String fieldName, final short value) { 995 appendFieldStart(buffer, fieldName); 996 appendDetail(buffer, fieldName, value); 997 appendFieldEnd(buffer, fieldName); 998 } 999 1000 /** 1001 * Appends to the {@code toString} a {@code short} array. 1002 * 1003 * @param buffer the {@link StringBuffer} to populate. 1004 * @param fieldName the field name. 1005 * @param array the array to add to the {@code toString}. 1006 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides. 1007 */ 1008 public void append(final StringBuffer buffer, final String fieldName, final short[] array, final Boolean fullDetail) { 1009 appendFieldStart(buffer, fieldName); 1010 if (array == null) { 1011 appendNullText(buffer, fieldName); 1012 } else if (isFullDetail(fullDetail)) { 1013 appendDetail(buffer, fieldName, array); 1014 } else { 1015 appendSummary(buffer, fieldName, array); 1016 } 1017 appendFieldEnd(buffer, fieldName); 1018 } 1019 1020 /** 1021 * Appends to the {@code toString} the class name. 1022 * 1023 * @param buffer the {@link StringBuffer} to populate. 1024 * @param object the {@link Object} whose name to output. 1025 */ 1026 protected void appendClassName(final StringBuffer buffer, final Object object) { 1027 if (isUseClassName() && object != null) { 1028 register(object); 1029 if (isUseShortClassName()) { 1030 buffer.append(getShortClassName(object.getClass())); 1031 } else { 1032 buffer.append(object.getClass().getName()); 1033 } 1034 } 1035 } 1036 1037 /** 1038 * Appends to the {@code toString} the content end. 1039 * 1040 * @param buffer the {@link StringBuffer} to populate. 1041 */ 1042 protected void appendContentEnd(final StringBuffer buffer) { 1043 buffer.append(getContentEnd()); 1044 } 1045 1046 /** 1047 * Appends to the {@code toString} the content start. 1048 * 1049 * @param buffer the {@link StringBuffer} to populate. 1050 */ 1051 protected void appendContentStart(final StringBuffer buffer) { 1052 buffer.append(getContentStart()); 1053 } 1054 1055 /** 1056 * Appends to the {@code toString} an {@link Object} value that has been detected to participate in a cycle. This implementation will print the standard 1057 * string value of the value. 1058 * 1059 * @param buffer the {@link StringBuffer} to populate. 1060 * @param fieldName the field name, typically not used as already appended 1061 * @param value the value to add to the {@code toString}, not {@code null}. 1062 * @since 2.2 1063 */ 1064 protected void appendCyclicObject(final StringBuffer buffer, final String fieldName, final Object value) { 1065 ObjectUtils.identityToString(buffer, value); 1066 } 1067 1068 /** 1069 * Appends to the {@code toString} a {@code boolean} value. 1070 * 1071 * @param buffer the {@link StringBuffer} to populate. 1072 * @param fieldName the field name, typically not used as already appended. 1073 * @param value the value to add to the {@code toString}. 1074 */ 1075 protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean value) { 1076 buffer.append(value); 1077 } 1078 1079 /** 1080 * Appends to the {@code toString} the detail of a {@code boolean} array. 1081 * 1082 * @param buffer the {@link StringBuffer} to populate. 1083 * @param fieldName the field name, typically not used as already appended. 1084 * @param array the array to add to the {@code toString}, not {@code null}. 1085 */ 1086 protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) { 1087 buffer.append(getArrayStart()); 1088 for (int i = 0; i < array.length; i++) { 1089 if (i > 0) { 1090 buffer.append(getArraySeparator()); 1091 } 1092 appendDetail(buffer, fieldName, array[i]); 1093 } 1094 buffer.append(getArrayEnd()); 1095 } 1096 1097 /** 1098 * Appends to the {@code toString} a {@code byte} value. 1099 * 1100 * @param buffer the {@link StringBuffer} to populate. 1101 * @param fieldName the field name, typically not used as already appended. 1102 * @param value the value to add to the {@code toString}. 1103 */ 1104 protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte value) { 1105 buffer.append(value); 1106 } 1107 1108 /** 1109 * Appends to the {@code toString} the detail of a {@code byte} array. 1110 * 1111 * @param buffer the {@link StringBuffer} to populate. 1112 * @param fieldName the field name, typically not used as already appended. 1113 * @param array the array to add to the {@code toString}, not {@code null}. 1114 */ 1115 protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) { 1116 buffer.append(getArrayStart()); 1117 for (int i = 0; i < array.length; i++) { 1118 if (i > 0) { 1119 buffer.append(getArraySeparator()); 1120 } 1121 appendDetail(buffer, fieldName, array[i]); 1122 } 1123 buffer.append(getArrayEnd()); 1124 } 1125 1126 /** 1127 * Appends to the {@code toString} a {@code char} value. 1128 * 1129 * @param buffer the {@link StringBuffer} to populate. 1130 * @param fieldName the field name, typically not used as already appended. 1131 * @param value the value to add to the {@code toString}. 1132 */ 1133 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char value) { 1134 buffer.append(value); 1135 } 1136 1137 /** 1138 * Appends to the {@code toString} the detail of a {@code char} array. 1139 * 1140 * @param buffer the {@link StringBuffer} to populate. 1141 * @param fieldName the field name, typically not used as already appended. 1142 * @param array the array to add to the {@code toString}, not {@code null}. 1143 */ 1144 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) { 1145 buffer.append(getArrayStart()); 1146 for (int i = 0; i < array.length; i++) { 1147 if (i > 0) { 1148 buffer.append(getArraySeparator()); 1149 } 1150 appendDetail(buffer, fieldName, array[i]); 1151 } 1152 buffer.append(getArrayEnd()); 1153 } 1154 1155 /** 1156 * Appends to the {@code toString} a {@link Collection}. 1157 * 1158 * @param buffer the {@link StringBuffer} to populate. 1159 * @param fieldName the field name, typically not used as already appended. 1160 * @param coll the {@link Collection} to add to the {@code toString}, not {@code null}. 1161 */ 1162 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection<?> coll) { 1163 buffer.append(coll); 1164 } 1165 1166 /** 1167 * Appends to the {@code toString} a {@code double} value. 1168 * 1169 * @param buffer the {@link StringBuffer} to populate. 1170 * @param fieldName the field name, typically not used as already appended. 1171 * @param value the value to add to the {@code toString}. 1172 */ 1173 protected void appendDetail(final StringBuffer buffer, final String fieldName, final double value) { 1174 buffer.append(value); 1175 } 1176 1177 /** 1178 * Appends to the {@code toString} the detail of a {@code double} array. 1179 * 1180 * @param buffer the {@link StringBuffer} to populate. 1181 * @param fieldName the field name, typically not used as already appended 1182 * @param array the array to add to the {@code toString}, not {@code null}. 1183 */ 1184 protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) { 1185 buffer.append(getArrayStart()); 1186 for (int i = 0; i < array.length; i++) { 1187 if (i > 0) { 1188 buffer.append(getArraySeparator()); 1189 } 1190 appendDetail(buffer, fieldName, array[i]); 1191 } 1192 buffer.append(getArrayEnd()); 1193 } 1194 1195 /** 1196 * Appends to the {@code toString} a {@code float} value. 1197 * 1198 * @param buffer the {@link StringBuffer} to populate. 1199 * @param fieldName the field name, typically not used as already appended. 1200 * @param value the value to add to the {@code toString}. 1201 */ 1202 protected void appendDetail(final StringBuffer buffer, final String fieldName, final float value) { 1203 buffer.append(value); 1204 } 1205 1206 /** 1207 * Appends to the {@code toString} the detail of a {@code float} array. 1208 * 1209 * @param buffer the {@link StringBuffer} to populate. 1210 * @param fieldName the field name, typically not used as already appended. 1211 * @param array the array to add to the {@code toString}, not {@code null}. 1212 */ 1213 protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) { 1214 buffer.append(getArrayStart()); 1215 for (int i = 0; i < array.length; i++) { 1216 if (i > 0) { 1217 buffer.append(getArraySeparator()); 1218 } 1219 appendDetail(buffer, fieldName, array[i]); 1220 } 1221 buffer.append(getArrayEnd()); 1222 } 1223 1224 /** 1225 * Appends to the {@code toString} an {@code int} value. 1226 * 1227 * @param buffer the {@link StringBuffer} to populate. 1228 * @param fieldName the field name, typically not used as already appended. 1229 * @param value the value to add to the {@code toString}. 1230 */ 1231 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int value) { 1232 buffer.append(value); 1233 } 1234 1235 /** 1236 * Appends to the {@code toString} the detail of an {@link Object} array item. 1237 * 1238 * @param buffer the {@link StringBuffer} to populate. 1239 * @param fieldName the field name, typically not used as already appended. 1240 * @param i the array item index to add. 1241 * @param item the array item to add. 1242 * @since 3.11 1243 */ 1244 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int i, final Object item) { 1245 if (i > 0) { 1246 buffer.append(getArraySeparator()); 1247 } 1248 if (item == null) { 1249 appendNullText(buffer, fieldName); 1250 } else { 1251 appendInternal(buffer, fieldName, item, isArrayContentDetail()); 1252 } 1253 } 1254 1255 /** 1256 * Appends to the {@code toString} the detail of an {@code int} array. 1257 * 1258 * @param buffer the {@link StringBuffer} to populate. 1259 * @param fieldName the field name, typically not used as already appended. 1260 * @param array the array to add to the {@code toString}, not {@code null}. 1261 */ 1262 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) { 1263 buffer.append(getArrayStart()); 1264 for (int i = 0; i < array.length; i++) { 1265 if (i > 0) { 1266 buffer.append(getArraySeparator()); 1267 } 1268 appendDetail(buffer, fieldName, array[i]); 1269 } 1270 buffer.append(getArrayEnd()); 1271 } 1272 1273 /** 1274 * Appends to the {@code toString} a {@code long} value. 1275 * 1276 * @param buffer the {@link StringBuffer} to populate. 1277 * @param fieldName the field name, typically not used as already appended. 1278 * @param value the value to add to the {@code toString}. 1279 */ 1280 protected void appendDetail(final StringBuffer buffer, final String fieldName, final long value) { 1281 buffer.append(value); 1282 } 1283 1284 /** 1285 * Appends to the {@code toString} the detail of a {@code long} array. 1286 * 1287 * @param buffer the {@link StringBuffer} to populate. 1288 * @param fieldName the field name, typically not used as already appended. 1289 * @param array the array to add to the {@code toString}, not {@code null}. 1290 */ 1291 protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) { 1292 buffer.append(getArrayStart()); 1293 for (int i = 0; i < array.length; i++) { 1294 if (i > 0) { 1295 buffer.append(getArraySeparator()); 1296 } 1297 appendDetail(buffer, fieldName, array[i]); 1298 } 1299 buffer.append(getArrayEnd()); 1300 } 1301 1302 /** 1303 * Appends to the {@code toString} a {@link Map}. 1304 * 1305 * @param buffer the {@link StringBuffer} to populate. 1306 * @param fieldName the field name, typically not used as already appended. 1307 * @param map the {@link Map} to add to the {@code toString}, not {@code null}. 1308 */ 1309 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Map<?, ?> map) { 1310 buffer.append(map); 1311 } 1312 1313 /** 1314 * Appends to the {@code toString} an {@link Object} value, printing the full detail of the {@link Object}. 1315 * 1316 * @param buffer the {@link StringBuffer} to populate. 1317 * @param fieldName the field name, typically not used as already appended. 1318 * @param value the value to add to the {@code toString}, not {@code null}. 1319 */ 1320 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { 1321 buffer.append(value); 1322 } 1323 1324 /** 1325 * Appends to the {@code toString} the detail of an {@link Object} array. 1326 * 1327 * @param buffer the {@link StringBuffer} to populate. 1328 * @param fieldName the field name, typically not used as already appended. 1329 * @param array the array to add to the {@code toString}, not {@code null}. 1330 */ 1331 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) { 1332 buffer.append(getArrayStart()); 1333 for (int i = 0; i < array.length; i++) { 1334 appendDetail(buffer, fieldName, i, array[i]); 1335 } 1336 buffer.append(getArrayEnd()); 1337 } 1338 1339 /** 1340 * Appends to the {@code toString} a {@code short} value. 1341 * 1342 * @param buffer the {@link StringBuffer} to populate. 1343 * @param fieldName the field name, typically not used as already appended. 1344 * @param value the value to add to the {@code toString}. 1345 */ 1346 protected void appendDetail(final StringBuffer buffer, final String fieldName, final short value) { 1347 buffer.append(value); 1348 } 1349 1350 /** 1351 * Appends to the {@code toString} the detail of a {@code short} array. 1352 * 1353 * @param buffer the {@link StringBuffer} to populate. 1354 * @param fieldName the field name, typically not used as already appended. 1355 * @param array the array to add to the {@code toString}, not {@code null}. 1356 */ 1357 protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) { 1358 buffer.append(getArrayStart()); 1359 for (int i = 0; i < array.length; i++) { 1360 if (i > 0) { 1361 buffer.append(getArraySeparator()); 1362 } 1363 appendDetail(buffer, fieldName, array[i]); 1364 } 1365 buffer.append(getArrayEnd()); 1366 } 1367 1368 /** 1369 * Appends to the {@code toString} the end of data indicator. 1370 * 1371 * @param buffer the {@link StringBuffer} to populate. 1372 * @param object the {@link Object} to build a {@code toString} for. 1373 */ 1374 public void appendEnd(final StringBuffer buffer, final Object object) { 1375 if (!isFieldSeparatorAtEnd()) { 1376 removeLastFieldSeparator(buffer); 1377 } 1378 appendContentEnd(buffer); 1379 unregister(object); 1380 } 1381 1382 /** 1383 * Appends to the {@code toString} the field end. 1384 * 1385 * @param buffer the {@link StringBuffer} to populate. 1386 * @param fieldName the field name, typically not used as already appended. 1387 */ 1388 protected void appendFieldEnd(final StringBuffer buffer, final String fieldName) { 1389 appendFieldSeparator(buffer); 1390 } 1391 1392 /** 1393 * Appends to the {@code toString} the field separator. 1394 * 1395 * @param buffer the {@link StringBuffer} to populate. 1396 */ 1397 protected void appendFieldSeparator(final StringBuffer buffer) { 1398 buffer.append(getFieldSeparator()); 1399 } 1400 1401 /** 1402 * Appends to the {@code toString} the field start. 1403 * 1404 * @param buffer the {@link StringBuffer} to populate. 1405 * @param fieldName the field name. 1406 */ 1407 protected void appendFieldStart(final StringBuffer buffer, final String fieldName) { 1408 if (isUseFieldNames() && fieldName != null) { 1409 buffer.append(fieldName); 1410 buffer.append(getFieldNameValueSeparator()); 1411 } 1412 } 1413 1414 /** 1415 * Appends the {@link System#identityHashCode(java.lang.Object)}. 1416 * 1417 * @param buffer the {@link StringBuffer} to populate. 1418 * @param object the {@link Object} whose id to output. 1419 */ 1420 protected void appendIdentityHashCode(final StringBuffer buffer, final Object object) { 1421 if (isUseIdentityHashCode() && object != null) { 1422 register(object); 1423 buffer.append('@'); 1424 buffer.append(ObjectUtils.identityHashCodeHex(object)); 1425 } 1426 } 1427 1428 /** 1429 * Appends to the {@code toString} an {@link Object}, correctly interpreting its type. 1430 * 1431 * <p> 1432 * 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 1433 * method. 1434 * </p> 1435 * 1436 * <p> 1437 * Either detail or summary views can be specified. 1438 * </p> 1439 * 1440 * <p> 1441 * If a cycle is detected, an object will be appended with the {@code Object.toString()} format. 1442 * </p> 1443 * 1444 * @param buffer the {@link StringBuffer} to populate. 1445 * @param fieldName the field name, typically not used as already appended. 1446 * @param value the value to add to the {@code toString}, not {@code null}. 1447 * @param detail output detail or not. 1448 */ 1449 protected void appendInternal(final StringBuffer buffer, final String fieldName, final Object value, final boolean detail) { 1450 if (isRegistered(value) && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) { 1451 appendCyclicObject(buffer, fieldName, value); 1452 return; 1453 } 1454 register(value); 1455 try { 1456 if (value instanceof Collection<?>) { 1457 if (detail) { 1458 appendDetail(buffer, fieldName, (Collection<?>) value); 1459 } else { 1460 appendSummarySize(buffer, fieldName, ((Collection<?>) value).size()); 1461 } 1462 } else if (value instanceof Map<?, ?>) { 1463 if (detail) { 1464 appendDetail(buffer, fieldName, (Map<?, ?>) value); 1465 } else { 1466 appendSummarySize(buffer, fieldName, ((Map<?, ?>) value).size()); 1467 } 1468 } else if (value instanceof long[]) { 1469 if (detail) { 1470 appendDetail(buffer, fieldName, (long[]) value); 1471 } else { 1472 appendSummary(buffer, fieldName, (long[]) value); 1473 } 1474 } else if (value instanceof int[]) { 1475 if (detail) { 1476 appendDetail(buffer, fieldName, (int[]) value); 1477 } else { 1478 appendSummary(buffer, fieldName, (int[]) value); 1479 } 1480 } else if (value instanceof short[]) { 1481 if (detail) { 1482 appendDetail(buffer, fieldName, (short[]) value); 1483 } else { 1484 appendSummary(buffer, fieldName, (short[]) value); 1485 } 1486 } else if (value instanceof byte[]) { 1487 if (detail) { 1488 appendDetail(buffer, fieldName, (byte[]) value); 1489 } else { 1490 appendSummary(buffer, fieldName, (byte[]) value); 1491 } 1492 } else if (value instanceof char[]) { 1493 if (detail) { 1494 appendDetail(buffer, fieldName, (char[]) value); 1495 } else { 1496 appendSummary(buffer, fieldName, (char[]) value); 1497 } 1498 } else if (value instanceof double[]) { 1499 if (detail) { 1500 appendDetail(buffer, fieldName, (double[]) value); 1501 } else { 1502 appendSummary(buffer, fieldName, (double[]) value); 1503 } 1504 } else if (value instanceof float[]) { 1505 if (detail) { 1506 appendDetail(buffer, fieldName, (float[]) value); 1507 } else { 1508 appendSummary(buffer, fieldName, (float[]) value); 1509 } 1510 } else if (value instanceof boolean[]) { 1511 if (detail) { 1512 appendDetail(buffer, fieldName, (boolean[]) value); 1513 } else { 1514 appendSummary(buffer, fieldName, (boolean[]) value); 1515 } 1516 } else if (ObjectUtils.isArray(value)) { 1517 if (detail) { 1518 appendDetail(buffer, fieldName, (Object[]) value); 1519 } else { 1520 appendSummary(buffer, fieldName, (Object[]) value); 1521 } 1522 } else if (detail) { 1523 appendDetail(buffer, fieldName, value); 1524 } else { 1525 appendSummary(buffer, fieldName, value); 1526 } 1527 } finally { 1528 unregister(value); 1529 } 1530 } 1531 1532 /** 1533 * Appends to the {@code toString} an indicator for {@code null}. 1534 * 1535 * <p> 1536 * The default indicator is {@code "<null>"}. 1537 * </p> 1538 * 1539 * @param buffer the {@link StringBuffer} to populate. 1540 * @param fieldName the field name, typically not used as already appended. 1541 */ 1542 protected void appendNullText(final StringBuffer buffer, final String fieldName) { 1543 buffer.append(getNullText()); 1544 } 1545 1546 /** 1547 * Appends to the {@code toString} the start of data indicator. 1548 * 1549 * @param buffer the {@link StringBuffer} to populate. 1550 * @param object the {@link Object} to build a {@code toString} for. 1551 */ 1552 public void appendStart(final StringBuffer buffer, final Object object) { 1553 if (object != null) { 1554 appendClassName(buffer, object); 1555 appendIdentityHashCode(buffer, object); 1556 appendContentStart(buffer); 1557 if (isFieldSeparatorAtStart()) { 1558 appendFieldSeparator(buffer); 1559 } 1560 } 1561 } 1562 1563 /** 1564 * Appends to the {@code toString} a summary of a {@code boolean} array. 1565 * 1566 * @param buffer the {@link StringBuffer} to populate. 1567 * @param fieldName the field name, typically not used as already appended. 1568 * @param array the array to add to the {@code toString}, not {@code null}. 1569 */ 1570 protected void appendSummary(final StringBuffer buffer, final String fieldName, final boolean[] array) { 1571 appendSummarySize(buffer, fieldName, array.length); 1572 } 1573 1574 /** 1575 * Appends to the {@code toString} a summary of a {@code byte} array. 1576 * 1577 * @param buffer the {@link StringBuffer} to populate. 1578 * @param fieldName the field name, typically not used as already appended. 1579 * @param array the array to add to the {@code toString}, not {@code null}. 1580 */ 1581 protected void appendSummary(final StringBuffer buffer, final String fieldName, final byte[] array) { 1582 appendSummarySize(buffer, fieldName, array.length); 1583 } 1584 1585 /** 1586 * Appends to the {@code toString} a summary of a {@code char} array. 1587 * 1588 * @param buffer the {@link StringBuffer} to populate. 1589 * @param fieldName the field name, typically not used as already appended. 1590 * @param array the array to add to the {@code toString}, not {@code null}. 1591 */ 1592 protected void appendSummary(final StringBuffer buffer, final String fieldName, final char[] array) { 1593 appendSummarySize(buffer, fieldName, array.length); 1594 } 1595 1596 /** 1597 * Appends to the {@code toString} a summary of a {@code double} array. 1598 * 1599 * @param buffer the {@link StringBuffer} to populate 1600 * @param fieldName the field name, typically not used as already appended 1601 * @param array the array to add to the {@code toString}, not {@code null} 1602 */ 1603 protected void appendSummary(final StringBuffer buffer, final String fieldName, final double[] array) { 1604 appendSummarySize(buffer, fieldName, array.length); 1605 } 1606 1607 /** 1608 * Appends to the {@code toString} a summary of a {@code float} array. 1609 * 1610 * @param buffer the {@link StringBuffer} to populate. 1611 * @param fieldName the field name, typically not used as already appended. 1612 * @param array the array to add to the {@code toString}, not {@code null}. 1613 */ 1614 protected void appendSummary(final StringBuffer buffer, final String fieldName, final float[] array) { 1615 appendSummarySize(buffer, fieldName, array.length); 1616 } 1617 1618 /** 1619 * Appends to the {@code toString} a summary of an {@code int} array. 1620 * 1621 * @param buffer the {@link StringBuffer} to populate. 1622 * @param fieldName the field name, typically not used as already appended. 1623 * @param array the array to add to the {@code toString}, not {@code null}. 1624 */ 1625 protected void appendSummary(final StringBuffer buffer, final String fieldName, final int[] array) { 1626 appendSummarySize(buffer, fieldName, array.length); 1627 } 1628 1629 /** 1630 * Appends to the {@code toString} a summary of a {@code long} array. 1631 * 1632 * @param buffer the {@link StringBuffer} to populate. 1633 * @param fieldName the field name, typically not used as already appended. 1634 * @param array the array to add to the {@code toString}, not {@code null}. 1635 */ 1636 protected void appendSummary(final StringBuffer buffer, final String fieldName, final long[] array) { 1637 appendSummarySize(buffer, fieldName, array.length); 1638 } 1639 1640 /** 1641 * Appends to the {@code toString} an {@link Object} value, printing a summary of the {@link Object}. 1642 * 1643 * @param buffer the {@link StringBuffer} to populate. 1644 * @param fieldName the field name, typically not used as already appended. 1645 * @param value the value to add to the {@code toString}, not {@code null}. 1646 */ 1647 protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object value) { 1648 buffer.append(getSummaryObjectStartText()); 1649 buffer.append(getShortClassName(value.getClass())); 1650 buffer.append(getSummaryObjectEndText()); 1651 } 1652 1653 /** 1654 * Appends to the {@code toString} a summary of an {@link Object} array. 1655 * 1656 * @param buffer the {@link StringBuffer} to populate. 1657 * @param fieldName the field name, typically not used as already appended. 1658 * @param array the array to add to the {@code toString}, not {@code null}. 1659 */ 1660 protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object[] array) { 1661 appendSummarySize(buffer, fieldName, array.length); 1662 } 1663 1664 /** 1665 * Appends to the {@code toString} a summary of a {@code short} array. 1666 * 1667 * @param buffer the {@link StringBuffer} to populate. 1668 * @param fieldName the field name, typically not used as already appended. 1669 * @param array the array to add to the {@code toString}, not {@code null}. 1670 */ 1671 protected void appendSummary(final StringBuffer buffer, final String fieldName, final short[] array) { 1672 appendSummarySize(buffer, fieldName, array.length); 1673 } 1674 1675 /** 1676 * Appends to the {@code toString} a size summary. 1677 * 1678 * <p> 1679 * The size summary is used to summarize the contents of {@link Collection}s, {@link Map}s and arrays. 1680 * </p> 1681 * 1682 * <p> 1683 * The output consists of a prefix, the passed in size and a suffix. 1684 * </p> 1685 * 1686 * <p> 1687 * The default format is {@code "<size=n>"}. 1688 * </p> 1689 * 1690 * @param buffer the {@link StringBuffer} to populate. 1691 * @param fieldName the field name, typically not used as already appended. 1692 * @param size the size to append. 1693 */ 1694 protected void appendSummarySize(final StringBuffer buffer, final String fieldName, final int size) { 1695 buffer.append(getSizeStartText()); 1696 buffer.append(size); 1697 buffer.append(getSizeEndText()); 1698 } 1699 1700 /** 1701 * Appends to the {@code toString} the superclass toString. 1702 * <p> 1703 * NOTE: It assumes that the toString has been created from the same ToStringStyle. 1704 * </p> 1705 * 1706 * <p> 1707 * A {@code null} {@code superToString} is ignored. 1708 * </p> 1709 * 1710 * @param buffer the {@link StringBuffer} to populate. 1711 * @param superToString the {@code super.toString()}. 1712 * @since 2.0 1713 */ 1714 public void appendSuper(final StringBuffer buffer, final String superToString) { 1715 appendToString(buffer, superToString); 1716 } 1717 1718 /** 1719 * Appends to the {@code toString} another toString. 1720 * <p> 1721 * NOTE: It assumes that the toString has been created from the same ToStringStyle. 1722 * </p> 1723 * 1724 * <p> 1725 * A {@code null} {@code toString} is ignored. 1726 * </p> 1727 * 1728 * @param buffer the {@link StringBuffer} to populate. 1729 * @param toString the additional {@code toString}. 1730 * @since 2.0 1731 */ 1732 public void appendToString(final StringBuffer buffer, final String toString) { 1733 if (toString != null) { 1734 final int pos1 = toString.indexOf(getContentStart()) + getContentStart().length(); 1735 final int pos2 = toString.lastIndexOf(getContentEnd()); 1736 if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) { 1737 if (isFieldSeparatorAtStart()) { 1738 removeLastFieldSeparator(buffer); 1739 } 1740 buffer.append(toString, pos1, pos2); 1741 appendFieldSeparator(buffer); 1742 } 1743 } 1744 } 1745 1746 /** 1747 * Gets the array end text. 1748 * 1749 * @return the current array end text. 1750 */ 1751 protected String getArrayEnd() { 1752 return arrayEnd; 1753 } 1754 1755 /** 1756 * Gets the array separator text. 1757 * 1758 * @return the current array separator text. 1759 */ 1760 protected String getArraySeparator() { 1761 return arraySeparator; 1762 } 1763 1764 /** 1765 * Gets the array start text. 1766 * 1767 * @return the current array start text. 1768 */ 1769 protected String getArrayStart() { 1770 return arrayStart; 1771 } 1772 1773 /** 1774 * Gets the content end text. 1775 * 1776 * @return the current content end text. 1777 */ 1778 protected String getContentEnd() { 1779 return contentEnd; 1780 } 1781 1782 /** 1783 * Gets the content start text. 1784 * 1785 * @return the current content start text. 1786 */ 1787 protected String getContentStart() { 1788 return contentStart; 1789 } 1790 1791 /** 1792 * Gets the field name value separator text. 1793 * 1794 * @return the current field name value separator text. 1795 */ 1796 protected String getFieldNameValueSeparator() { 1797 return fieldNameValueSeparator; 1798 } 1799 1800 /** 1801 * Gets the field separator text. 1802 * 1803 * @return the current field separator text. 1804 */ 1805 protected String getFieldSeparator() { 1806 return fieldSeparator; 1807 } 1808 1809 /** 1810 * Gets the text to output when {@code null} found. 1811 * 1812 * @return the current text to output when null found. 1813 */ 1814 protected String getNullText() { 1815 return nullText; 1816 } 1817 1818 /** 1819 * Gets the short class name for a class. 1820 * 1821 * <p> 1822 * The short class name is the class name excluding the package name. 1823 * </p> 1824 * 1825 * @param cls the {@link Class} to get the short name of. 1826 * @return the short name. 1827 */ 1828 protected String getShortClassName(final Class<?> cls) { 1829 return ClassUtils.getShortClassName(cls); 1830 } 1831 1832 /** 1833 * Gets the end text to output when a {@link Collection}, {@link Map} or array size is output. 1834 * 1835 * <p> 1836 * This is output after the size value. 1837 * </p> 1838 * 1839 * @return the current end of size text. 1840 */ 1841 protected String getSizeEndText() { 1842 return sizeEndText; 1843 } 1844 1845 /** 1846 * Gets the start text to output when a {@link Collection}, {@link Map} or array size is output. 1847 * 1848 * <p> 1849 * This is output before the size value. 1850 * </p> 1851 * 1852 * @return the current start of size text. 1853 */ 1854 protected String getSizeStartText() { 1855 return sizeStartText; 1856 } 1857 1858 /** 1859 * Gets the end text to output when an {@link Object} is output in summary mode. 1860 * 1861 * <p> 1862 * This is output after the size value. 1863 * </p> 1864 * 1865 * @return the current end of summary text. 1866 */ 1867 protected String getSummaryObjectEndText() { 1868 return summaryObjectEndText; 1869 } 1870 1871 /** 1872 * Gets the start text to output when an {@link Object} is output in summary mode. 1873 * 1874 * <p> 1875 * This is output before the size value. 1876 * </p> 1877 * 1878 * @return the current start of summary text. 1879 */ 1880 protected String getSummaryObjectStartText() { 1881 return summaryObjectStartText; 1882 } 1883 1884 /** 1885 * Gets whether to output array content detail. 1886 * 1887 * @return the current array content detail setting. 1888 */ 1889 protected boolean isArrayContentDetail() { 1890 return arrayContentDetail; 1891 } 1892 1893 /** 1894 * Gets whether to use full detail when the caller doesn't specify. 1895 * 1896 * @return the current defaultFullDetail flag. 1897 */ 1898 protected boolean isDefaultFullDetail() { 1899 return defaultFullDetail; 1900 } 1901 1902 /** 1903 * Gets whether the field separator should be added at the end of each buffer. 1904 * 1905 * @return fieldSeparatorAtEnd flag. 1906 * @since 2.0 1907 */ 1908 protected boolean isFieldSeparatorAtEnd() { 1909 return fieldSeparatorAtEnd; 1910 } 1911 1912 /** 1913 * Gets whether the field separator should be added at the start of each buffer. 1914 * 1915 * @return the fieldSeparatorAtStart flag. 1916 * @since 2.0 1917 */ 1918 protected boolean isFieldSeparatorAtStart() { 1919 return fieldSeparatorAtStart; 1920 } 1921 1922 /** 1923 * Is this field to be output in full detail. 1924 * 1925 * <p> 1926 * 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 1927 * 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 1928 * detail level is used. 1929 * </p> 1930 * 1931 * @param fullDetailRequest the detail level requested. 1932 * @return whether full detail is to be shown. 1933 */ 1934 protected boolean isFullDetail(final Boolean fullDetailRequest) { 1935 if (fullDetailRequest == null) { 1936 return isDefaultFullDetail(); 1937 } 1938 return fullDetailRequest.booleanValue(); 1939 } 1940 1941 // Setters and getters for the customizable parts of the style 1942 // These methods are not expected to be overridden, except to make public 1943 // (They are not public so that immutable subclasses can be written) 1944 /** 1945 * Gets whether to use the class name. 1946 * 1947 * @return the current useClassName flag. 1948 */ 1949 protected boolean isUseClassName() { 1950 return useClassName; 1951 } 1952 1953 /** 1954 * Gets whether to use the field names passed in. 1955 * 1956 * @return the current useFieldNames flag. 1957 */ 1958 protected boolean isUseFieldNames() { 1959 return useFieldNames; 1960 } 1961 1962 /** 1963 * Gets whether to use the identity hash code. 1964 * 1965 * @return the current useIdentityHashCode flag. 1966 */ 1967 protected boolean isUseIdentityHashCode() { 1968 return useIdentityHashCode; 1969 } 1970 1971 /** 1972 * Gets whether to output short or long class names. 1973 * 1974 * @return the current useShortClassName flag. 1975 * @since 2.0 1976 */ 1977 protected boolean isUseShortClassName() { 1978 return useShortClassName; 1979 } 1980 1981 /** 1982 * Appends to the {@code toString} the detail of an array type. 1983 * 1984 * @param buffer the {@link StringBuffer} to populate. 1985 * @param fieldName the field name, typically not used as already appended. 1986 * @param array the array to add to the {@code toString}, not {@code null}. 1987 * @since 2.0 1988 */ 1989 protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) { 1990 buffer.append(getArrayStart()); 1991 final int length = Array.getLength(array); 1992 for (int i = 0; i < length; i++) { 1993 appendDetail(buffer, fieldName, i, Array.get(array, i)); 1994 } 1995 buffer.append(getArrayEnd()); 1996 } 1997 1998 /** 1999 * Remove the last field separator from the buffer. 2000 * 2001 * @param buffer the {@link StringBuffer} to populate. 2002 * @since 2.0 2003 */ 2004 protected void removeLastFieldSeparator(final StringBuffer buffer) { 2005 if (Strings.CS.endsWith(buffer, getFieldSeparator())) { 2006 buffer.setLength(buffer.length() - getFieldSeparator().length()); 2007 } 2008 } 2009 2010 /** 2011 * Sets whether to output array content detail. 2012 * 2013 * @param arrayContentDetail the new arrayContentDetail flag. 2014 */ 2015 protected void setArrayContentDetail(final boolean arrayContentDetail) { 2016 this.arrayContentDetail = arrayContentDetail; 2017 } 2018 2019 /** 2020 * Sets the array end text. 2021 * 2022 * <p> 2023 * {@code null} is accepted, but will be converted to an empty String. 2024 * </p> 2025 * 2026 * @param arrayEnd the new array end text. 2027 */ 2028 protected void setArrayEnd(final String arrayEnd) { 2029 this.arrayEnd = ObjectUtils.toString(arrayEnd); 2030 } 2031 2032 /** 2033 * Sets the array separator text. 2034 * 2035 * <p> 2036 * {@code null} is accepted, but will be converted to an empty String. 2037 * </p> 2038 * 2039 * @param arraySeparator the new array separator text. 2040 */ 2041 protected void setArraySeparator(final String arraySeparator) { 2042 this.arraySeparator = ObjectUtils.toString(arraySeparator); 2043 } 2044 2045 /** 2046 * Sets the array start text. 2047 * 2048 * <p> 2049 * {@code null} is accepted, but will be converted to an empty String. 2050 * </p> 2051 * 2052 * @param arrayStart the new array start text. 2053 */ 2054 protected void setArrayStart(final String arrayStart) { 2055 this.arrayStart = ObjectUtils.toString(arrayStart); 2056 } 2057 2058 /** 2059 * Sets the content end text. 2060 * 2061 * <p> 2062 * {@code null} is accepted, but will be converted to an empty String. 2063 * </p> 2064 * 2065 * @param contentEnd the new content end text. 2066 */ 2067 protected void setContentEnd(final String contentEnd) { 2068 this.contentEnd = ObjectUtils.toString(contentEnd); 2069 } 2070 2071 /** 2072 * Sets the content start text. 2073 * 2074 * <p> 2075 * {@code null} is accepted, but will be converted to an empty String. 2076 * </p> 2077 * 2078 * @param contentStart the new content start text. 2079 */ 2080 protected void setContentStart(final String contentStart) { 2081 this.contentStart = ObjectUtils.toString(contentStart); 2082 } 2083 2084 /** 2085 * Sets whether to use full detail when the caller doesn't specify. 2086 * 2087 * @param defaultFullDetail the new defaultFullDetail flag. 2088 */ 2089 protected void setDefaultFullDetail(final boolean defaultFullDetail) { 2090 this.defaultFullDetail = defaultFullDetail; 2091 } 2092 2093 /** 2094 * Sets the field name value separator text. 2095 * 2096 * <p> 2097 * {@code null} is accepted, but will be converted to an empty String. 2098 * </p> 2099 * 2100 * @param fieldNameValueSeparator the new field name value separator text. 2101 */ 2102 protected void setFieldNameValueSeparator(final String fieldNameValueSeparator) { 2103 this.fieldNameValueSeparator = ObjectUtils.toString(fieldNameValueSeparator); 2104 } 2105 2106 /** 2107 * Sets the field separator text. 2108 * 2109 * <p> 2110 * {@code null} is accepted, but will be converted to an empty String. 2111 * </p> 2112 * 2113 * @param fieldSeparator the new field separator text. 2114 */ 2115 protected void setFieldSeparator(final String fieldSeparator) { 2116 this.fieldSeparator = ObjectUtils.toString(fieldSeparator); 2117 } 2118 2119 /** 2120 * Sets whether the field separator should be added at the end of each buffer. 2121 * 2122 * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag. 2123 * @since 2.0 2124 */ 2125 protected void setFieldSeparatorAtEnd(final boolean fieldSeparatorAtEnd) { 2126 this.fieldSeparatorAtEnd = fieldSeparatorAtEnd; 2127 } 2128 2129 /** 2130 * Sets whether the field separator should be added at the start of each buffer. 2131 * 2132 * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag. 2133 * @since 2.0 2134 */ 2135 protected void setFieldSeparatorAtStart(final boolean fieldSeparatorAtStart) { 2136 this.fieldSeparatorAtStart = fieldSeparatorAtStart; 2137 } 2138 2139 /** 2140 * Sets the text to output when {@code null} found. 2141 * 2142 * <p> 2143 * {@code null} is accepted, but will be converted to an empty String. 2144 * </p> 2145 * 2146 * @param nullText the new text to output when null found. 2147 */ 2148 protected void setNullText(final String nullText) { 2149 this.nullText = ObjectUtils.toString(nullText); 2150 } 2151 2152 /** 2153 * Sets the end text to output when a {@link Collection}, {@link Map} or array size is output. 2154 * 2155 * <p> 2156 * This is output after the size value. 2157 * </p> 2158 * 2159 * <p> 2160 * {@code null} is accepted, but will be converted to an empty String. 2161 * </p> 2162 * 2163 * @param sizeEndText the new end of size text. 2164 */ 2165 protected void setSizeEndText(final String sizeEndText) { 2166 this.sizeEndText = ObjectUtils.toString(sizeEndText); 2167 } 2168 2169 /** 2170 * Sets the start text to output when a {@link Collection}, {@link Map} or array size is output. 2171 * 2172 * <p> 2173 * This is output before the size value. 2174 * </p> 2175 * 2176 * <p> 2177 * {@code null} is accepted, but will be converted to an empty String. 2178 * </p> 2179 * 2180 * @param sizeStartText the new start of size text. 2181 */ 2182 protected void setSizeStartText(final String sizeStartText) { 2183 this.sizeStartText = ObjectUtils.toString(sizeStartText); 2184 } 2185 2186 /** 2187 * Sets the end text to output when an {@link Object} is output in summary mode. 2188 * 2189 * <p> 2190 * This is output after the size value. 2191 * </p> 2192 * 2193 * <p> 2194 * {@code null} is accepted, but will be converted to an empty String. 2195 * </p> 2196 * 2197 * @param summaryObjectEndText the new end of summary text. 2198 */ 2199 protected void setSummaryObjectEndText(final String summaryObjectEndText) { 2200 this.summaryObjectEndText = ObjectUtils.toString(summaryObjectEndText); 2201 } 2202 2203 /** 2204 * Sets the start text to output when an {@link Object} is output in summary mode. 2205 * 2206 * <p> 2207 * This is output before the size value. 2208 * </p> 2209 * 2210 * <p> 2211 * {@code null} is accepted, but will be converted to an empty String. 2212 * </p> 2213 * 2214 * @param summaryObjectStartText the new start of summary text. 2215 */ 2216 protected void setSummaryObjectStartText(final String summaryObjectStartText) { 2217 this.summaryObjectStartText = ObjectUtils.toString(summaryObjectStartText); 2218 } 2219 2220 /** 2221 * Sets whether to use the class name. 2222 * 2223 * @param useClassName the new useClassName flag. 2224 */ 2225 protected void setUseClassName(final boolean useClassName) { 2226 this.useClassName = useClassName; 2227 } 2228 2229 /** 2230 * Sets whether to use the field names passed in. 2231 * 2232 * @param useFieldNames the new useFieldNames flag. 2233 */ 2234 protected void setUseFieldNames(final boolean useFieldNames) { 2235 this.useFieldNames = useFieldNames; 2236 } 2237 2238 /** 2239 * Sets whether to use the identity hash code. 2240 * 2241 * @param useIdentityHashCode the new useIdentityHashCode flag. 2242 */ 2243 protected void setUseIdentityHashCode(final boolean useIdentityHashCode) { 2244 this.useIdentityHashCode = useIdentityHashCode; 2245 } 2246 2247 /** 2248 * Sets whether to output short or long class names. 2249 * 2250 * @param useShortClassName the new useShortClassName flag. 2251 * @since 2.0 2252 */ 2253 protected void setUseShortClassName(final boolean useShortClassName) { 2254 this.useShortClassName = useShortClassName; 2255 } 2256}