View Javadoc
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   * </p>
52   * <pre>
53   * public class MyStyle extends ToStringStyle {
54   *   protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
55   *     if (value instanceof Date) {
56   *       value = new SimpleDateFormat("yyyy-MM-dd").format(value);
57   *     }
58   *     buffer.append(value);
59   *   }
60   * }
61   * </pre>
62   *
63   * @since 1.0
64   * @version $Id: ToStringStyle.java 1583482 2014-03-31 22:54:57Z niallp $
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 <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>'&lt;null&gt;'</code>.
297      */
298     private String nullText = "<null>";
299 
300     /**
301      * The summary size text start <code>'&lt;size'</code>.
302      */
303     private String sizeStartText = "<size=";
304 
305     /**
306      * The summary size text start <code>'&gt;'</code>.
307      */
308     private String sizeEndText = ">";
309 
310     /**
311      * The summary object text start <code>'&lt;'</code>.
312      */
313     private String summaryObjectStartText = "<";
314 
315     /**
316      * The summary object text start <code>'&gt;'</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>'&lt;null&gt;'</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>'&lt;size=n&gt;'</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 
2211     /**
2212      * <p><code>ToStringStyle</code> that does not print out the
2213      * classname, identity hashcode, content start or field name.</p>
2214      *
2215      * <p>This is an inner class rather than using
2216      * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2217      */
2218     private static final class SimpleToStringStyle extends ToStringStyle {
2219 
2220         private static final long serialVersionUID = 1L;
2221 
2222         /**
2223          * <p>Constructor.</p>
2224          *
2225          * <p>Use the static constant rather than instantiating.</p>
2226          */
2227         SimpleToStringStyle() {
2228             super();
2229             this.setUseClassName(false);
2230             this.setUseIdentityHashCode(false);
2231             this.setUseFieldNames(false);
2232             this.setContentStart("");
2233             this.setContentEnd("");
2234         }
2235 
2236         /**
2237          * <p>Ensure <code>Singleton</ode> after serialization.</p>
2238          * @return the singleton
2239          */
2240         private Object readResolve() {
2241             return ToStringStyle.SIMPLE_STYLE;
2242         }
2243 
2244     }
2245 
2246     //----------------------------------------------------------------------------
2247 
2248     /**
2249      * <p><code>ToStringStyle</code> that outputs on multiple lines.</p>
2250      *
2251      * <p>This is an inner class rather than using
2252      * <code>StandardToStringStyle</code> to ensure its immutability.</p>
2253      */
2254     private static final class MultiLineToStringStyle extends ToStringStyle {
2255 
2256         private static final long serialVersionUID = 1L;
2257 
2258         /**
2259          * <p>Constructor.</p>
2260          *
2261          * <p>Use the static constant rather than instantiating.</p>
2262          */
2263         MultiLineToStringStyle() {
2264             super();
2265             this.setContentStart("[");
2266             this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + "  ");
2267             this.setFieldSeparatorAtStart(true);
2268             this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]");
2269         }
2270 
2271         /**
2272          * <p>Ensure <code>Singleton</code> after serialization.</p>
2273          *
2274          * @return the singleton
2275          */
2276         private Object readResolve() {
2277             return ToStringStyle.MULTI_LINE_STYLE;
2278         }
2279 
2280     }
2281 
2282 }