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