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