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