Add support for static field output.

Main points: 

(1) 
Deprecate in ReflectionToStringBuilder:

public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics)

In favor of:

public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics, Class reflectUpToClass)

(2) New convenience methods ReflectionToStringBuilder.toStringWithStatics.


git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137695 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Gary D. Gregory 2003-10-23 22:26:00 +00:00
parent 667dcaf2ad
commit 5d13513875
3 changed files with 336 additions and 34 deletions

View File

@ -104,7 +104,7 @@
* @author Stephen Colebourne
* @author Pete Gieser
* @since 2.0
* @version $Id: ReflectionToStringBuilder.java,v 1.11 2003/09/07 14:32:34 psteitz Exp $
* @version $Id: ReflectionToStringBuilder.java,v 1.12 2003/10/23 22:25:16 ggregory Exp $
*/
public class ReflectionToStringBuilder extends ToStringBuilder {
@ -114,9 +114,9 @@ public class ReflectionToStringBuilder extends ToStringBuilder {
*/
private static ThreadLocal registry = new ThreadLocal() {
protected synchronized Object initialValue() {
// The HashSet implementation is not synchronized,
// which is just what we need here.
return new HashSet();
// The HashSet implementation is not synchronized,
// which is just what we need here.
return new HashSet();
}
};
@ -150,7 +150,7 @@ static boolean isRegistered(Object value) {
static void register(Object value) {
getRegistry().add(value);
}
/**
* <p>This method uses reflection to build a suitable
* <code>toString</code> using the default <code>ToStringStyle</code>.
@ -168,7 +168,7 @@ static void register(Object value) {
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
public static String toString(Object object) {
return toString(object, null, false, null);
return toString(object, null, false, false, null);
}
/**
@ -194,7 +194,7 @@ public static String toString(Object object) {
* <code>ToStringStyle</code> is <code>null</code>
*/
public static String toString(Object object, ToStringStyle style) {
return toString(object, style, false, null);
return toString(object, style, false, false, null);
}
/**
@ -224,7 +224,79 @@ public static String toString(Object object, ToStringStyle style) {
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
public static String toString(Object object, ToStringStyle style, boolean outputTransients) {
return toString(object, style, outputTransients, null);
return toString(object, style, outputTransients, false, null);
}
/**
* <p>This method uses reflection to build a suitable
* <code>toString</code>.</p>
*
* <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
* fields. This means that it will throw a security exception if run
* under a security manager, if the permissions are not set up correctly.
* It is also not as efficient as testing explicitly.</p>
*
* <p>If the <code>outputTransients</code> is <code>true</code>,
* transient fields will be output, otherwise they are ignored,
* as they are likely derived fields, and not part of the value of the
* Object.</p>
*
* <p>If the <code>outputStatics</code> is <code>true</code>,
* static fields will be output, otherwise they are ignored.</p>
*
* <p>Static fields will not be included. Superclass fields will be appended.</p>
*
* <p>If the style is <code>null</code>, the default
* <code>ToStringStyle</code> is used.</p>
*
* @param object the Object to be output
* @param style the style of the <code>toString</code> to create,
* may be <code>null</code>
* @param outputTransients whether to include transient fields
* @param outputStatics whether to include transient fields
* @return the String result
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics) {
return toString(object, style, outputTransients, outputStatics, null);
}
/**
* <p>This method uses reflection to build a suitable
* <code>toString</code>.</p>
*
* <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
* fields. This means that it will throw a security exception if run
* under a security manager, if the permissions are not set up correctly.
* It is also not as efficient as testing explicitly. </p>
*
* <p>If the <code>outputTransients</code> is <code>true</code>,
* transient fields will be output, otherwise they are ignored,
* as they are likely derived fields, and not part of the value of the
* Object.</p>
*
* <p>If the <code>outputStatics</code> is <code>true</code>,
* static fields will be output, otherwise they are ignored.</p>
*
* <p>Superclass fields will be appended up to and including the
* specified superclass. A null superclass is treated as
* <code>java.lang.Object</code>.</p>
*
* <p>If the style is <code>null</code>, the default
* <code>ToStringStyle</code> is used.</p>
*
* @param object the Object to be output
* @param style the style of the <code>toString</code> to create,
* may be <code>null</code>
* @param outputTransients whether to include transient fields
* @param outputStatics whether to include static fields
* @param reflectUpToClass the superclass to reflect up to (inclusive),
* may be <code>null</code>
* @return the String result
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics, Class reflectUpToClass) {
return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics).toString();
}
/**
@ -247,6 +319,8 @@ public static String toString(Object object, ToStringStyle style, boolean output
*
* <p>If the style is <code>null</code>, the default
* <code>ToStringStyle</code> is used.</p>
*
* @deprecated Use {@link #toString(Object,ToStringStyle,boolean,boolean,Class)}
*
* @param object the Object to be output
* @param style the style of the <code>toString</code> to create,
@ -257,14 +331,97 @@ public static String toString(Object object, ToStringStyle style, boolean output
* @return the String result
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
public static String toString(
Object object,
ToStringStyle style,
boolean outputTransients,
Class reflectUpToClass) {
public static String toString(Object object, ToStringStyle style, boolean outputTransients, Class reflectUpToClass) {
return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients).toString();
}
/**
* TODO: Is this convenience API really needed?
*
* <p>This method uses reflection to build a suitable
* <code>toString</code> value which includes static fields.</p>
*
* <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
* fields. This means that it will throw a security exception if run
* under a security manager, if the permissions are not set up correctly.
* It is also not as efficient as testing explicitly. </p>
*
* <p>Transient fields are not output.</p>
*
* <p>Superclass fields will be appended up to and including
* <code>java.lang.Object</code>.</p>
*
* <p>The default <code>ToStringStyle</code> is used.</p>
*
* @param object the Object to be output
* @param reflectUpToClass the superclass to reflect up to (inclusive),
* may be <code>null</code>
* @return the String result
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
public static Object toStringWithStatics(Object object) {
return toString(object, null, false, true, null);
}
/**
* TODO: Is this convenience API really needed?
*
* <p>This method uses reflection to build a suitable
* <code>toString</code> value which includes static fields.</p>
*
* <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
* fields. This means that it will throw a security exception if run
* under a security manager, if the permissions are not set up correctly.
* It is also not as efficient as testing explicitly. </p>
*
* <p>Transient fields are not output.</p>
*
* <p>Superclass fields will be appended up to and including the specified superclass.
* A null superclass is treated as <code>java.lang.Object</code>.</p>
*
* <p>The default <code>ToStringStyle</code> is used.</p>
*
* @param object the Object to be output
* @param reflectUpToClass the superclass to reflect up to (inclusive),
* may be <code>null</code>
* @return the String result
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
public static Object toStringWithStatics(Object object, Class reflectUpToClass) {
return toString(object, null, false, true, reflectUpToClass);
}
/**
* TODO: Is this convenience API really needed?
*
* <p>This method uses reflection to build a suitable
* <code>toString</code> value which includes static fields.</p>
*
* <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
* fields. This means that it will throw a security exception if run
* under a security manager, if the permissions are not set up correctly.
* It is also not as efficient as testing explicitly. </p>
*
* <p>Transient fields are not output.</p>
*
* <p>Superclass fields will be appended up to and including the specified superclass.
* A null superclass is treated as <code>java.lang.Object</code>.</p>
*
* <p>If the style is <code>null</code>, the default
* <code>ToStringStyle</code> is used.</p>
*
* @param object the Object to be output
* @param style the style of the <code>toString</code> to create,
* may be <code>null</code>
* @param reflectUpToClass the superclass to reflect up to (inclusive),
* may be <code>null</code>
* @return the String result
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
public static Object toStringWithStatics(Object object, ToStringStyle toStringStyle, Class reflectUpToClass) {
return toString(object, toStringStyle, false, true, reflectUpToClass);
}
/**
* <p>Unregisters the given object.</p>
*
@ -276,6 +433,11 @@ static void unregister(Object value) {
getRegistry().remove(value);
}
/**
* Whether or not to append static fields.
*/
private boolean appendStatics = false;
/**
* Whether or not to append transient fields.
*/
@ -340,6 +502,8 @@ public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffe
/**
* Constructor.
*
* @deprecated Use {@link #ReflectionToStringBuilder(Object,ToStringStyle,StringBuffer,Class,boolean,boolean)}.
*
* @param object the Object to build a <code>toString</code> for,
* must not be <code>null</code>
* @param style the style of the <code>toString</code> to create,
@ -361,21 +525,57 @@ public ReflectionToStringBuilder(
this.setAppendTransients(outputTransients);
}
/**
* Constructor.
*
* @param object the Object to build a <code>toString</code> for,
* must not be <code>null</code>
* @param style the style of the <code>toString</code> to create,
* may be <code>null</code>
* @param buffer the <code>StringBuffer</code> to populate, may be
* <code>null</code>
* @param reflectUpToClass the superclass to reflect up to (inclusive),
* may be <code>null</code>
* @param outputTransients whether to include transient fields
* @param outputStatics whether to include static fields
*/
public ReflectionToStringBuilder(
Object object,
ToStringStyle style,
StringBuffer buffer,
Class reflectUpToClass,
boolean outputTransients,
boolean outputStatics) {
super(object, style, buffer);
this.setUpToClass(reflectUpToClass);
this.setAppendTransients(outputTransients);
this.setAppendStatics(outputStatics);
}
/**
* Returns whether or not to append the given <code>Field</code>.
* <ul>
* <li>Static fields are not appended.</li>
* <li>Transient fields are appended only if {@link #isAppendTransients()} returns <code>true</code>.
* <li>Static fields are appended only if {@link #isAppendStatics()} returns <code>true</code>.
* <li>Inner class fields are not appened.</li>
* </ul>
* @param field The Field to test.
* @return Whether or not to append the given <code>Field</code>.
*/
protected boolean accept(Field field) {
String fieldName = field.getName();
return (fieldName.indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) == -1)
&& (this.isAppendTransients() || !Modifier.isTransient(field.getModifiers()))
&& (!Modifier.isStatic(field.getModifiers()));
if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) {
// Reject field from inner class.
return false;
}
if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) {
// transients.
return false;
}
if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) {
// transients.
return false;
}
return true;
}
/**
@ -438,7 +638,7 @@ protected void appendFieldsIn(Class clazz) {
this.unregisterObject();
}
}
/**
* <p>Gets the last super class to stop appending fields for.</p>
*
@ -459,6 +659,15 @@ protected Object getValue(Field field) throws IllegalArgumentException, IllegalA
return field.get(this.getObject());
}
/**
* <p>Gets whether or not to append static fields.</p>
*
* @return Whether or not to append static fields.
*/
public boolean isAppendStatics() {
return this.appendStatics;
}
/**
* <p>Gets whether or not to append transient fields.</p>
*
@ -467,7 +676,7 @@ protected Object getValue(Field field) throws IllegalArgumentException, IllegalA
public boolean isAppendTransients() {
return this.appendTransients;
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* array.</p>
@ -488,6 +697,15 @@ void registerObject() {
register(this.getObject());
}
/**
* <p>Sets whether or not to append static fields.</p>
*
* @param appendStatics Whether or not to append static fields.
*/
public void setAppendStatics(boolean appendStatics) {
this.appendStatics = appendStatics;
}
/**
* <p>Sets whether or not to append transient fields.</p>
*

View File

@ -125,7 +125,7 @@
* @author Gary Gregory
* @author Pete Gieser
* @since 1.0
* @version $Id: ToStringBuilder.java,v 1.29 2003/08/23 00:21:49 ggregory Exp $
* @version $Id: ToStringBuilder.java,v 1.30 2003/10/23 22:25:16 ggregory Exp $
*/
public class ToStringBuilder {
@ -176,7 +176,7 @@ public static String reflectionToString(Object object, ToStringStyle style) {
* @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean)
*/
public static String reflectionToString(Object object, ToStringStyle style, boolean outputTransients) {
return ReflectionToStringBuilder.toString(object, style, outputTransients, null);
return ReflectionToStringBuilder.toString(object, style, outputTransients, false, null);
}
/**
@ -190,7 +190,7 @@ public static String reflectionToString(
ToStringStyle style,
boolean outputTransients,
Class reflectUpToClass) {
return ReflectionToStringBuilder.toString(object, style, outputTransients, reflectUpToClass);
return ReflectionToStringBuilder.toString(object, style, outputTransients, false, reflectUpToClass);
}
/**
@ -1035,6 +1035,16 @@ public ToStringBuilder appendToString(String toString) {
return this;
}
/**
* <p>Returns the <code>Object</code> being output.</p>
*
* @return The object being output.
* @since 2.0
*/
public Object getObject() {
return object;
}
/**
* <p>Gets the <code>StringBuffer</code> being populated.</p>
*
@ -1069,14 +1079,4 @@ public String toString() {
return buffer.toString();
}
/**
* <p>Returns the <code>Object</code> being output.</p>
*
* @return The object being output.
* @since 2.0
*/
public Object getObject() {
return object;
}
}

View File

@ -68,7 +68,7 @@
* @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a>
* @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
* @author <a href="mailto:alex@apache.org">Alex Chaffee</a>
* @version $Id: ToStringBuilderTest.java,v 1.10 2003/08/18 02:22:26 bayard Exp $
* @version $Id: ToStringBuilderTest.java,v 1.11 2003/10/23 22:26:00 ggregory Exp $
*/
public class ToStringBuilderTest extends TestCase {
@ -840,4 +840,88 @@ public void testBooleanArrayArray() {
assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object) array).toString());
}
public void testSimpleReflectionStatics() {
SimpleReflectionStaticFieldsFixture instance1 = new SimpleReflectionStaticFieldsFixture();
assertEquals(
this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345]",
ReflectionToStringBuilder.toString(instance1, null, false, true, SimpleReflectionStaticFieldsFixture.class));
assertEquals(
this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345]",
ReflectionToStringBuilder.toString(instance1, null, true, true, SimpleReflectionStaticFieldsFixture.class));
assertEquals(
this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345]",
ReflectionToStringBuilder.toStringWithStatics(instance1, null, SimpleReflectionStaticFieldsFixture.class));
assertEquals(
this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345]",
ReflectionToStringBuilder.toStringWithStatics(instance1, SimpleReflectionStaticFieldsFixture.class));
}
/**
* Tests ReflectionToStringBuilder.toString() for statics.
*/
public void testReflectionStatics() {
ReflectionStaticFieldsFixture instance1 = new ReflectionStaticFieldsFixture();
assertEquals(
this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345,instanceString=instanceString,instanceInt=67890]",
ReflectionToStringBuilder.toString(instance1, null, false, true, ReflectionStaticFieldsFixture.class));
assertEquals(
this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345,staticTransientString=staticTransientString,staticTransientInt=54321,instanceString=instanceString,instanceInt=67890,transientString=transientString,transientInt=98765]",
ReflectionToStringBuilder.toString(instance1, null, true, true, ReflectionStaticFieldsFixture.class));
assertEquals(
this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345,instanceString=instanceString,instanceInt=67890]",
ReflectionToStringBuilder.toStringWithStatics(instance1, null, ReflectionStaticFieldsFixture.class));
assertEquals(
this.toBaseString(instance1) + "[staticString=staticString,staticInt=12345,instanceString=instanceString,instanceInt=67890]",
ReflectionToStringBuilder.toStringWithStatics(instance1, ReflectionStaticFieldsFixture.class));
}
/**
* Tests ReflectionToStringBuilder.toString() for statics.
*/
public void testInheritedReflectionStatics() {
InheritedReflectionStaticFieldsFixture instance1 = new InheritedReflectionStaticFieldsFixture();
assertEquals(
this.toBaseString(instance1) + "[staticString2=staticString2,staticInt2=67890]",
ReflectionToStringBuilder.toString(instance1, null, false, true, InheritedReflectionStaticFieldsFixture.class));
assertEquals(
this.toBaseString(instance1) + "[staticString2=staticString2,staticInt2=67890,staticString=staticString,staticInt=12345]",
ReflectionToStringBuilder.toString(instance1, null, false, true, SimpleReflectionStaticFieldsFixture.class));
assertEquals(
this.toBaseString(instance1) + "[staticString2=staticString2,staticInt2=67890,staticString=staticString,staticInt=12345]",
ReflectionToStringBuilder.toStringWithStatics(instance1, null, SimpleReflectionStaticFieldsFixture.class));
assertEquals(
this.toBaseString(instance1) + "[staticString2=staticString2,staticInt2=67890,staticString=staticString,staticInt=12345]",
ReflectionToStringBuilder.toStringWithStatics(instance1, SimpleReflectionStaticFieldsFixture.class));
}
/**
* Tests ReflectionToStringBuilder.toString() for statics.
*/
class ReflectionStaticFieldsFixture {
static final String staticString = "staticString";
static final int staticInt = 12345;
static final transient String staticTransientString = "staticTransientString";
static final transient int staticTransientInt = 54321;
String instanceString = "instanceString";
int instanceInt = 67890;
transient String transientString = "transientString";
transient int transientInt = 98765;
}
/**
* Test fixture for ReflectionToStringBuilder.toString() for statics.
*/
class SimpleReflectionStaticFieldsFixture {
static final String staticString = "staticString";
static final int staticInt = 12345;
}
/**
* Test fixture for ReflectionToStringBuilder.toString() for statics.
*/
class InheritedReflectionStaticFieldsFixture extends SimpleReflectionStaticFieldsFixture {
static final String staticString2 = "staticString2";
static final int staticInt2 = 67890;
}
}