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