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