1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang.builder;
18
19 import java.io.Serializable;
20 import java.lang.reflect.Array;
21 import java.util.Collection;
22 import java.util.HashSet;
23 import java.util.Map;
24 import java.util.Set;
25
26 import org.apache.commons.lang.ClassUtils;
27 import org.apache.commons.lang.ObjectUtils;
28 import org.apache.commons.lang.SystemUtils;
29
30 /**
31 * <p>Controls <code>String</code> formatting for {@link ToStringBuilder}.
32 * The main public interface is always via <code>ToStringBuilder</code>.</p>
33 *
34 * <p>These classes are intended to be used as <code>Singletons</code>.
35 * There is no need to instantiate a new style each time. A program
36 * will generally use one of the predefined constants on this class.
37 * Alternatively, the {@link StandardToStringStyle} class can be used
38 * to set the individual settings. Thus most styles can be achieved
39 * without subclassing.</p>
40 *
41 * <p>If required, a subclass can override as many or as few of the
42 * methods as it requires. Each object type (from <code>boolean</code>
43 * to <code>long</code> to <code>Object</code> to <code>int[]</code>) has
44 * its own methods to output it. Most have two versions, detail and summary.
45 *
46 * <p>For example, the detail version of the array based methods will
47 * output the whole array, whereas the summary method will just output
48 * the array length.</p>
49 *
50 * <p>If you want to format the output of certain objects, such as dates, you
51 * must create a subclass and override a method.
52 * <pre>
53 * public class MyStyle extends ToStringStyle {
54 * protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
55 * if (value instanceof Date) {
56 * value = new SimpleDateFormat("yyyy-MM-dd").format(value);
57 * }
58 * buffer.append(value);
59 * }
60 * }
61 * </pre>
62 * </p>
63 *
64 * @author Stephen Colebourne
65 * @author Gary Gregory
66 * @author Pete Gieser
67 * @author Masato Tezuka
68 * @since 1.0
69 * @version $Id: ToStringStyle.java 594386 2007-11-13 01:22:21Z bayard $
70 */
71 public abstract class ToStringStyle implements Serializable {
72
73 /**
74 * The default toString style. Using the Using the <code>Person</code>
75 * example from {@link ToStringBuilder}, the output would look like this:
76 *
77 * <pre>
78 * Person@182f0db[name=John Doe,age=33,smoker=false]
79 * </pre>
80 */
81 public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle();
82
83 /**
84 * The multi line toString style. Using the Using the <code>Person</code>
85 * example from {@link ToStringBuilder}, the output would look like this:
86 *
87 * <pre>
88 * Person@182f0db[
89 * name=John Doe
90 * age=33
91 * smoker=false
92 * ]
93 * </pre>
94 */
95 public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle();
96
97 /**
98 * The no field names toString style. Using the Using the
99 * <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 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 * <p>
132 * A registry of objects used by <code>reflectionToString</code> methods
133 * to detect cyclical object references and avoid infinite loops.
134 * </p>
135 */
136 private static ThreadLocal registry = new ThreadLocal() {
137 protected Object initialValue() {
138 // The HashSet implementation is not synchronized,
139 // which is just what we need here.
140 return new HashSet();
141 }
142 };
143
144 /**
145 * <p>
146 * Returns the registry of objects being traversed by the <code>reflectionToString</code>
147 * methods in the current thread.
148 * </p>
149 *
150 * @return Set the registry of objects being traversed
151 */
152 static Set getRegistry() {
153 return (Set) registry.get();
154 }
155
156 /**
157 * <p>
158 * Returns <code>true</code> if the registry contains the given object.
159 * Used by the reflection methods to avoid infinite loops.
160 * </p>
161 *
162 * @param value
163 * The object to lookup in the registry.
164 * @return boolean <code>true</code> if the registry contains the given
165 * object.
166 */
167 static boolean isRegistered(Object value) {
168 return getRegistry().contains(value);
169 }
170
171 /**
172 * <p>
173 * Registers the given object. Used by the reflection methods to avoid
174 * infinite loops.
175 * </p>
176 *
177 * @param value
178 * The object to register.
179 */
180 static void register(Object value) {
181 if (value != null) {
182 getRegistry().add(value);
183 }
184 }
185
186 /**
187 * <p>
188 * Unregisters the given object.
189 * </p>
190 *
191 * <p>
192 * Used by the reflection methods to avoid infinite loops.
193 * </p>
194 *
195 * @param value
196 * The object to unregister.
197 */
198 static void unregister(Object value) {
199 getRegistry().remove(value);
200 }
201
202 /**
203 * Whether to use the field names, the default is <code>true</code>.
204 */
205 private boolean useFieldNames = true;
206
207 /**
208 * Whether to use the class name, the default is <code>true</code>.
209 */
210 private boolean useClassName = true;
211
212 /**
213 * Whether to use short class names, the default is <code>false</code>.
214 */
215 private boolean useShortClassName = false;
216
217 /**
218 * Whether to use the identity hash code, the default is <code>true</code>.
219 */
220 private boolean useIdentityHashCode = true;
221
222 /**
223 * The content start <code>'['</code>.
224 */
225 private String contentStart = "[";
226
227 /**
228 * The content end <code>']'</code>.
229 */
230 private String contentEnd = "]";
231
232 /**
233 * The field name value separator <code>'='</code>.
234 */
235 private String fieldNameValueSeparator = "=";
236
237 /**
238 * Whether the field separator should be added before any other fields.
239 */
240 private boolean fieldSeparatorAtStart = false;
241
242 /**
243 * Whether the field separator should be added after any other fields.
244 */
245 private boolean fieldSeparatorAtEnd = false;
246
247 /**
248 * The field separator <code>','</code>.
249 */
250 private String fieldSeparator = ",";
251
252 /**
253 * The array start <code>'{'</code>.
254 */
255 private String arrayStart = "{";
256
257 /**
258 * The array separator <code>','</code>.
259 */
260 private String arraySeparator = ",";
261
262 /**
263 * The detail for array content.
264 */
265 private boolean arrayContentDetail = true;
266
267 /**
268 * The array end <code>'}'</code>.
269 */
270 private String arrayEnd = "}";
271
272 /**
273 * The value to use when fullDetail is <code>null</code>,
274 * the default value is <code>true</code>.
275 */
276 private boolean defaultFullDetail = true;
277
278 /**
279 * The <code>null</code> text <code>'<null>'</code>.
280 */
281 private String nullText = "<null>";
282
283 /**
284 * The summary size text start <code>'<size'</code>.
285 */
286 private String sizeStartText = "<size=";
287
288 /**
289 * The summary size text start <code>'>'</code>.
290 */
291 private String sizeEndText = ">";
292
293 /**
294 * The summary object text start <code>'<'</code>.
295 */
296 private String summaryObjectStartText = "<";
297
298 /**
299 * The summary object text start <code>'>'</code>.
300 */
301 private String summaryObjectEndText = ">";
302
303 //----------------------------------------------------------------------------
304
305 /**
306 * <p>Constructor.</p>
307 */
308 protected ToStringStyle() {
309 super();
310 }
311
312 //----------------------------------------------------------------------------
313
314 /**
315 * <p>Append to the <code>toString</code> the superclass toString.</p>
316 * <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p>
317 *
318 * <p>A <code>null</code> <code>superToString</code> is ignored.</p>
319 *
320 * @param buffer the <code>StringBuffer</code> to populate
321 * @param superToString the <code>super.toString()</code>
322 * @since 2.0
323 */
324 public void appendSuper(StringBuffer buffer, String superToString) {
325 appendToString(buffer, superToString);
326 }
327
328 /**
329 * <p>Append to the <code>toString</code> another toString.</p>
330 * <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p>
331 *
332 * <p>A <code>null</code> <code>toString</code> is ignored.</p>
333 *
334 * @param buffer the <code>StringBuffer</code> to populate
335 * @param toString the additional <code>toString</code>
336 * @since 2.0
337 */
338 public void appendToString(StringBuffer buffer, String toString) {
339 if (toString != null) {
340 int pos1 = toString.indexOf(contentStart) + contentStart.length();
341 int pos2 = toString.lastIndexOf(contentEnd);
342 if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) {
343 String data = toString.substring(pos1, pos2);
344 if (fieldSeparatorAtStart) {
345 removeLastFieldSeparator(buffer);
346 }
347 buffer.append(data);
348 appendFieldSeparator(buffer);
349 }
350 }
351 }
352
353 /**
354 * <p>Append to the <code>toString</code> the start of data indicator.</p>
355 *
356 * @param buffer the <code>StringBuffer</code> to populate
357 * @param object the <code>Object</code> to build a <code>toString</code> for
358 */
359 public void appendStart(StringBuffer buffer, Object object) {
360 if (object != null) {
361 appendClassName(buffer, object);
362 appendIdentityHashCode(buffer, object);
363 appendContentStart(buffer);
364 if (fieldSeparatorAtStart) {
365 appendFieldSeparator(buffer);
366 }
367 }
368 }
369
370 /**
371 * <p>Append to the <code>toString</code> the end of data indicator.</p>
372 *
373 * @param buffer the <code>StringBuffer</code> to populate
374 * @param object the <code>Object</code> to build a
375 * <code>toString</code> for.
376 */
377 public void appendEnd(StringBuffer buffer, Object object) {
378 if (this.fieldSeparatorAtEnd == false) {
379 removeLastFieldSeparator(buffer);
380 }
381 appendContentEnd(buffer);
382 unregister(object);
383 }
384
385 /**
386 * <p>Remove the last field separator from the buffer.</p>
387 *
388 * @param buffer the <code>StringBuffer</code> to populate
389 * @since 2.0
390 */
391 protected void removeLastFieldSeparator(StringBuffer buffer) {
392 int len = buffer.length();
393 int sepLen = fieldSeparator.length();
394 if (len > 0 && sepLen > 0 && len >= sepLen) {
395 boolean match = true;
396 for (int i = 0; i < sepLen; i++) {
397 if (buffer.charAt(len - 1 - i) != fieldSeparator.charAt(sepLen - 1 - i)) {
398 match = false;
399 break;
400 }
401 }
402 if (match) {
403 buffer.setLength(len - sepLen);
404 }
405 }
406 }
407
408 //----------------------------------------------------------------------------
409
410 /**
411 * <p>Append to the <code>toString</code> an <code>Object</code>
412 * value, printing the full <code>toString</code> of the
413 * <code>Object</code> passed in.</p>
414 *
415 * @param buffer the <code>StringBuffer</code> to populate
416 * @param fieldName the field name
417 * @param value the value to add to the <code>toString</code>
418 * @param fullDetail <code>true</code> for detail, <code>false</code>
419 * for summary info, <code>null</code> for style decides
420 */
421 public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
422 appendFieldStart(buffer, fieldName);
423
424 if (value == null) {
425 appendNullText(buffer, fieldName);
426
427 } else {
428 appendInternal(buffer, fieldName, value, isFullDetail(fullDetail));
429 }
430
431 appendFieldEnd(buffer, fieldName);
432 }
433
434 /**
435 * <p>Append to the <code>toString</code> an <code>Object</code>,
436 * correctly interpreting its type.</p>
437 *
438 * <p>This method performs the main lookup by Class type to correctly
439 * route arrays, <code>Collections</code>, <code>Maps</code> and
440 * <code>Objects</code> to the appropriate method.</p>
441 *
442 * <p>Either detail or summary views can be specified.</p>
443 *
444 * <p>If a cycle is detected, an object will be appended with the
445 * <code>Object.toString()</code> format.</p>
446 *
447 * @param buffer the <code>StringBuffer</code> to populate
448 * @param fieldName the field name, typically not used as already appended
449 * @param value the value to add to the <code>toString</code>,
450 * not <code>null</code>
451 * @param detail output detail or not
452 */
453 protected void appendInternal(StringBuffer buffer, String fieldName, Object value, boolean detail) {
454 if (isRegistered(value)
455 && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) {
456 appendCyclicObject(buffer, fieldName, value);
457 return;
458 }
459
460 register(value);
461
462 try {
463 if (value instanceof Collection) {
464 if (detail) {
465 appendDetail(buffer, fieldName, (Collection) value);
466 } else {
467 appendSummarySize(buffer, fieldName, ((Collection) value).size());
468 }
469
470 } else if (value instanceof Map) {
471 if (detail) {
472 appendDetail(buffer, fieldName, (Map) value);
473 } else {
474 appendSummarySize(buffer, fieldName, ((Map) value).size());
475 }
476
477 } else if (value instanceof long[]) {
478 if (detail) {
479 appendDetail(buffer, fieldName, (long[]) value);
480 } else {
481 appendSummary(buffer, fieldName, (long[]) value);
482 }
483
484 } else if (value instanceof int[]) {
485 if (detail) {
486 appendDetail(buffer, fieldName, (int[]) value);
487 } else {
488 appendSummary(buffer, fieldName, (int[]) value);
489 }
490
491 } else if (value instanceof short[]) {
492 if (detail) {
493 appendDetail(buffer, fieldName, (short[]) value);
494 } else {
495 appendSummary(buffer, fieldName, (short[]) value);
496 }
497
498 } else if (value instanceof byte[]) {
499 if (detail) {
500 appendDetail(buffer, fieldName, (byte[]) value);
501 } else {
502 appendSummary(buffer, fieldName, (byte[]) value);
503 }
504
505 } else if (value instanceof char[]) {
506 if (detail) {
507 appendDetail(buffer, fieldName, (char[]) value);
508 } else {
509 appendSummary(buffer, fieldName, (char[]) value);
510 }
511
512 } else if (value instanceof double[]) {
513 if (detail) {
514 appendDetail(buffer, fieldName, (double[]) value);
515 } else {
516 appendSummary(buffer, fieldName, (double[]) value);
517 }
518
519 } else if (value instanceof float[]) {
520 if (detail) {
521 appendDetail(buffer, fieldName, (float[]) value);
522 } else {
523 appendSummary(buffer, fieldName, (float[]) value);
524 }
525
526 } else if (value instanceof boolean[]) {
527 if (detail) {
528 appendDetail(buffer, fieldName, (boolean[]) value);
529 } else {
530 appendSummary(buffer, fieldName, (boolean[]) value);
531 }
532
533 } else if (value.getClass().isArray()) {
534 if (detail) {
535 appendDetail(buffer, fieldName, (Object[]) value);
536 } else {
537 appendSummary(buffer, fieldName, (Object[]) value);
538 }
539
540 } else {
541 if (detail) {
542 appendDetail(buffer, fieldName, value);
543 } else {
544 appendSummary(buffer, fieldName, value);
545 }
546 }
547 } finally {
548 unregister(value);
549 }
550 }
551
552 /**
553 * <p>Append to the <code>toString</code> an <code>Object</code>
554 * value that has been detected to participate in a cycle. This
555 * implementation will print the standard string value of the value.</p>
556 *
557 * @param buffer the <code>StringBuffer</code> to populate
558 * @param fieldName the field name, typically not used as already appended
559 * @param value the value to add to the <code>toString</code>,
560 * not <code>null</code>
561 *
562 * @since 2.2
563 */
564 protected void appendCyclicObject(StringBuffer buffer, String fieldName, Object value) {
565 ObjectUtils.appendIdentityToString(buffer, value);
566 }
567
568 /**
569 * <p>Append to the <code>toString</code> an <code>Object</code>
570 * value, printing the full detail of the <code>Object</code>.</p>
571 *
572 * @param buffer the <code>StringBuffer</code> to populate
573 * @param fieldName the field name, typically not used as already appended
574 * @param value the value to add to the <code>toString</code>,
575 * not <code>null</code>
576 */
577 protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
578 buffer.append(value);
579 }
580
581 /**
582 * <p>Append to the <code>toString</code> a <code>Collection</code>.</p>
583 *
584 * @param buffer the <code>StringBuffer</code> to populate
585 * @param fieldName the field name, typically not used as already appended
586 * @param coll the <code>Collection</code> to add to the
587 * <code>toString</code>, not <code>null</code>
588 */
589 protected void appendDetail(StringBuffer buffer, String fieldName, Collection coll) {
590 buffer.append(coll);
591 }
592
593 /**
594 * <p>Append to the <code>toString</code> a <code>Map<code>.</p>
595 *
596 * @param buffer the <code>StringBuffer</code> to populate
597 * @param fieldName the field name, typically not used as already appended
598 * @param map the <code>Map</code> to add to the <code>toString</code>,
599 * not <code>null</code>
600 */
601 protected void appendDetail(StringBuffer buffer, String fieldName, Map map) {
602 buffer.append(map);
603 }
604
605 /**
606 * <p>Append to the <code>toString</code> an <code>Object</code>
607 * value, printing a summary of the <code>Object</code>.</P>
608 *
609 * @param buffer the <code>StringBuffer</code> to populate
610 * @param fieldName the field name, typically not used as already appended
611 * @param value the value to add to the <code>toString</code>,
612 * not <code>null</code>
613 */
614 protected void appendSummary(StringBuffer buffer, String fieldName, Object value) {
615 buffer.append(summaryObjectStartText);
616 buffer.append(getShortClassName(value.getClass()));
617 buffer.append(summaryObjectEndText);
618 }
619
620 //----------------------------------------------------------------------------
621
622 /**
623 * <p>Append to the <code>toString</code> a <code>long</code>
624 * value.</p>
625 *
626 * @param buffer the <code>StringBuffer</code> to populate
627 * @param fieldName the field name
628 * @param value the value to add to the <code>toString</code>
629 */
630 public void append(StringBuffer buffer, String fieldName, long value) {
631 appendFieldStart(buffer, fieldName);
632 appendDetail(buffer, fieldName, value);
633 appendFieldEnd(buffer, fieldName);
634 }
635
636 /**
637 * <p>Append to the <code>toString</code> a <code>long</code>
638 * value.</p>
639 *
640 * @param buffer the <code>StringBuffer</code> to populate
641 * @param fieldName the field name, typically not used as already appended
642 * @param value the value to add to the <code>toString</code>
643 */
644 protected void appendDetail(StringBuffer buffer, String fieldName, long value) {
645 buffer.append(value);
646 }
647
648 //----------------------------------------------------------------------------
649
650 /**
651 * <p>Append to the <code>toString</code> an <code>int</code>
652 * value.</p>
653 *
654 * @param buffer the <code>StringBuffer</code> to populate
655 * @param fieldName the field name
656 * @param value the value to add to the <code>toString</code>
657 */
658 public void append(StringBuffer buffer, String fieldName, int value) {
659 appendFieldStart(buffer, fieldName);
660 appendDetail(buffer, fieldName, value);
661 appendFieldEnd(buffer, fieldName);
662 }
663
664 /**
665 * <p>Append to the <code>toString</code> an <code>int</code>
666 * value.</p>
667 *
668 * @param buffer the <code>StringBuffer</code> to populate
669 * @param fieldName the field name, typically not used as already appended
670 * @param value the value to add to the <code>toString</code>
671 */
672 protected void appendDetail(StringBuffer buffer, String fieldName, int value) {
673 buffer.append(value);
674 }
675
676 //----------------------------------------------------------------------------
677
678 /**
679 * <p>Append to the <code>toString</code> a <code>short</code>
680 * value.</p>
681 *
682 * @param buffer the <code>StringBuffer</code> to populate
683 * @param fieldName the field name
684 * @param value the value to add to the <code>toString</code>
685 */
686 public void append(StringBuffer buffer, String fieldName, short value) {
687 appendFieldStart(buffer, fieldName);
688 appendDetail(buffer, fieldName, value);
689 appendFieldEnd(buffer, fieldName);
690 }
691
692 /**
693 * <p>Append to the <code>toString</code> a <code>short</code>
694 * value.</p>
695 *
696 * @param buffer the <code>StringBuffer</code> to populate
697 * @param fieldName the field name, typically not used as already appended
698 * @param value the value to add to the <code>toString</code>
699 */
700 protected void appendDetail(StringBuffer buffer, String fieldName, short value) {
701 buffer.append(value);
702 }
703
704 //----------------------------------------------------------------------------
705
706 /**
707 * <p>Append to the <code>toString</code> a <code>byte</code>
708 * value.</p>
709 *
710 * @param buffer the <code>StringBuffer</code> to populate
711 * @param fieldName the field name
712 * @param value the value to add to the <code>toString</code>
713 */
714 public void append(StringBuffer buffer, String fieldName, byte value) {
715 appendFieldStart(buffer, fieldName);
716 appendDetail(buffer, fieldName, value);
717 appendFieldEnd(buffer, fieldName);
718 }
719
720 /**
721 * <p>Append to the <code>toString</code> a <code>byte</code>
722 * value.</p>
723 *
724 * @param buffer the <code>StringBuffer</code> to populate
725 * @param fieldName the field name, typically not used as already appended
726 * @param value the value to add to the <code>toString</code>
727 */
728 protected void appendDetail(StringBuffer buffer, String fieldName, byte value) {
729 buffer.append(value);
730 }
731
732 //----------------------------------------------------------------------------
733
734 /**
735 * <p>Append to the <code>toString</code> a <code>char</code>
736 * value.</p>
737 *
738 * @param buffer the <code>StringBuffer</code> to populate
739 * @param fieldName the field name
740 * @param value the value to add to the <code>toString</code>
741 */
742 public void append(StringBuffer buffer, String fieldName, char value) {
743 appendFieldStart(buffer, fieldName);
744 appendDetail(buffer, fieldName, value);
745 appendFieldEnd(buffer, fieldName);
746 }
747
748 /**
749 * <p>Append to the <code>toString</code> a <code>char</code>
750 * value.</p>
751 *
752 * @param buffer the <code>StringBuffer</code> to populate
753 * @param fieldName the field name, typically not used as already appended
754 * @param value the value to add to the <code>toString</code>
755 */
756 protected void appendDetail(StringBuffer buffer, String fieldName, char value) {
757 buffer.append(value);
758 }
759
760 //----------------------------------------------------------------------------
761
762 /**
763 * <p>Append to the <code>toString</code> a <code>double</code>
764 * value.</p>
765 *
766 * @param buffer the <code>StringBuffer</code> to populate
767 * @param fieldName the field name
768 * @param value the value to add to the <code>toString</code>
769 */
770 public void append(StringBuffer buffer, String fieldName, double value) {
771 appendFieldStart(buffer, fieldName);
772 appendDetail(buffer, fieldName, value);
773 appendFieldEnd(buffer, fieldName);
774 }
775
776 /**
777 * <p>Append to the <code>toString</code> a <code>double</code>
778 * value.</p>
779 *
780 * @param buffer the <code>StringBuffer</code> to populate
781 * @param fieldName the field name, typically not used as already appended
782 * @param value the value to add to the <code>toString</code>
783 */
784 protected void appendDetail(StringBuffer buffer, String fieldName, double value) {
785 buffer.append(value);
786 }
787
788 //----------------------------------------------------------------------------
789
790 /**
791 * <p>Append to the <code>toString</code> a <code>float</code>
792 * value.</p>
793 *
794 * @param buffer the <code>StringBuffer</code> to populate
795 * @param fieldName the field name
796 * @param value the value to add to the <code>toString</code>
797 */
798 public void append(StringBuffer buffer, String fieldName, float value) {
799 appendFieldStart(buffer, fieldName);
800 appendDetail(buffer, fieldName, value);
801 appendFieldEnd(buffer, fieldName);
802 }
803
804 /**
805 * <p>Append to the <code>toString</code> a <code>float</code>
806 * value.</p>
807 *
808 * @param buffer the <code>StringBuffer</code> to populate
809 * @param fieldName the field name, typically not used as already appended
810 * @param value the value to add to the <code>toString</code>
811 */
812 protected void appendDetail(StringBuffer buffer, String fieldName, float value) {
813 buffer.append(value);
814 }
815
816 //----------------------------------------------------------------------------
817
818 /**
819 * <p>Append to the <code>toString</code> a <code>boolean</code>
820 * value.</p>
821 *
822 * @param buffer the <code>StringBuffer</code> to populate
823 * @param fieldName the field name
824 * @param value the value to add to the <code>toString</code>
825 */
826 public void append(StringBuffer buffer, String fieldName, boolean value) {
827 appendFieldStart(buffer, fieldName);
828 appendDetail(buffer, fieldName, value);
829 appendFieldEnd(buffer, fieldName);
830 }
831
832 /**
833 * <p>Append to the <code>toString</code> a <code>boolean</code>
834 * value.</p>
835 *
836 * @param buffer the <code>StringBuffer</code> to populate
837 * @param fieldName the field name, typically not used as already appended
838 * @param value the value to add to the <code>toString</code>
839 */
840 protected void appendDetail(StringBuffer buffer, String fieldName, boolean value) {
841 buffer.append(value);
842 }
843
844 /**
845 * <p>Append to the <code>toString</code> an <code>Object</code>
846 * array.</p>
847 *
848 * @param buffer the <code>StringBuffer</code> to populate
849 * @param fieldName the field name
850 * @param array the array to add to the toString
851 * @param fullDetail <code>true</code> for detail, <code>false</code>
852 * for summary info, <code>null</code> for style decides
853 */
854 public void append(StringBuffer buffer, String fieldName, Object[] array, Boolean fullDetail) {
855 appendFieldStart(buffer, fieldName);
856
857 if (array == null) {
858 appendNullText(buffer, fieldName);
859
860 } else if (isFullDetail(fullDetail)) {
861 appendDetail(buffer, fieldName, array);
862
863 } else {
864 appendSummary(buffer, fieldName, array);
865 }
866
867 appendFieldEnd(buffer, fieldName);
868 }
869
870 //----------------------------------------------------------------------------
871
872 /**
873 * <p>Append to the <code>toString</code> the detail of an
874 * <code>Object</code> array.</p>
875 *
876 * @param buffer the <code>StringBuffer</code> to populate
877 * @param fieldName the field name, typically not used as already appended
878 * @param array the array to add to the <code>toString</code>,
879 * not <code>null</code>
880 */
881 protected void appendDetail(StringBuffer buffer, String fieldName, Object[] array) {
882 buffer.append(arrayStart);
883 for (int i = 0; i < array.length; i++) {
884 Object item = array[i];
885 if (i > 0) {
886 buffer.append(arraySeparator);
887 }
888 if (item == null) {
889 appendNullText(buffer, fieldName);
890
891 } else {
892 appendInternal(buffer, fieldName, item, arrayContentDetail);
893 }
894 }
895 buffer.append(arrayEnd);
896 }
897
898 /**
899 * <p>Append to the <code>toString</code> the detail of an array type.</p>
900 *
901 * @param buffer the <code>StringBuffer</code> to populate
902 * @param fieldName the field name, typically not used as already appended
903 * @param array the array to add to the <code>toString</code>,
904 * not <code>null</code>
905 * @since 2.0
906 */
907 protected void reflectionAppendArrayDetail(StringBuffer buffer, String fieldName, Object array) {
908 buffer.append(arrayStart);
909 int length = Array.getLength(array);
910 for (int i = 0; i < length; i++) {
911 Object item = Array.get(array, i);
912 if (i > 0) {
913 buffer.append(arraySeparator);
914 }
915 if (item == null) {
916 appendNullText(buffer, fieldName);
917
918 } else {
919 appendInternal(buffer, fieldName, item, arrayContentDetail);
920 }
921 }
922 buffer.append(arrayEnd);
923 }
924
925 /**
926 * <p>Append to the <code>toString</code> a summary of an
927 * <code>Object</code> array.</p>
928 *
929 * @param buffer the <code>StringBuffer</code> to populate
930 * @param fieldName the field name, typically not used as already appended
931 * @param array the array to add to the <code>toString</code>,
932 * not <code>null</code>
933 */
934 protected void appendSummary(StringBuffer buffer, String fieldName, Object[] array) {
935 appendSummarySize(buffer, fieldName, array.length);
936 }
937
938 //----------------------------------------------------------------------------
939
940 /**
941 * <p>Append to the <code>toString</code> a <code>long</code>
942 * array.</p>
943 *
944 * @param buffer the <code>StringBuffer</code> to populate
945 * @param fieldName the field name
946 * @param array the array to add to the <code>toString</code>
947 * @param fullDetail <code>true</code> for detail, <code>false</code>
948 * for summary info, <code>null</code> for style decides
949 */
950 public void append(StringBuffer buffer, String fieldName, long[] array, Boolean fullDetail) {
951 appendFieldStart(buffer, fieldName);
952
953 if (array == null) {
954 appendNullText(buffer, fieldName);
955
956 } else if (isFullDetail(fullDetail)) {
957 appendDetail(buffer, fieldName, array);
958
959 } else {
960 appendSummary(buffer, fieldName, array);
961 }
962
963 appendFieldEnd(buffer, fieldName);
964 }
965
966 /**
967 * <p>Append to the <code>toString</code> the detail of a
968 * <code>long</code> array.</p>
969 *
970 * @param buffer the <code>StringBuffer</code> to populate
971 * @param fieldName the field name, typically not used as already appended
972 * @param array the array to add to the <code>toString</code>,
973 * not <code>null</code>
974 */
975 protected void appendDetail(StringBuffer buffer, String fieldName, long[] array) {
976 buffer.append(arrayStart);
977 for (int i = 0; i < array.length; i++) {
978 if (i > 0) {
979 buffer.append(arraySeparator);
980 }
981 appendDetail(buffer, fieldName, array[i]);
982 }
983 buffer.append(arrayEnd);
984 }
985
986 /**
987 * <p>Append to the <code>toString</code> a summary of a
988 * <code>long</code> array.</p>
989 *
990 * @param buffer the <code>StringBuffer</code> to populate
991 * @param fieldName the field name, typically not used as already appended
992 * @param array the array to add to the <code>toString</code>,
993 * not <code>null</code>
994 */
995 protected void appendSummary(StringBuffer buffer, String fieldName, long[] array) {
996 appendSummarySize(buffer, fieldName, array.length);
997 }
998
999 //----------------------------------------------------------------------------
1000
1001 /**
1002 * <p>Append to the <code>toString</code> an <code>int</code>
1003 * array.</p>
1004 *
1005 * @param buffer the <code>StringBuffer</code> to populate
1006 * @param fieldName the field name
1007 * @param array the array to add to the <code>toString</code>
1008 * @param fullDetail <code>true</code> for detail, <code>false</code>
1009 * for summary info, <code>null</code> for style decides
1010 */
1011 public void append(StringBuffer buffer, String fieldName, int[] array, Boolean fullDetail) {
1012 appendFieldStart(buffer, fieldName);
1013
1014 if (array == null) {
1015 appendNullText(buffer, fieldName);
1016
1017 } else if (isFullDetail(fullDetail)) {
1018 appendDetail(buffer, fieldName, array);
1019
1020 } else {
1021 appendSummary(buffer, fieldName, array);
1022 }
1023
1024 appendFieldEnd(buffer, fieldName);
1025 }
1026
1027 /**
1028 * <p>Append to the <code>toString</code> the detail of an
1029 * <code>int</code> array.</p>
1030 *
1031 * @param buffer the <code>StringBuffer</code> to populate
1032 * @param fieldName the field name, typically not used as already appended
1033 * @param array the array to add to the <code>toString</code>,
1034 * not <code>null</code>
1035 */
1036 protected void appendDetail(StringBuffer buffer, String fieldName, int[] array) {
1037 buffer.append(arrayStart);
1038 for (int i = 0; i < array.length; i++) {
1039 if (i > 0) {
1040 buffer.append(arraySeparator);
1041 }
1042 appendDetail(buffer, fieldName, array[i]);
1043 }
1044 buffer.append(arrayEnd);
1045 }
1046
1047 /**
1048 * <p>Append to the <code>toString</code> a summary of an
1049 * <code>int</code> array.</p>
1050 *
1051 * @param buffer the <code>StringBuffer</code> to populate
1052 * @param fieldName the field name, typically not used as already appended
1053 * @param array the array to add to the <code>toString</code>,
1054 * not <code>null</code>
1055 */
1056 protected void appendSummary(StringBuffer buffer, String fieldName, int[] array) {
1057 appendSummarySize(buffer, fieldName, array.length);
1058 }
1059
1060 //----------------------------------------------------------------------------
1061
1062 /**
1063 * <p>Append to the <code>toString</code> a <code>short</code>
1064 * array.</p>
1065 *
1066 * @param buffer the <code>StringBuffer</code> to populate
1067 * @param fieldName the field name
1068 * @param array the array to add to the <code>toString</code>
1069 * @param fullDetail <code>true</code> for detail, <code>false</code>
1070 * for summary info, <code>null</code> for style decides
1071 */
1072 public void append(StringBuffer buffer, String fieldName, short[] array, Boolean fullDetail) {
1073 appendFieldStart(buffer, fieldName);
1074
1075 if (array == null) {
1076 appendNullText(buffer, fieldName);
1077
1078 } else if (isFullDetail(fullDetail)) {
1079 appendDetail(buffer, fieldName, array);
1080
1081 } else {
1082 appendSummary(buffer, fieldName, array);
1083 }
1084
1085 appendFieldEnd(buffer, fieldName);
1086 }
1087
1088 /**
1089 * <p>Append to the <code>toString</code> the detail of a
1090 * <code>short</code> array.</p>
1091 *
1092 * @param buffer the <code>StringBuffer</code> to populate
1093 * @param fieldName the field name, typically not used as already appended
1094 * @param array the array to add to the <code>toString</code>,
1095 * not <code>null</code>
1096 */
1097 protected void appendDetail(StringBuffer buffer, String fieldName, short[] array) {
1098 buffer.append(arrayStart);
1099 for (int i = 0; i < array.length; i++) {
1100 if (i > 0) {
1101 buffer.append(arraySeparator);
1102 }
1103 appendDetail(buffer, fieldName, array[i]);
1104 }
1105 buffer.append(arrayEnd);
1106 }
1107
1108 /**
1109 * <p>Append to the <code>toString</code> a summary of a
1110 * <code>short</code> array.</p>
1111 *
1112 * @param buffer the <code>StringBuffer</code> to populate
1113 * @param fieldName the field name, typically not used as already appended
1114 * @param array the array to add to the <code>toString</code>,
1115 * not <code>null</code>
1116 */
1117 protected void appendSummary(StringBuffer buffer, String fieldName, short[] array) {
1118 appendSummarySize(buffer, fieldName, array.length);
1119 }
1120
1121 //----------------------------------------------------------------------------
1122
1123 /**
1124 * <p>Append to the <code>toString</code> a <code>byte</code>
1125 * array.</p>
1126 *
1127 * @param buffer the <code>StringBuffer</code> to populate
1128 * @param fieldName the field name
1129 * @param array the array to add to the <code>toString</code>
1130 * @param fullDetail <code>true</code> for detail, <code>false</code>
1131 * for summary info, <code>null</code> for style decides
1132 */
1133 public void append(StringBuffer buffer, String fieldName, byte[] array, Boolean fullDetail) {
1134 appendFieldStart(buffer, fieldName);
1135
1136 if (array == null) {
1137 appendNullText(buffer, fieldName);
1138
1139 } else if (isFullDetail(fullDetail)) {
1140 appendDetail(buffer, fieldName, array);
1141
1142 } else {
1143 appendSummary(buffer, fieldName, array);
1144 }
1145
1146 appendFieldEnd(buffer, fieldName);
1147 }
1148
1149 /**
1150 * <p>Append to the <code>toString</code> the detail of a
1151 * <code>byte</code> array.</p>
1152 *
1153 * @param buffer the <code>StringBuffer</code> to populate
1154 * @param fieldName the field name, typically not used as already appended
1155 * @param array the array to add to the <code>toString</code>,
1156 * not <code>null</code>
1157 */
1158 protected void appendDetail(StringBuffer buffer, String fieldName, byte[] array) {
1159 buffer.append(arrayStart);
1160 for (int i = 0; i < array.length; i++) {
1161 if (i > 0) {
1162 buffer.append(arraySeparator);
1163 }
1164 appendDetail(buffer, fieldName, array[i]);
1165 }
1166 buffer.append(arrayEnd);
1167 }
1168
1169 /**
1170 * <p>Append to the <code>toString</code> a summary of a
1171 * <code>byte</code> array.</p>
1172 *
1173 * @param buffer the <code>StringBuffer</code> to populate
1174 * @param fieldName the field name, typically not used as already appended
1175 * @param array the array to add to the <code>toString</code>,
1176 * not <code>null</code>
1177 */
1178 protected void appendSummary(StringBuffer buffer, String fieldName, byte[] array) {
1179 appendSummarySize(buffer, fieldName, array.length);
1180 }
1181
1182 //----------------------------------------------------------------------------
1183
1184 /**
1185 * <p>Append to the <code>toString</code> a <code>char</code>
1186 * array.</p>
1187 *
1188 * @param buffer the <code>StringBuffer</code> to populate
1189 * @param fieldName the field name
1190 * @param array the array to add to the <code>toString</code>
1191 * @param fullDetail <code>true</code> for detail, <code>false</code>
1192 * for summary info, <code>null</code> for style decides
1193 */
1194 public void append(StringBuffer buffer, String fieldName, char[] array, Boolean fullDetail) {
1195 appendFieldStart(buffer, fieldName);
1196
1197 if (array == null) {
1198 appendNullText(buffer, fieldName);
1199
1200 } else if (isFullDetail(fullDetail)) {
1201 appendDetail(buffer, fieldName, array);
1202
1203 } else {
1204 appendSummary(buffer, fieldName, array);
1205 }
1206
1207 appendFieldEnd(buffer, fieldName);
1208 }
1209
1210 /**
1211 * <p>Append to the <code>toString</code> the detail of a
1212 * <code>char</code> array.</p>
1213 *
1214 * @param buffer the <code>StringBuffer</code> to populate
1215 * @param fieldName the field name, typically not used as already appended
1216 * @param array the array to add to the <code>toString</code>,
1217 * not <code>null</code>
1218 */
1219 protected void appendDetail(StringBuffer buffer, String fieldName, char[] array) {
1220 buffer.append(arrayStart);
1221 for (int i = 0; i < array.length; i++) {
1222 if (i > 0) {
1223 buffer.append(arraySeparator);
1224 }
1225 appendDetail(buffer, fieldName, array[i]);
1226 }
1227 buffer.append(arrayEnd);
1228 }
1229
1230 /**
1231 * <p>Append to the <code>toString</code> a summary of a
1232 * <code>char</code> array.</p>
1233 *
1234 * @param buffer the <code>StringBuffer</code> to populate
1235 * @param fieldName the field name, typically not used as already appended
1236 * @param array the array to add to the <code>toString</code>,
1237 * not <code>null</code>
1238 */
1239 protected void appendSummary(StringBuffer buffer, String fieldName, char[] array) {
1240 appendSummarySize(buffer, fieldName, array.length);
1241 }
1242
1243 //----------------------------------------------------------------------------
1244
1245 /**
1246 * <p>Append to the <code>toString</code> a <code>double</code>
1247 * array.</p>
1248 *
1249 * @param buffer the <code>StringBuffer</code> to populate
1250 * @param fieldName the field name
1251 * @param array the array to add to the toString
1252 * @param fullDetail <code>true</code> for detail, <code>false</code>
1253 * for summary info, <code>null</code> for style decides
1254 */
1255 public void append(StringBuffer buffer, String fieldName, double[] array, Boolean fullDetail) {
1256 appendFieldStart(buffer, fieldName);
1257
1258 if (array == null) {
1259 appendNullText(buffer, fieldName);
1260
1261 } else if (isFullD