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