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