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