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