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