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