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