/*
* 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 org.caudexorigo.builder;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.caudexorigo.lang.ClassUtils;
import org.caudexorigo.lang.ObjectUtils;
import org.caudexorigo.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(StringBuilder buffer, String fieldName, Object value)
* {
* if (value instanceof Date)
* {
* value = new SimpleDateFormat("yyyy-MM-dd").format(value);
* }
* buffer.append(value);
* }
* }
* </pre>
*
* </p>
*
* @author Stephen Colebourne
* @author Gary Gregory
* @author Pete Gieser
* @author Masato Tezuka
* @since 1.0
* @version $Id: ToStringStyle.java 594386 2007-11-13 01:22:21Z bayard $
*/
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 ThreadLocal registry = new ThreadLocal()
{
protected Object initialValue()
{
// The HashSet implementation is not synchronized,
// which is just what we need here.
return new HashSet();
}
};
/**
* <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 Set getRegistry()
{
return (Set) 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)
{
return getRegistry().contains(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)
{
getRegistry().add(value);
}
}
/**
* <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)
{
getRegistry().remove(value);
}
/**
* 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>'<null>'</code>.
*/
private String nullText = "<null>";
/**
* The summary size text start <code>'<size'</code>.
*/
private String sizeStartText = "<size=";
/**
* The summary size text start <code>'>'</code>.
*/
private String sizeEndText = ">";
/**
* The summary object text start <code>'<'</code>.
*/
private String summaryObjectStartText = "<";
/**
* The summary object text start <code>'>'</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>StringBuilder</code> to populate
* @param superToString
* the <code>super.toString()</code>
* @since 2.0
*/
public void appendSuper(StringBuilder 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>StringBuilder</code> to populate
* @param toString
* the additional <code>toString</code>
* @since 2.0
*/
public void appendToString(StringBuilder 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>StringBuilder</code> to populate
* @param object
* the <code>Object</code> to build a <code>toString</code> for
*/
public void appendStart(StringBuilder 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>StringBuilder</code> to populate
* @param object
* the <code>Object</code> to build a <code>toString</code> for.
*/
public void appendEnd(StringBuilder 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>StringBuilder</code> to populate
* @since 2.0
*/
protected void removeLastFieldSeparator(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder buffer, String fieldName, Object value)
{
ObjectUtils.appendIdentityToString(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>StringBuilder</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(StringBuilder buffer, String fieldName, Object value)
{
buffer.append(value);
}
/**
* <p>
* Append to the <code>toString</code> a <code>Collection</code>.
* </p>
*
* @param buffer
* the <code>StringBuilder</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(StringBuilder buffer, String fieldName, Collection coll)
{
buffer.append(coll);
}
/**
* <p>
* Append to the <code>toString</code> a <code>Map<code>.
* </p>
*
* @param buffer
* the <code>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</code> to populate
* @param fieldName
* the field name
* @param value
* the value to add to the <code>toString</code>
*/
public void append(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</code> to populate
* @param fieldName
* the field name
* @param value
* the value to add to the <code>toString</code>
*/
public void append(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</code> to populate
* @param fieldName
* the field name
* @param value
* the value to add to the <code>toString</code>
*/
public void append(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</code> to populate
* @param fieldName
* the field name
* @param value
* the value to add to the <code>toString</code>
*/
public void append(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</code> to populate
* @param fieldName
* the field name
* @param value
* the value to add to the <code>toString</code>
*/
public void append(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</code> to populate
* @param fieldName
* the field name
* @param value
* the value to add to the <code>toString</code>
*/
public void append(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</code> to populate
* @param fieldName
* the field name
* @param value
* the value to add to the <code>toString</code>
*/
public void append(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</code> to populate
* @param fieldName
* the field name
* @param value
* the value to add to the <code>toString</code>
*/
public void append(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</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(StringBuilder 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>StringBuilder</code> to populate
* @param object
* the <code>Object</code> whose name to output
*/
protected void appendClassName(StringBuilder 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>StringBuilder</code> to populate
* @param object
* the <code>Object</code> whose id to output
*/
protected void appendIdentityHashCode(StringBuilder 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>StringBuilder</code> to populate
*/
protected void appendContentStart(StringBuilder buffer)
{
buffer.append(contentStart);
}
/**
* <p>
* Append to the <code>toString</code> the content end.
* </p>
*
* @param buffer
* the <code>StringBuilder</code> to populate
*/
protected void appendContentEnd(StringBuilder buffer)
{
buffer.append(contentEnd);
}
/**
* <p>
* Append to the <code>toString</code> an indicator for <code>null</code>.
* </p>
*
* <p>
* The default indicator is <code>'<null>'</code>.
* </p>
*
* @param buffer
* the <code>StringBuilder</code> to populate
* @param fieldName
* the field name, typically not used as already appended
*/
protected void appendNullText(StringBuilder buffer, String fieldName)
{
buffer.append(nullText);
}
/**
* <p>
* Append to the <code>toString</code> the field separator.
* </p>
*
* @param buffer
* the <code>StringBuilder</code> to populate
*/
protected void appendFieldSeparator(StringBuilder buffer)
{
buffer.append(fieldSeparator);
}
/**
* <p>
* Append to the <code>toString</code> the field start.
* </p>
*
* @param buffer
* the <code>StringBuilder</code> to populate
* @param fieldName
* the field name
*/
protected void appendFieldStart(StringBuilder 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>StringBuilder</code> to populate
* @param fieldName
* the field name, typically not used as already appended
*/
protected void appendFieldEnd(StringBuilder 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>'<size=n>'<code>.
* </p>
*
* @param buffer
* the <code>StringBuilder</code> to populate
* @param fieldName
* the field name, typically not used as already appended
* @param size
* the size to append
*/
protected void appendSummarySize(StringBuilder 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;
}
}
}