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