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