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