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