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