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; 028import org.apache.commons.lang3.SystemUtils; 029 030/** 031 * <p>Controls <code>String</code> formatting for {@link ToStringBuilder}. 032 * The main public interface is always via <code>ToStringBuilder</code>.</p> 033 * 034 * <p>These classes are intended to be used as <code>Singletons</code>. 035 * There is no need to instantiate a new style each time. A program 036 * will generally use one of the predefined constants on this class. 037 * Alternatively, the {@link StandardToStringStyle} class can be used 038 * to set the individual settings. Thus most styles can be achieved 039 * without subclassing.</p> 040 * 041 * <p>If required, a subclass can override as many or as few of the 042 * methods as it requires. Each object type (from <code>boolean</code> 043 * to <code>long</code> to <code>Object</code> to <code>int[]</code>) has 044 * its own methods to output it. Most have two versions, detail and summary. 045 * 046 * <p>For example, the detail version of the array based methods will 047 * output the whole array, whereas the summary method will just output 048 * the array length.</p> 049 * 050 * <p>If you want to format the output of certain objects, such as dates, you 051 * must create a subclass and override a method. 052 * </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 */ 066public abstract class ToStringStyle implements Serializable { 067 068 /** 069 * Serialization version ID. 070 */ 071 private static final long serialVersionUID = -2587890625525655916L; 072 073 /** 074 * The default toString style. Using the <code>Person</code> 075 * example from {@link ToStringBuilder}, the output would look like this: 076 * 077 * <pre> 078 * Person@182f0db[name=John Doe,age=33,smoker=false] 079 * </pre> 080 */ 081 public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle(); 082 083 /** 084 * The multi line toString style. Using the <code>Person</code> 085 * example from {@link ToStringBuilder}, the output would look like this: 086 * 087 * <pre> 088 * Person@182f0db[ 089 * name=John Doe 090 * age=33 091 * smoker=false 092 * ] 093 * </pre> 094 */ 095 public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle(); 096 097 /** 098 * The no field names toString style. Using the 099 * <code>Person</code> example from {@link ToStringBuilder}, the output 100 * would look like this: 101 * 102 * <pre> 103 * Person@182f0db[John Doe,33,false] 104 * </pre> 105 */ 106 public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle(); 107 108 /** 109 * The short prefix toString style. Using the <code>Person</code> example 110 * from {@link ToStringBuilder}, the output would look like this: 111 * 112 * <pre> 113 * Person[name=John Doe,age=33,smoker=false] 114 * </pre> 115 * 116 * @since 2.1 117 */ 118 public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle(); 119 120 /** 121 * The simple toString style. Using the <code>Person</code> 122 * example from {@link ToStringBuilder}, the output would look like this: 123 * 124 * <pre> 125 * John Doe,33,false 126 * </pre> 127 */ 128 public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle(); 129 130 /** 131 * The no class name toString style. Using the <code>Person</code> 132 * example from {@link ToStringBuilder}, the output would look like this: 133 * 134 * <pre> 135 * [name=John Doe,age=33,smoker=false] 136 * </pre> 137 * 138 * @since 3.4 139 */ 140 public static final ToStringStyle NO_CLASS_NAME_STYLE = new NoClassNameToStringStyle(); 141 142 /** 143 * The JSON toString style. Using the <code>Person</code> example from 144 * {@link ToStringBuilder}, the output would look like this: 145 * 146 * <pre> 147 * {"name": "John Doe", "age": 33, "smoker": true} 148 * </pre> 149 * 150 * <strong>Note:</strong> Since field names are mandatory in JSON, this 151 * ToStringStyle will throw an {@link UnsupportedOperationException} if no 152 * field name is passed in while appending. Furthermore This ToStringStyle 153 * will only generate valid JSON if referenced objects also produce JSON 154 * when calling {@code toString()} on them. 155 * 156 * @since 3.4 157 * @see <a href="http://json.org">json.org</a> 158 */ 159 public static final ToStringStyle JSON_STYLE = new JsonToStringStyle(); 160 161 /** 162 * <p> 163 * A registry of objects used by <code>reflectionToString</code> methods 164 * to detect cyclical object references and avoid infinite loops. 165 * </p> 166 */ 167 private static final ThreadLocal<WeakHashMap<Object, Object>> REGISTRY = 168 new ThreadLocal<WeakHashMap<Object,Object>>(); 169 /* 170 * Note that objects of this class are generally shared between threads, so 171 * an instance variable would not be suitable here. 172 * 173 * In normal use the registry should always be left empty, because the caller 174 * should call toString() which will clean up. 175 * 176 * See LANG-792 177 */ 178 179 /** 180 * <p> 181 * Returns the registry of objects being traversed by the <code>reflectionToString</code> 182 * methods in the current thread. 183 * </p> 184 * 185 * @return Set the registry of objects being traversed 186 */ 187 static Map<Object, Object> getRegistry() { 188 return REGISTRY.get(); 189 } 190 191 /** 192 * <p> 193 * Returns <code>true</code> if the registry contains the given object. 194 * Used by the reflection methods to avoid infinite loops. 195 * </p> 196 * 197 * @param value 198 * The object to lookup in the registry. 199 * @return boolean <code>true</code> if the registry contains the given 200 * object. 201 */ 202 static boolean isRegistered(final Object value) { 203 final Map<Object, Object> m = getRegistry(); 204 return m != null && m.containsKey(value); 205 } 206 207 /** 208 * <p> 209 * Registers the given object. Used by the reflection methods to avoid 210 * infinite loops. 211 * </p> 212 * 213 * @param value 214 * The object to register. 215 */ 216 static void register(final Object value) { 217 if (value != null) { 218 final Map<Object, Object> m = getRegistry(); 219 if (m == null) { 220 REGISTRY.set(new WeakHashMap<Object, Object>()); 221 } 222 getRegistry().put(value, null); 223 } 224 } 225 226 /** 227 * <p> 228 * Unregisters the given object. 229 * </p> 230 * 231 * <p> 232 * Used by the reflection methods to avoid infinite loops. 233 * </p> 234 * 235 * @param value 236 * The object to unregister. 237 */ 238 static void unregister(final Object value) { 239 if (value != null) { 240 final Map<Object, Object> m = getRegistry(); 241 if (m != null) { 242 m.remove(value); 243 if (m.isEmpty()) { 244 REGISTRY.remove(); 245 } 246 } 247 } 248 } 249 250 /** 251 * Whether to use the field names, the default is <code>true</code>. 252 */ 253 private boolean useFieldNames = true; 254 255 /** 256 * Whether to use the class name, the default is <code>true</code>. 257 */ 258 private boolean useClassName = true; 259 260 /** 261 * Whether to use short class names, the default is <code>false</code>. 262 */ 263 private boolean useShortClassName = false; 264 265 /** 266 * Whether to use the identity hash code, the default is <code>true</code>. 267 */ 268 private boolean useIdentityHashCode = true; 269 270 /** 271 * The content start <code>'['</code>. 272 */ 273 private String contentStart = "["; 274 275 /** 276 * The content end <code>']'</code>. 277 */ 278 private String contentEnd = "]"; 279 280 /** 281 * The field name value separator <code>'='</code>. 282 */ 283 private String fieldNameValueSeparator = "="; 284 285 /** 286 * Whether the field separator should be added before any other fields. 287 */ 288 private boolean fieldSeparatorAtStart = false; 289 290 /** 291 * Whether the field separator should be added after any other fields. 292 */ 293 private boolean fieldSeparatorAtEnd = false; 294 295 /** 296 * The field separator <code>','</code>. 297 */ 298 private String fieldSeparator = ","; 299 300 /** 301 * The array start <code>'{'</code>. 302 */ 303 private String arrayStart = "{"; 304 305 /** 306 * The array separator <code>','</code>. 307 */ 308 private String arraySeparator = ","; 309 310 /** 311 * The detail for array content. 312 */ 313 private boolean arrayContentDetail = true; 314 315 /** 316 * The array end <code>'}'</code>. 317 */ 318 private String arrayEnd = "}"; 319 320 /** 321 * The value to use when fullDetail is <code>null</code>, 322 * the default value is <code>true</code>. 323 */ 324 private boolean defaultFullDetail = true; 325 326 /** 327 * The <code>null</code> text <code>'<null>'</code>. 328 */ 329 private String nullText = "<null>"; 330 331 /** 332 * The summary size text start <code>'<size'</code>. 333 */ 334 private String sizeStartText = "<size="; 335 336 /** 337 * The summary size text start <code>'>'</code>. 338 */ 339 private String sizeEndText = ">"; 340 341 /** 342 * The summary object text start <code>'<'</code>. 343 */ 344 private String summaryObjectStartText = "<"; 345 346 /** 347 * The summary object text start <code>'>'</code>. 348 */ 349 private String summaryObjectEndText = ">"; 350 351 //---------------------------------------------------------------------------- 352 353 /** 354 * <p>Constructor.</p> 355 */ 356 protected ToStringStyle() { 357 super(); 358 } 359 360 //---------------------------------------------------------------------------- 361 362 /** 363 * <p>Append to the <code>toString</code> the superclass toString.</p> 364 * <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p> 365 * 366 * <p>A <code>null</code> <code>superToString</code> is ignored.</p> 367 * 368 * @param buffer the <code>StringBuffer</code> to populate 369 * @param superToString the <code>super.toString()</code> 370 * @since 2.0 371 */ 372 public void appendSuper(final StringBuffer buffer, final String superToString) { 373 appendToString(buffer, superToString); 374 } 375 376 /** 377 * <p>Append to the <code>toString</code> another toString.</p> 378 * <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p> 379 * 380 * <p>A <code>null</code> <code>toString</code> is ignored.</p> 381 * 382 * @param buffer the <code>StringBuffer</code> to populate 383 * @param toString the additional <code>toString</code> 384 * @since 2.0 385 */ 386 public void appendToString(final StringBuffer buffer, final String toString) { 387 if (toString != null) { 388 final int pos1 = toString.indexOf(contentStart) + contentStart.length(); 389 final int pos2 = toString.lastIndexOf(contentEnd); 390 if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) { 391 final String data = toString.substring(pos1, pos2); 392 if (fieldSeparatorAtStart) { 393 removeLastFieldSeparator(buffer); 394 } 395 buffer.append(data); 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 == false) { 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 ToStringStyle.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 ToStringStyle.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 ToStringStyle.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 ToStringStyle.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(SystemUtils.LINE_SEPARATOR + " "); 2298 this.setFieldSeparatorAtStart(true); 2299 this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]"); 2300 } 2301 2302 /** 2303 * <p>Ensure <code>Singleton</code> after serialization.</p> 2304 * 2305 * @return the singleton 2306 */ 2307 private Object readResolve() { 2308 return ToStringStyle.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 hashcode 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 ToStringStyle.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 /** 2368 * The summary size text start <code>'>'</code>. 2369 */ 2370 private String FIELD_NAME_PREFIX = "\""; 2371 2372 /** 2373 * <p> 2374 * Constructor. 2375 * </p> 2376 * 2377 * <p> 2378 * Use the static constant rather than instantiating. 2379 * </p> 2380 */ 2381 JsonToStringStyle() { 2382 super(); 2383 2384 this.setUseClassName(false); 2385 this.setUseIdentityHashCode(false); 2386 2387 this.setContentStart("{"); 2388 this.setContentEnd("}"); 2389 2390 this.setArrayStart("["); 2391 this.setArrayEnd("]"); 2392 2393 this.setFieldSeparator(","); 2394 this.setFieldNameValueSeparator(":"); 2395 2396 this.setNullText("null"); 2397 2398 this.setSummaryObjectStartText("\"<"); 2399 this.setSummaryObjectEndText(">\""); 2400 2401 this.setSizeStartText("\"<size="); 2402 this.setSizeEndText(">\""); 2403 } 2404 2405 @Override 2406 public void append(StringBuffer buffer, String fieldName, 2407 Object[] array, Boolean fullDetail) { 2408 2409 if (fieldName == null) { 2410 throw new UnsupportedOperationException( 2411 "Field names are mandatory when using JsonToStringStyle"); 2412 } 2413 if (!isFullDetail(fullDetail)){ 2414 throw new UnsupportedOperationException( 2415 "FullDetail must be true when using JsonToStringStyle"); 2416 } 2417 2418 super.append(buffer, fieldName, array, fullDetail); 2419 } 2420 2421 @Override 2422 public void append(StringBuffer buffer, String fieldName, long[] array, 2423 Boolean fullDetail) { 2424 2425 if (fieldName == null) { 2426 throw new UnsupportedOperationException( 2427 "Field names are mandatory when using JsonToStringStyle"); 2428 } 2429 if (!isFullDetail(fullDetail)){ 2430 throw new UnsupportedOperationException( 2431 "FullDetail must be true when using JsonToStringStyle"); 2432 } 2433 2434 super.append(buffer, fieldName, array, fullDetail); 2435 } 2436 2437 @Override 2438 public void append(StringBuffer buffer, String fieldName, int[] array, 2439 Boolean fullDetail) { 2440 2441 if (fieldName == null) { 2442 throw new UnsupportedOperationException( 2443 "Field names are mandatory when using JsonToStringStyle"); 2444 } 2445 if (!isFullDetail(fullDetail)){ 2446 throw new UnsupportedOperationException( 2447 "FullDetail must be true when using JsonToStringStyle"); 2448 } 2449 2450 super.append(buffer, fieldName, array, fullDetail); 2451 } 2452 2453 @Override 2454 public void append(StringBuffer buffer, String fieldName, 2455 short[] array, Boolean fullDetail) { 2456 2457 if (fieldName == null) { 2458 throw new UnsupportedOperationException( 2459 "Field names are mandatory when using JsonToStringStyle"); 2460 } 2461 if (!isFullDetail(fullDetail)){ 2462 throw new UnsupportedOperationException( 2463 "FullDetail must be true when using JsonToStringStyle"); 2464 } 2465 2466 super.append(buffer, fieldName, array, fullDetail); 2467 } 2468 2469 @Override 2470 public void append(StringBuffer buffer, String fieldName, byte[] array, 2471 Boolean fullDetail) { 2472 2473 if (fieldName == null) { 2474 throw new UnsupportedOperationException( 2475 "Field names are mandatory when using JsonToStringStyle"); 2476 } 2477 if (!isFullDetail(fullDetail)){ 2478 throw new UnsupportedOperationException( 2479 "FullDetail must be true when using JsonToStringStyle"); 2480 } 2481 2482 super.append(buffer, fieldName, array, fullDetail); 2483 } 2484 2485 @Override 2486 public void append(StringBuffer buffer, String fieldName, char[] array, 2487 Boolean fullDetail) { 2488 2489 if (fieldName == null) { 2490 throw new UnsupportedOperationException( 2491 "Field names are mandatory when using JsonToStringStyle"); 2492 } 2493 if (!isFullDetail(fullDetail)){ 2494 throw new UnsupportedOperationException( 2495 "FullDetail must be true when using JsonToStringStyle"); 2496 } 2497 2498 super.append(buffer, fieldName, array, fullDetail); 2499 } 2500 2501 @Override 2502 public void append(StringBuffer buffer, String fieldName, 2503 double[] array, Boolean fullDetail) { 2504 2505 if (fieldName == null) { 2506 throw new UnsupportedOperationException( 2507 "Field names are mandatory when using JsonToStringStyle"); 2508 } 2509 if (!isFullDetail(fullDetail)){ 2510 throw new UnsupportedOperationException( 2511 "FullDetail must be true when using JsonToStringStyle"); 2512 } 2513 2514 super.append(buffer, fieldName, array, fullDetail); 2515 } 2516 2517 @Override 2518 public void append(StringBuffer buffer, String fieldName, 2519 float[] array, Boolean fullDetail) { 2520 2521 if (fieldName == null) { 2522 throw new UnsupportedOperationException( 2523 "Field names are mandatory when using JsonToStringStyle"); 2524 } 2525 if (!isFullDetail(fullDetail)){ 2526 throw new UnsupportedOperationException( 2527 "FullDetail must be true when using JsonToStringStyle"); 2528 } 2529 2530 super.append(buffer, fieldName, array, fullDetail); 2531 } 2532 2533 @Override 2534 public void append(StringBuffer buffer, String fieldName, 2535 boolean[] array, Boolean fullDetail) { 2536 2537 if (fieldName == null) { 2538 throw new UnsupportedOperationException( 2539 "Field names are mandatory when using JsonToStringStyle"); 2540 } 2541 if (!isFullDetail(fullDetail)){ 2542 throw new UnsupportedOperationException( 2543 "FullDetail must be true when using JsonToStringStyle"); 2544 } 2545 2546 super.append(buffer, fieldName, array, fullDetail); 2547 } 2548 2549 @Override 2550 public void append(StringBuffer buffer, String fieldName, Object value, 2551 Boolean fullDetail) { 2552 2553 if (fieldName == null) { 2554 throw new UnsupportedOperationException( 2555 "Field names are mandatory when using JsonToStringStyle"); 2556 } 2557 if (!isFullDetail(fullDetail)){ 2558 throw new UnsupportedOperationException( 2559 "FullDetail must be true when using JsonToStringStyle"); 2560 } 2561 2562 super.append(buffer, fieldName, value, fullDetail); 2563 } 2564 2565 @Override 2566 protected void appendDetail(StringBuffer buffer, String fieldName, char value) { 2567 appendValueAsString(buffer, String.valueOf(value)); 2568 } 2569 2570 @Override 2571 protected void appendDetail(StringBuffer buffer, String fieldName, Object value) { 2572 2573 if (value == null) { 2574 appendNullText(buffer, fieldName); 2575 return; 2576 } 2577 2578 if (value instanceof String || value instanceof Character) { 2579 appendValueAsString(buffer, value.toString()); 2580 return; 2581 } 2582 2583 if (value instanceof Number || value instanceof Boolean) { 2584 buffer.append(value); 2585 return; 2586 } 2587 2588 final String valueAsString = value.toString(); 2589 if (isJsonObject(valueAsString) || isJsonArray(valueAsString)) { 2590 buffer.append(value); 2591 return; 2592 } 2593 2594 appendDetail(buffer, fieldName, valueAsString); 2595 } 2596 2597 private boolean isJsonArray(String valueAsString) { 2598 return valueAsString.startsWith(getArrayStart()) 2599 && valueAsString.startsWith(getArrayEnd()); 2600 } 2601 2602 private boolean isJsonObject(String valueAsString) { 2603 return valueAsString.startsWith(getContentStart()) 2604 && valueAsString.endsWith(getContentEnd()); 2605 } 2606 2607 /** 2608 * Appends the given String in parenthesis to the given StringBuffer. 2609 * 2610 * @param buffer the StringBuffer to append the value to. 2611 * @param value the value to append. 2612 */ 2613 private void appendValueAsString(StringBuffer buffer, String value) { 2614 buffer.append("\"" + value + "\""); 2615 } 2616 2617 @Override 2618 protected void appendFieldStart(StringBuffer buffer, String fieldName) { 2619 2620 if (fieldName == null) { 2621 throw new UnsupportedOperationException( 2622 "Field names are mandatory when using JsonToStringStyle"); 2623 } 2624 2625 super.appendFieldStart(buffer, FIELD_NAME_PREFIX + fieldName 2626 + FIELD_NAME_PREFIX); 2627 } 2628 2629 /** 2630 * <p> 2631 * Ensure <code>Singleton</code> after serialization. 2632 * </p> 2633 * 2634 * @return the singleton 2635 */ 2636 private Object readResolve() { 2637 return ToStringStyle.JSON_STYLE; 2638 } 2639 2640 } 2641}