stc.app.bean.lang.ToStringStyle.java Source code

Java tutorial

Introduction

Here is the source code for stc.app.bean.lang.ToStringStyle.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package stc.app.bean.lang;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;
import java.util.WeakHashMap;

import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.SystemUtils;

/**
 * <p>
 * Controls <code>String</code> formatting for {@link ToStringBuilder}. The main public interface is
 * always via <code>ToStringBuilder</code>.
 * </p>
 * 
 * <p>
 * These classes are intended to be used as <code>Singletons</code>. There is no need to instantiate
 * a new style each time. A program will generally use one of the predefined constants on this
 * class. Alternatively, the {@link StandardToStringStyle} class can be used to set the individual
 * settings. Thus most styles can be achieved without subclassing.
 * </p>
 * 
 * <p>
 * If required, a subclass can override as many or as few of the methods as it requires. Each object
 * type (from <code>boolean</code> to <code>long</code> to <code>Object</code> to <code>int[]</code>
 * ) has its own methods to output it. Most have two versions, detail and summary.
 * 
 * <p>
 * For example, the detail version of the array based methods will output the whole array, whereas
 * the summary method will just output the array length.
 * </p>
 * 
 * <p>
 * If you want to format the output of certain objects, such as dates, you must create a subclass
 * and override a method.
 * 
 * <pre>
 * public class MyStyle extends ToStringStyle {
 *   protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
 *     if (value instanceof Date) {
 *       value = new SimpleDateFormat(&quot;yyyy-MM-dd&quot;).format(value);
 *     }
 *     buffer.append(value);
 *   }
 * }
 * </pre>
 * 
 * </p>
 * 
 * @author Apache Software Foundation
 * @author Gary Gregory
 * @author Pete Gieser
 * @author Masato Tezuka
 * @since 1.0
 * @version $Id: ToStringStyle.java 907168 2010-02-06 03:33:50Z mbenson $
 */
public abstract class ToStringStyle implements Serializable {

    /**
     * The default toString style. Using the Using the <code>Person</code> example from
     * {@link ToStringBuilder}, the output would look like this:
     * 
     * <pre>
     * Person@182f0db[name=John Doe,age=33,smoker=false]
     * </pre>
     */
    public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle();

    /**
     * The multi line toString style. Using the Using the <code>Person</code> example from
     * {@link ToStringBuilder}, the output would look like this:
     * 
     * <pre>
     * Person@182f0db[
     *   name=John Doe
     *   age=33
     *   smoker=false
     * ]
     * </pre>
     */
    public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle();

    /**
     * The no field names toString style. Using the Using the <code>Person</code> example from
     * {@link ToStringBuilder}, the output would look like this:
     * 
     * <pre>
     * Person@182f0db[John Doe,33,false]
     * </pre>
     */
    public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle();

    /**
     * The short prefix toString style. Using the <code>Person</code> example from
     * {@link ToStringBuilder}, the output would look like this:
     * 
     * <pre>
     * Person[name=John Doe,age=33,smoker=false]
     * </pre>
     * 
     * @since 2.1
     */
    public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle();

    /**
     * The simple toString style. Using the Using the <code>Person</code> example from
     * {@link ToStringBuilder}, the output would look like this:
     * 
     * <pre>
     * John Doe,33,false
     * </pre>
     */
    public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle();

    /**
     * <p>
     * A registry of objects used by <code>reflectionToString</code> methods to detect cyclical object
     * references and avoid infinite loops.
     * </p>
     */
    private static final ThreadLocal REGISTRY = new ThreadLocal();

    /**
     * <p>
     * Returns the registry of objects being traversed by the <code>reflectionToString</code> methods
     * in the current thread.
     * </p>
     * 
     * @return Set the registry of objects being traversed
     */
    static Map getRegistry() {
        return (Map) REGISTRY.get();
    }

    /**
     * <p>
     * Returns <code>true</code> if the registry contains the given object. Used by the reflection
     * methods to avoid infinite loops.
     * </p>
     * 
     * @param value The object to lookup in the registry.
     * @return boolean <code>true</code> if the registry contains the given object.
     */
    static boolean isRegistered(Object value) {
        Map m = getRegistry();
        return m != null && m.containsKey(value);
    }

    /**
     * <p>
     * Registers the given object. Used by the reflection methods to avoid infinite loops.
     * </p>
     * 
     * @param value The object to register.
     */
    static void register(Object value) {
        if (value != null) {
            Map m = getRegistry();
            if (m == null) {
                m = new WeakHashMap();
                REGISTRY.set(m);
            }
            m.put(value, null);
        }
    }

    /**
     * <p>
     * Unregisters the given object.
     * </p>
     * 
     * <p>
     * Used by the reflection methods to avoid infinite loops.
     * </p>
     * 
     * @param value The object to unregister.
     */
    static void unregister(Object value) {
        if (value != null) {
            Map m = getRegistry();
            if (m != null) {
                m.remove(value);
                if (m.isEmpty()) {
                    REGISTRY.set(null);
                }
            }
        }
    }

    /**
     * Whether to use the field names, the default is <code>true</code>.
     */
    private boolean useFieldNames = true;

    /**
     * Whether to use the class name, the default is <code>true</code>.
     */
    private boolean useClassName = true;

    /**
     * Whether to use short class names, the default is <code>false</code>.
     */
    private boolean useShortClassName = false;

    /**
     * Whether to use the identity hash code, the default is <code>true</code>.
     */
    private boolean useIdentityHashCode = true;

    /**
     * The content start <code>'['</code>.
     */
    private String contentStart = "[";

    /**
     * The content end <code>']'</code>.
     */
    private String contentEnd = "]";

    /**
     * The field name value separator <code>'='</code>.
     */
    private String fieldNameValueSeparator = "=";

    /**
     * Whether the field separator should be added before any other fields.
     */
    private boolean fieldSeparatorAtStart = false;

    /**
     * Whether the field separator should be added after any other fields.
     */
    private boolean fieldSeparatorAtEnd = false;

    /**
     * The field separator <code>','</code>.
     */
    private String fieldSeparator = ",";

    /**
     * The array start <code>'{'</code>.
     */
    private String arrayStart = "{";

    /**
     * The array separator <code>','</code>.
     */
    private String arraySeparator = ",";

    /**
     * The detail for array content.
     */
    private boolean arrayContentDetail = true;

    /**
     * The array end <code>'}'</code>.
     */
    private String arrayEnd = "}";

    /**
     * The value to use when fullDetail is <code>null</code>, the default value is <code>true</code>.
     */
    private boolean defaultFullDetail = true;

    /**
     * The <code>null</code> text <code>'&lt;null&gt;'</code>.
     */
    private String nullText = "<null>";

    /**
     * The summary size text start <code>'<size'</code>.
     */
    private String sizeStartText = "<size=";

    /**
     * The summary size text start <code>'&gt;'</code>.
     */
    private String sizeEndText = ">";

    /**
     * The summary object text start <code>'&lt;'</code>.
     */
    private String summaryObjectStartText = "<";

    /**
     * The summary object text start <code>'&gt;'</code>.
     */
    private String summaryObjectEndText = ">";

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Constructor.
     * </p>
     */
    protected ToStringStyle() {
        super();
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> the superclass toString.
     * </p>
     * <p>
     * NOTE: It assumes that the toString has been created from the same ToStringStyle.
     * </p>
     * 
     * <p>
     * A <code>null</code> <code>superToString</code> is ignored.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param superToString the <code>super.toString()</code>
     * @since 2.0
     */
    public void appendSuper(StringBuffer buffer, String superToString) {
        appendToString(buffer, superToString);
    }

    /**
     * <p>
     * Append to the <code>toString</code> another toString.
     * </p>
     * <p>
     * NOTE: It assumes that the toString has been created from the same ToStringStyle.
     * </p>
     * 
     * <p>
     * A <code>null</code> <code>toString</code> is ignored.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param toString the additional <code>toString</code>
     * @since 2.0
     */
    public void appendToString(StringBuffer buffer, String toString) {
        if (toString != null) {
            int pos1 = toString.indexOf(contentStart) + contentStart.length();
            int pos2 = toString.lastIndexOf(contentEnd);
            if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) {
                String data = toString.substring(pos1, pos2);
                if (fieldSeparatorAtStart) {
                    removeLastFieldSeparator(buffer);
                }
                buffer.append(data);
                appendFieldSeparator(buffer);
            }
        }
    }

    /**
     * <p>
     * Append to the <code>toString</code> the start of data indicator.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param object the <code>Object</code> to build a <code>toString</code> for
     */
    public void appendStart(StringBuffer buffer, Object object) {
        if (object != null) {
            appendClassName(buffer, object);
            appendIdentityHashCode(buffer, object);
            appendContentStart(buffer);
            if (fieldSeparatorAtStart) {
                appendFieldSeparator(buffer);
            }
        }
    }

    /**
     * <p>
     * Append to the <code>toString</code> the end of data indicator.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param object the <code>Object</code> to build a <code>toString</code> for.
     */
    public void appendEnd(StringBuffer buffer, Object object) {
        if (this.fieldSeparatorAtEnd == false) {
            removeLastFieldSeparator(buffer);
        }
        appendContentEnd(buffer);
        unregister(object);
    }

    /**
     * <p>
     * Remove the last field separator from the buffer.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @since 2.0
     */
    protected void removeLastFieldSeparator(StringBuffer buffer) {
        int len = buffer.length();
        int sepLen = fieldSeparator.length();
        if (len > 0 && sepLen > 0 && len >= sepLen) {
            boolean match = true;
            for (int i = 0; i < sepLen; i++) {
                if (buffer.charAt(len - 1 - i) != fieldSeparator.charAt(sepLen - 1 - i)) {
                    match = false;
                    break;
                }
            }
            if (match) {
                buffer.setLength(len - sepLen);
            }
        }
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> an <code>Object</code> value, printing the full
     * <code>toString</code> of the <code>Object</code> passed in.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param value the value to add to the <code>toString</code>
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (value == null) {
            appendNullText(buffer, fieldName);

        } else {
            appendInternal(buffer, fieldName, value, isFullDetail(fullDetail));
        }

        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> an <code>Object</code>, correctly interpreting its type.
     * </p>
     * 
     * <p>
     * This method performs the main lookup by Class type to correctly route arrays,
     * <code>Collections</code>, <code>Maps</code> and <code>Objects</code> to the appropriate method.
     * </p>
     * 
     * <p>
     * Either detail or summary views can be specified.
     * </p>
     * 
     * <p>
     * If a cycle is detected, an object will be appended with the <code>Object.toString()</code>
     * format.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>, not <code>null</code>
     * @param detail output detail or not
     */
    protected void appendInternal(StringBuffer buffer, String fieldName, Object value, boolean detail) {
        if (isRegistered(value)
                && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) {
            appendCyclicObject(buffer, fieldName, value);
            return;
        }

        register(value);

        try {
            if (value instanceof Collection) {
                if (detail) {
                    appendDetail(buffer, fieldName, (Collection) value);
                } else {
                    appendSummarySize(buffer, fieldName, ((Collection) value).size());
                }

            } else if (value instanceof Map) {
                if (detail) {
                    appendDetail(buffer, fieldName, (Map) value);
                } else {
                    appendSummarySize(buffer, fieldName, ((Map) value).size());
                }

            } else if (value instanceof long[]) {
                if (detail) {
                    appendDetail(buffer, fieldName, (long[]) value);
                } else {
                    appendSummary(buffer, fieldName, (long[]) value);
                }

            } else if (value instanceof int[]) {
                if (detail) {
                    appendDetail(buffer, fieldName, (int[]) value);
                } else {
                    appendSummary(buffer, fieldName, (int[]) value);
                }

            } else if (value instanceof short[]) {
                if (detail) {
                    appendDetail(buffer, fieldName, (short[]) value);
                } else {
                    appendSummary(buffer, fieldName, (short[]) value);
                }

            } else if (value instanceof byte[]) {
                if (detail) {
                    appendDetail(buffer, fieldName, (byte[]) value);
                } else {
                    appendSummary(buffer, fieldName, (byte[]) value);
                }

            } else if (value instanceof char[]) {
                if (detail) {
                    appendDetail(buffer, fieldName, (char[]) value);
                } else {
                    appendSummary(buffer, fieldName, (char[]) value);
                }

            } else if (value instanceof double[]) {
                if (detail) {
                    appendDetail(buffer, fieldName, (double[]) value);
                } else {
                    appendSummary(buffer, fieldName, (double[]) value);
                }

            } else if (value instanceof float[]) {
                if (detail) {
                    appendDetail(buffer, fieldName, (float[]) value);
                } else {
                    appendSummary(buffer, fieldName, (float[]) value);
                }

            } else if (value instanceof boolean[]) {
                if (detail) {
                    appendDetail(buffer, fieldName, (boolean[]) value);
                } else {
                    appendSummary(buffer, fieldName, (boolean[]) value);
                }

            } else if (value.getClass().isArray()) {
                if (detail) {
                    appendDetail(buffer, fieldName, (Object[]) value);
                } else {
                    appendSummary(buffer, fieldName, (Object[]) value);
                }

            } else {
                if (detail) {
                    appendDetail(buffer, fieldName, value);
                } else {
                    appendSummary(buffer, fieldName, value);
                }
            }
        } finally {
            unregister(value);
        }
    }

    /**
     * <p>
     * Append to the <code>toString</code> an <code>Object</code> value that has been detected to
     * participate in a cycle. This implementation will print the standard string value of the value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>, not <code>null</code>
     * 
     * @since 2.2
     */
    protected void appendCyclicObject(StringBuffer buffer, String fieldName, Object value) {
        ObjectUtils.identityToString(buffer, value);
    }

    /**
     * <p>
     * Append to the <code>toString</code> an <code>Object</code> value, printing the full detail of
     * the <code>Object</code>.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
        buffer.append(value);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a <code>Collection</code>.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param coll the <code>Collection</code> to add to the <code>toString</code>, not
     *        <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, Collection coll) {
        buffer.append(coll);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a <code>Map<code>.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param map the <code>Map</code> to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, Map map) {
        buffer.append(map);
    }

    /**
     * <p>
     * Append to the <code>toString</code> an <code>Object</code> value, printing a summary of the
     * <code>Object</code>.
     * </P>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, Object value) {
        buffer.append(summaryObjectStartText);
        buffer.append(getShortClassName(value.getClass()));
        buffer.append(summaryObjectEndText);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>long</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param value the value to add to the <code>toString</code>
     */
    public void append(StringBuffer buffer, String fieldName, long value) {
        appendFieldStart(buffer, fieldName);
        appendDetail(buffer, fieldName, value);
        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a <code>long</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, long value) {
        buffer.append(value);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> an <code>int</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param value the value to add to the <code>toString</code>
     */
    public void append(StringBuffer buffer, String fieldName, int value) {
        appendFieldStart(buffer, fieldName);
        appendDetail(buffer, fieldName, value);
        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> an <code>int</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, int value) {
        buffer.append(value);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>short</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param value the value to add to the <code>toString</code>
     */
    public void append(StringBuffer buffer, String fieldName, short value) {
        appendFieldStart(buffer, fieldName);
        appendDetail(buffer, fieldName, value);
        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a <code>short</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, short value) {
        buffer.append(value);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>byte</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param value the value to add to the <code>toString</code>
     */
    public void append(StringBuffer buffer, String fieldName, byte value) {
        appendFieldStart(buffer, fieldName);
        appendDetail(buffer, fieldName, value);
        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a <code>byte</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, byte value) {
        buffer.append(value);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>char</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param value the value to add to the <code>toString</code>
     */
    public void append(StringBuffer buffer, String fieldName, char value) {
        appendFieldStart(buffer, fieldName);
        appendDetail(buffer, fieldName, value);
        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a <code>char</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, char value) {
        buffer.append(value);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>double</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param value the value to add to the <code>toString</code>
     */
    public void append(StringBuffer buffer, String fieldName, double value) {
        appendFieldStart(buffer, fieldName);
        appendDetail(buffer, fieldName, value);
        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a <code>double</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, double value) {
        buffer.append(value);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>float</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param value the value to add to the <code>toString</code>
     */
    public void append(StringBuffer buffer, String fieldName, float value) {
        appendFieldStart(buffer, fieldName);
        appendDetail(buffer, fieldName, value);
        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a <code>float</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, float value) {
        buffer.append(value);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>boolean</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param value the value to add to the <code>toString</code>
     */
    public void append(StringBuffer buffer, String fieldName, boolean value) {
        appendFieldStart(buffer, fieldName);
        appendDetail(buffer, fieldName, value);
        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a <code>boolean</code> value.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param value the value to add to the <code>toString</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, boolean value) {
        buffer.append(value);
    }

    /**
     * <p>
     * Append to the <code>toString</code> an <code>Object</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param array the array to add to the toString
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, Object[] array, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (array == null) {
            appendNullText(buffer, fieldName);

        } else if (isFullDetail(fullDetail)) {
            appendDetail(buffer, fieldName, array);

        } else {
            appendSummary(buffer, fieldName, array);
        }

        appendFieldEnd(buffer, fieldName);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> the detail of an <code>Object</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, Object[] array) {
        buffer.append(arrayStart);
        for (int i = 0; i < array.length; i++) {
            Object item = array[i];
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            if (item == null) {
                appendNullText(buffer, fieldName);

            } else {
                appendInternal(buffer, fieldName, item, arrayContentDetail);
            }
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the detail of an array type.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     * @since 2.0
     */
    protected void reflectionAppendArrayDetail(StringBuffer buffer, String fieldName, Object array) {
        buffer.append(arrayStart);
        int length = Array.getLength(array);
        for (int i = 0; i < length; i++) {
            Object item = Array.get(array, i);
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            if (item == null) {
                appendNullText(buffer, fieldName);

            } else {
                appendInternal(buffer, fieldName, item, arrayContentDetail);
            }
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a summary of an <code>Object</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, Object[] array) {
        appendSummarySize(buffer, fieldName, array.length);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>long</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param array the array to add to the <code>toString</code>
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, long[] array, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (array == null) {
            appendNullText(buffer, fieldName);

        } else if (isFullDetail(fullDetail)) {
            appendDetail(buffer, fieldName, array);

        } else {
            appendSummary(buffer, fieldName, array);
        }

        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the detail of a <code>long</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, long[] array) {
        buffer.append(arrayStart);
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            appendDetail(buffer, fieldName, array[i]);
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a summary of a <code>long</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, long[] array) {
        appendSummarySize(buffer, fieldName, array.length);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> an <code>int</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param array the array to add to the <code>toString</code>
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, int[] array, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (array == null) {
            appendNullText(buffer, fieldName);

        } else if (isFullDetail(fullDetail)) {
            appendDetail(buffer, fieldName, array);

        } else {
            appendSummary(buffer, fieldName, array);
        }

        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the detail of an <code>int</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, int[] array) {
        buffer.append(arrayStart);
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            appendDetail(buffer, fieldName, array[i]);
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a summary of an <code>int</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, int[] array) {
        appendSummarySize(buffer, fieldName, array.length);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>short</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param array the array to add to the <code>toString</code>
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, short[] array, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (array == null) {
            appendNullText(buffer, fieldName);

        } else if (isFullDetail(fullDetail)) {
            appendDetail(buffer, fieldName, array);

        } else {
            appendSummary(buffer, fieldName, array);
        }

        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the detail of a <code>short</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, short[] array) {
        buffer.append(arrayStart);
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            appendDetail(buffer, fieldName, array[i]);
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a summary of a <code>short</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, short[] array) {
        appendSummarySize(buffer, fieldName, array.length);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>byte</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param array the array to add to the <code>toString</code>
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, byte[] array, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (array == null) {
            appendNullText(buffer, fieldName);

        } else if (isFullDetail(fullDetail)) {
            appendDetail(buffer, fieldName, array);

        } else {
            appendSummary(buffer, fieldName, array);
        }

        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the detail of a <code>byte</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, byte[] array) {
        buffer.append(arrayStart);
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            appendDetail(buffer, fieldName, array[i]);
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a summary of a <code>byte</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, byte[] array) {
        appendSummarySize(buffer, fieldName, array.length);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>char</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param array the array to add to the <code>toString</code>
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, char[] array, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (array == null) {
            appendNullText(buffer, fieldName);

        } else if (isFullDetail(fullDetail)) {
            appendDetail(buffer, fieldName, array);

        } else {
            appendSummary(buffer, fieldName, array);
        }

        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the detail of a <code>char</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, char[] array) {
        buffer.append(arrayStart);
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            appendDetail(buffer, fieldName, array[i]);
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a summary of a <code>char</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, char[] array) {
        appendSummarySize(buffer, fieldName, array.length);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>double</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param array the array to add to the toString
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, double[] array, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (array == null) {
            appendNullText(buffer, fieldName);

        } else if (isFullDetail(fullDetail)) {
            appendDetail(buffer, fieldName, array);

        } else {
            appendSummary(buffer, fieldName, array);
        }

        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the detail of a <code>double</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, double[] array) {
        buffer.append(arrayStart);
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            appendDetail(buffer, fieldName, array[i]);
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a summary of a <code>double</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, double[] array) {
        appendSummarySize(buffer, fieldName, array.length);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>float</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param array the array to add to the toString
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, float[] array, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (array == null) {
            appendNullText(buffer, fieldName);

        } else if (isFullDetail(fullDetail)) {
            appendDetail(buffer, fieldName, array);

        } else {
            appendSummary(buffer, fieldName, array);
        }

        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the detail of a <code>float</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, float[] array) {
        buffer.append(arrayStart);
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            appendDetail(buffer, fieldName, array[i]);
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a summary of a <code>float</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, float[] array) {
        appendSummarySize(buffer, fieldName, array.length);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> a <code>boolean</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     * @param array the array to add to the toString
     * @param fullDetail <code>true</code> for detail, <code>false</code> for summary info,
     *        <code>null</code> for style decides
     */
    public void append(StringBuffer buffer, String fieldName, boolean[] array, Boolean fullDetail) {
        appendFieldStart(buffer, fieldName);

        if (array == null) {
            appendNullText(buffer, fieldName);

        } else if (isFullDetail(fullDetail)) {
            appendDetail(buffer, fieldName, array);

        } else {
            appendSummary(buffer, fieldName, array);
        }

        appendFieldEnd(buffer, fieldName);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the detail of a <code>boolean</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendDetail(StringBuffer buffer, String fieldName, boolean[] array) {
        buffer.append(arrayStart);
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                buffer.append(arraySeparator);
            }
            appendDetail(buffer, fieldName, array[i]);
        }
        buffer.append(arrayEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a summary of a <code>boolean</code> array.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param array the array to add to the <code>toString</code>, not <code>null</code>
     */
    protected void appendSummary(StringBuffer buffer, String fieldName, boolean[] array) {
        appendSummarySize(buffer, fieldName, array.length);
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Append to the <code>toString</code> the class name.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param object the <code>Object</code> whose name to output
     */
    protected void appendClassName(StringBuffer buffer, Object object) {
        if (useClassName && object != null) {
            register(object);
            if (useShortClassName) {
                buffer.append(getShortClassName(object.getClass()));
            } else {
                buffer.append(object.getClass().getName());
            }
        }
    }

    /**
     * <p>
     * Append the {@link System#identityHashCode(java.lang.Object)}.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param object the <code>Object</code> whose id to output
     */
    protected void appendIdentityHashCode(StringBuffer buffer, Object object) {
        if (this.isUseIdentityHashCode() && object != null) {
            register(object);
            buffer.append('@');
            buffer.append(Integer.toHexString(System.identityHashCode(object)));
        }
    }

    /**
     * <p>
     * Append to the <code>toString</code> the content start.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     */
    protected void appendContentStart(StringBuffer buffer) {
        buffer.append(contentStart);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the content end.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     */
    protected void appendContentEnd(StringBuffer buffer) {
        buffer.append(contentEnd);
    }

    /**
     * <p>
     * Append to the <code>toString</code> an indicator for <code>null</code>.
     * </p>
     * 
     * <p>
     * The default indicator is <code>'&lt;null&gt;'</code>.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     */
    protected void appendNullText(StringBuffer buffer, String fieldName) {
        buffer.append(nullText);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the field separator.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     */
    protected void appendFieldSeparator(StringBuffer buffer) {
        buffer.append(fieldSeparator);
    }

    /**
     * <p>
     * Append to the <code>toString</code> the field start.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name
     */
    protected void appendFieldStart(StringBuffer buffer, String fieldName) {
        if (useFieldNames && fieldName != null) {
            buffer.append(fieldName);
            buffer.append(fieldNameValueSeparator);
        }
    }

    /**
     * <p>
     * Append to the <code>toString<code> the field end.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     */
    protected void appendFieldEnd(StringBuffer buffer, String fieldName) {
        appendFieldSeparator(buffer);
    }

    /**
     * <p>
     * Append to the <code>toString</code> a size summary.
     * </p>
     * 
     * <p>
     * The size summary is used to summarize the contents of <code>Collections</code>,
     * <code>Maps</code> and arrays.
     * </p>
     * 
     * <p>
     * The output consists of a prefix, the passed in size and a suffix.
     * </p>
     * 
     * <p>
     * The default format is <code>'&lt;size=n&gt;'<code>.
     * </p>
     * 
     * @param buffer the <code>StringBuffer</code> to populate
     * @param fieldName the field name, typically not used as already appended
     * @param size the size to append
     */
    protected void appendSummarySize(StringBuffer buffer, String fieldName, int size) {
        buffer.append(sizeStartText);
        buffer.append(size);
        buffer.append(sizeEndText);
    }

    /**
     * <p>
     * Is this field to be output in full detail.
     * </p>
     * 
     * <p>
     * This method converts a detail request into a detail level. The calling code may request full
     * detail (<code>true</code>), but a subclass might ignore that and always return
     * <code>false</code>. The calling code may pass in <code>null</code> indicating that it doesn't
     * care about the detail level. In this case the default detail level is used.
     * </p>
     * 
     * @param fullDetailRequest the detail level requested
     * @return whether full detail is to be shown
     */
    protected boolean isFullDetail(Boolean fullDetailRequest) {
        if (fullDetailRequest == null) {
            return defaultFullDetail;
        }
        return fullDetailRequest.booleanValue();
    }

    /**
     * <p>
     * Gets the short class name for a class.
     * </p>
     * 
     * <p>
     * The short class name is the classname excluding the package name.
     * </p>
     * 
     * @param cls the <code>Class</code> to get the short name of
     * @return the short name
     */
    protected String getShortClassName(Class cls) {
        return ClassUtils.getShortClassName(cls);
    }

    // Setters and getters for the customizable parts of the style
    // These methods are not expected to be overridden, except to make public
    // (They are not public so that immutable subclasses can be written)
    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets whether to use the class name.
     * </p>
     * 
     * @return the current useClassName flag
     */
    protected boolean isUseClassName() {
        return useClassName;
    }

    /**
     * <p>
     * Sets whether to use the class name.
     * </p>
     * 
     * @param useClassName the new useClassName flag
     */
    protected void setUseClassName(boolean useClassName) {
        this.useClassName = useClassName;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets whether to output short or long class names.
     * </p>
     * 
     * @return the current useShortClassName flag
     * @since 2.0
     */
    protected boolean isUseShortClassName() {
        return useShortClassName;
    }

    /**
     * <p>
     * Gets whether to output short or long class names.
     * </p>
     * 
     * @return the current shortClassName flag
     * @deprecated Use {@link #isUseShortClassName()} Method will be removed in Commons Lang 3.0.
     */
    protected boolean isShortClassName() {
        return useShortClassName;
    }

    /**
     * <p>
     * Sets whether to output short or long class names.
     * </p>
     * 
     * @param useShortClassName the new useShortClassName flag
     * @since 2.0
     */
    protected void setUseShortClassName(boolean useShortClassName) {
        this.useShortClassName = useShortClassName;
    }

    /**
     * <p>
     * Sets whether to output short or long class names.
     * </p>
     * 
     * @param shortClassName the new shortClassName flag
     * @deprecated Use {@link #setUseShortClassName(boolean)} Method will be removed in Commons Lang
     *             3.0.
     */
    protected void setShortClassName(boolean shortClassName) {
        this.useShortClassName = shortClassName;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets whether to use the identity hash code.
     * </p>
     * 
     * @return the current useIdentityHashCode flag
     */
    protected boolean isUseIdentityHashCode() {
        return useIdentityHashCode;
    }

    /**
     * <p>
     * Sets whether to use the identity hash code.
     * </p>
     * 
     * @param useIdentityHashCode the new useIdentityHashCode flag
     */
    protected void setUseIdentityHashCode(boolean useIdentityHashCode) {
        this.useIdentityHashCode = useIdentityHashCode;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets whether to use the field names passed in.
     * </p>
     * 
     * @return the current useFieldNames flag
     */
    protected boolean isUseFieldNames() {
        return useFieldNames;
    }

    /**
     * <p>
     * Sets whether to use the field names passed in.
     * </p>
     * 
     * @param useFieldNames the new useFieldNames flag
     */
    protected void setUseFieldNames(boolean useFieldNames) {
        this.useFieldNames = useFieldNames;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets whether to use full detail when the caller doesn't specify.
     * </p>
     * 
     * @return the current defaultFullDetail flag
     */
    protected boolean isDefaultFullDetail() {
        return defaultFullDetail;
    }

    /**
     * <p>
     * Sets whether to use full detail when the caller doesn't specify.
     * </p>
     * 
     * @param defaultFullDetail the new defaultFullDetail flag
     */
    protected void setDefaultFullDetail(boolean defaultFullDetail) {
        this.defaultFullDetail = defaultFullDetail;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets whether to output array content detail.
     * </p>
     * 
     * @return the current array content detail setting
     */
    protected boolean isArrayContentDetail() {
        return arrayContentDetail;
    }

    /**
     * <p>
     * Sets whether to output array content detail.
     * </p>
     * 
     * @param arrayContentDetail the new arrayContentDetail flag
     */
    protected void setArrayContentDetail(boolean arrayContentDetail) {
        this.arrayContentDetail = arrayContentDetail;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the array start text.
     * </p>
     * 
     * @return the current array start text
     */
    protected String getArrayStart() {
        return arrayStart;
    }

    /**
     * <p>
     * Sets the array start text.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param arrayStart the new array start text
     */
    protected void setArrayStart(String arrayStart) {
        if (arrayStart == null) {
            arrayStart = "";
        }
        this.arrayStart = arrayStart;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the array end text.
     * </p>
     * 
     * @return the current array end text
     */
    protected String getArrayEnd() {
        return arrayEnd;
    }

    /**
     * <p>
     * Sets the array end text.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param arrayEnd the new array end text
     */
    protected void setArrayEnd(String arrayEnd) {
        if (arrayEnd == null) {
            arrayEnd = "";
        }
        this.arrayEnd = arrayEnd;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the array separator text.
     * </p>
     * 
     * @return the current array separator text
     */
    protected String getArraySeparator() {
        return arraySeparator;
    }

    /**
     * <p>
     * Sets the array separator text.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param arraySeparator the new array separator text
     */
    protected void setArraySeparator(String arraySeparator) {
        if (arraySeparator == null) {
            arraySeparator = "";
        }
        this.arraySeparator = arraySeparator;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the content start text.
     * </p>
     * 
     * @return the current content start text
     */
    protected String getContentStart() {
        return contentStart;
    }

    /**
     * <p>
     * Sets the content start text.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param contentStart the new content start text
     */
    protected void setContentStart(String contentStart) {
        if (contentStart == null) {
            contentStart = "";
        }
        this.contentStart = contentStart;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the content end text.
     * </p>
     * 
     * @return the current content end text
     */
    protected String getContentEnd() {
        return contentEnd;
    }

    /**
     * <p>
     * Sets the content end text.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param contentEnd the new content end text
     */
    protected void setContentEnd(String contentEnd) {
        if (contentEnd == null) {
            contentEnd = "";
        }
        this.contentEnd = contentEnd;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the field name value separator text.
     * </p>
     * 
     * @return the current field name value separator text
     */
    protected String getFieldNameValueSeparator() {
        return fieldNameValueSeparator;
    }

    /**
     * <p>
     * Sets the field name value separator text.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param fieldNameValueSeparator the new field name value separator text
     */
    protected void setFieldNameValueSeparator(String fieldNameValueSeparator) {
        if (fieldNameValueSeparator == null) {
            fieldNameValueSeparator = "";
        }
        this.fieldNameValueSeparator = fieldNameValueSeparator;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the field separator text.
     * </p>
     * 
     * @return the current field separator text
     */
    protected String getFieldSeparator() {
        return fieldSeparator;
    }

    /**
     * <p>
     * Sets the field separator text.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param fieldSeparator the new field separator text
     */
    protected void setFieldSeparator(String fieldSeparator) {
        if (fieldSeparator == null) {
            fieldSeparator = "";
        }
        this.fieldSeparator = fieldSeparator;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets whether the field separator should be added at the start of each buffer.
     * </p>
     * 
     * @return the fieldSeparatorAtStart flag
     * @since 2.0
     */
    protected boolean isFieldSeparatorAtStart() {
        return fieldSeparatorAtStart;
    }

    /**
     * <p>
     * Sets whether the field separator should be added at the start of each buffer.
     * </p>
     * 
     * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag
     * @since 2.0
     */
    protected void setFieldSeparatorAtStart(boolean fieldSeparatorAtStart) {
        this.fieldSeparatorAtStart = fieldSeparatorAtStart;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets whether the field separator should be added at the end of each buffer.
     * </p>
     * 
     * @return fieldSeparatorAtEnd flag
     * @since 2.0
     */
    protected boolean isFieldSeparatorAtEnd() {
        return fieldSeparatorAtEnd;
    }

    /**
     * <p>
     * Sets whether the field separator should be added at the end of each buffer.
     * </p>
     * 
     * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag
     * @since 2.0
     */
    protected void setFieldSeparatorAtEnd(boolean fieldSeparatorAtEnd) {
        this.fieldSeparatorAtEnd = fieldSeparatorAtEnd;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the text to output when <code>null</code> found.
     * </p>
     * 
     * @return the current text to output when null found
     */
    protected String getNullText() {
        return nullText;
    }

    /**
     * <p>
     * Sets the text to output when <code>null</code> found.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param nullText the new text to output when null found
     */
    protected void setNullText(String nullText) {
        if (nullText == null) {
            nullText = "";
        }
        this.nullText = nullText;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the start text to output when a <code>Collection</code>, <code>Map</code> or array size is
     * output.
     * </p>
     * 
     * <p>
     * This is output before the size value.
     * </p>
     * 
     * @return the current start of size text
     */
    protected String getSizeStartText() {
        return sizeStartText;
    }

    /**
     * <p>
     * Sets the start text to output when a <code>Collection</code>, <code>Map</code> or array size is
     * output.
     * </p>
     * 
     * <p>
     * This is output before the size value.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param sizeStartText the new start of size text
     */
    protected void setSizeStartText(String sizeStartText) {
        if (sizeStartText == null) {
            sizeStartText = "";
        }
        this.sizeStartText = sizeStartText;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the end text to output when a <code>Collection</code>, <code>Map</code> or array size is
     * output.
     * </p>
     * 
     * <p>
     * This is output after the size value.
     * </p>
     * 
     * @return the current end of size text
     */
    protected String getSizeEndText() {
        return sizeEndText;
    }

    /**
     * <p>
     * Sets the end text to output when a <code>Collection</code>, <code>Map</code> or array size is
     * output.
     * </p>
     * 
     * <p>
     * This is output after the size value.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param sizeEndText the new end of size text
     */
    protected void setSizeEndText(String sizeEndText) {
        if (sizeEndText == null) {
            sizeEndText = "";
        }
        this.sizeEndText = sizeEndText;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the start text to output when an <code>Object</code> is output in summary mode.
     * </p>
     * 
     * <p>
     * This is output before the size value.
     * </p>
     * 
     * @return the current start of summary text
     */
    protected String getSummaryObjectStartText() {
        return summaryObjectStartText;
    }

    /**
     * <p>
     * Sets the start text to output when an <code>Object</code> is output in summary mode.
     * </p>
     * 
     * <p>
     * This is output before the size value.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param summaryObjectStartText the new start of summary text
     */
    protected void setSummaryObjectStartText(String summaryObjectStartText) {
        if (summaryObjectStartText == null) {
            summaryObjectStartText = "";
        }
        this.summaryObjectStartText = summaryObjectStartText;
    }

    // ---------------------------------------------------------------------

    /**
     * <p>
     * Gets the end text to output when an <code>Object</code> is output in summary mode.
     * </p>
     * 
     * <p>
     * This is output after the size value.
     * </p>
     * 
     * @return the current end of summary text
     */
    protected String getSummaryObjectEndText() {
        return summaryObjectEndText;
    }

    /**
     * <p>
     * Sets the end text to output when an <code>Object</code> is output in summary mode.
     * </p>
     * 
     * <p>
     * This is output after the size value.
     * </p>
     * 
     * <p>
     * <code>null</code> is accepted, but will be converted to an empty String.
     * </p>
     * 
     * @param summaryObjectEndText the new end of summary text
     */
    protected void setSummaryObjectEndText(String summaryObjectEndText) {
        if (summaryObjectEndText == null) {
            summaryObjectEndText = "";
        }
        this.summaryObjectEndText = summaryObjectEndText;
    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * Default <code>ToStringStyle</code>.
     * </p>
     * 
     * <p>
     * This is an inner class rather than using <code>StandardToStringStyle</code> to ensure its
     * immutability.
     * </p>
     */
    private static final class DefaultToStringStyle extends ToStringStyle {

        /**
         * Required for serialization support.
         * 
         * @see java.io.Serializable
         */
        private static final long serialVersionUID = 1L;

        /**
         * <p>
         * Constructor.
         * </p>
         * 
         * <p>
         * Use the static constant rather than instantiating.
         * </p>
         */
        DefaultToStringStyle() {
            super();
        }

        /**
         * <p>
         * Ensure <code>Singleton</code> after serialization.
         * </p>
         * 
         * @return the singleton
         */
        private Object readResolve() {
            return ToStringStyle.DEFAULT_STYLE;
        }

    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * <code>ToStringStyle</code> that does not print out the field names.
     * </p>
     * 
     * <p>
     * This is an inner class rather than using <code>StandardToStringStyle</code> to ensure its
     * immutability.
     */
    private static final class NoFieldNameToStringStyle extends ToStringStyle {

        private static final long serialVersionUID = 1L;

        /**
         * <p>
         * Constructor.
         * </p>
         * 
         * <p>
         * Use the static constant rather than instantiating.
         * </p>
         */
        NoFieldNameToStringStyle() {
            super();
            this.setUseFieldNames(false);
        }

        /**
         * <p>
         * Ensure <code>Singleton</code> after serialization.
         * </p>
         * 
         * @return the singleton
         */
        private Object readResolve() {
            return ToStringStyle.NO_FIELD_NAMES_STYLE;
        }

    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * <code>ToStringStyle</code> that prints out the short class name and no identity hashcode.
     * </p>
     * 
     * <p>
     * This is an inner class rather than using <code>StandardToStringStyle</code> to ensure its
     * immutability.
     * </p>
     */
    private static final class ShortPrefixToStringStyle extends ToStringStyle {

        private static final long serialVersionUID = 1L;

        /**
         * <p>
         * Constructor.
         * </p>
         * 
         * <p>
         * Use the static constant rather than instantiating.
         * </p>
         */
        ShortPrefixToStringStyle() {
            super();
            this.setUseShortClassName(true);
            this.setUseIdentityHashCode(false);
        }

        /**
         * <p>
         * Ensure <code>Singleton</ode> after serialization.
         * </p>
         * 
         * @return the singleton
         */
        private Object readResolve() {
            return ToStringStyle.SHORT_PREFIX_STYLE;
        }

    }

    /**
     * <p>
     * <code>ToStringStyle</code> that does not print out the classname, identity hashcode, content
     * start or field name.
     * </p>
     * 
     * <p>
     * This is an inner class rather than using <code>StandardToStringStyle</code> to ensure its
     * immutability.
     * </p>
     */
    private static final class SimpleToStringStyle extends ToStringStyle {

        private static final long serialVersionUID = 1L;

        /**
         * <p>
         * Constructor.
         * </p>
         * 
         * <p>
         * Use the static constant rather than instantiating.
         * </p>
         */
        SimpleToStringStyle() {
            super();
            this.setUseClassName(false);
            this.setUseIdentityHashCode(false);
            this.setUseFieldNames(false);
            this.setContentStart("");
            this.setContentEnd("");
        }

        /**
         * <p>
         * Ensure <code>Singleton</ode> after serialization.
         * </p>
         * 
         * @return the singleton
         */
        private Object readResolve() {
            return ToStringStyle.SIMPLE_STYLE;
        }

    }

    // ----------------------------------------------------------------------------

    /**
     * <p>
     * <code>ToStringStyle</code> that outputs on multiple lines.
     * </p>
     * 
     * <p>
     * This is an inner class rather than using <code>StandardToStringStyle</code> to ensure its
     * immutability.
     * </p>
     */
    private static final class MultiLineToStringStyle extends ToStringStyle {

        private static final long serialVersionUID = 1L;

        /**
         * <p>
         * Constructor.
         * </p>
         * 
         * <p>
         * Use the static constant rather than instantiating.
         * </p>
         */
        MultiLineToStringStyle() {
            super();
            this.setContentStart("[");
            this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + "  ");
            this.setFieldSeparatorAtStart(true);
            this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]");
        }

        /**
         * <p>
         * Ensure <code>Singleton</code> after serialization.
         * </p>
         * 
         * @return the singleton
         */
        private Object readResolve() {
            return ToStringStyle.MULTI_LINE_STYLE;
        }

    }

}