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