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