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