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