You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2002/12/31 21:17:55 UTC
cvs commit: jakarta-commons/lang/src/java/org/apache/commons/lang/builder ToStringBuilder.java
scolebourne 2002/12/31 12:17:54
Modified: lang/src/test/org/apache/commons/lang/builder
ToStringBuilderTest.java
lang/src/java/org/apache/commons/lang/builder
ToStringBuilder.java
Log:
Fix to include superclass fields in reflection toString
Revision Changes Path
1.3 +53 -5 jakarta-commons/lang/src/test/org/apache/commons/lang/builder/ToStringBuilderTest.java
Index: ToStringBuilderTest.java
===================================================================
RCS file: /home/cvs/jakarta-commons/lang/src/test/org/apache/commons/lang/builder/ToStringBuilderTest.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ToStringBuilderTest.java 8 Dec 2002 20:48:46 -0000 1.2
+++ ToStringBuilderTest.java 31 Dec 2002 20:17:53 -0000 1.3
@@ -56,6 +56,7 @@
package org.apache.commons.lang.builder;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import junit.framework.Test;
import junit.framework.TestCase;
@@ -163,10 +164,57 @@
assertEquals(baseStr + "[]", new ToStringBuilder(base).toString());
}
- public void testReflection() {
- assertEquals(baseStr + "[value=5]", ToStringBuilder.reflectionToString(base));
- }
-
+ public void testReflection() {
+ assertEquals(baseStr + "[value=5]", ToStringBuilder.reflectionToString(base));
+ }
+
+ private String toBaseString(Object o) {
+ return o.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(o));
+ }
+
+ public void testReflectionHierarchyArrayList() {
+ List base = new ArrayList();
+ String baseStr = this.toBaseString(base);
+ assertEquals(baseStr + "[elementData={<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>},size=0,modCount=0]", ToStringBuilder.reflectionToString(base, null, true));
+ assertEquals(baseStr + "[size=0]", ToStringBuilder.reflectionToString(base, null, false));
+ }
+
+ public void testReflectionHierarchy() {
+ ReflectionTestFixtureA baseA = new ReflectionTestFixtureA();
+ String baseStr = this.toBaseString(baseA);
+ assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA));
+ assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null));
+ assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null, false));
+ assertEquals(baseStr + "[a=a,transientA=t]", ToStringBuilder.reflectionToString(baseA, null, true));
+ assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null, false, null));
+ assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null, false, Object.class));
+ assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null, false, List.class));
+ assertEquals(baseStr + "[a=a]", ToStringBuilder.reflectionToString(baseA, null, false, ReflectionTestFixtureA.class));
+
+ ReflectionTestFixtureB baseB = new ReflectionTestFixtureB();
+ baseStr = this.toBaseString(baseB);
+ assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB));
+ assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB));
+ assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null));
+ assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null, false));
+ assertEquals(baseStr + "[b=b,transientB=t,a=a,transientA=t]", ToStringBuilder.reflectionToString(baseB, null, true));
+ assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null, false, null));
+ assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null, false, Object.class));
+ assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null, false, List.class));
+ assertEquals(baseStr + "[b=b,a=a]", ToStringBuilder.reflectionToString(baseB, null, false, ReflectionTestFixtureA.class));
+ assertEquals(baseStr + "[b=b]", ToStringBuilder.reflectionToString(baseB, null, false, ReflectionTestFixtureB.class));
+ }
+
+ static class ReflectionTestFixtureA {
+ private char a='a';
+ private transient char transientA='t';
+ }
+
+ static class ReflectionTestFixtureB extends ReflectionTestFixtureA {
+ private char b='b';
+ private transient char transientB='t';
+ }
+
public void testAppendSuper() {
assertEquals(baseStr + "[]", new ToStringBuilder(base).appendSuper("Integer@8888[]").toString());
assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").toString());
1.11 +66 -17 jakarta-commons/lang/src/java/org/apache/commons/lang/builder/ToStringBuilder.java
Index: ToStringBuilder.java
===================================================================
RCS file: /home/cvs/jakarta-commons/lang/src/java/org/apache/commons/lang/builder/ToStringBuilder.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- ToStringBuilder.java 23 Dec 2002 00:20:31 -0000 1.10
+++ ToStringBuilder.java 31 Dec 2002 20:17:53 -0000 1.11
@@ -98,7 +98,7 @@
* <code>reflectionToString</code>, uses <code>Field.setAccessible</code> to
* change the visibility of the fields. This will fail under a security manager,
* unless the appropriate permissions are set up correctly. It is also
- * slower than testing explicitly and does not handle superclasses.</p>
+ * slower than testing explicitly.</p>
*
* <p>A typical invocation for this method would look like:</p>
* <pre>
@@ -243,14 +243,14 @@
*
* <p>Transient members will be not be included, as they are likely derived.</p>
*
- * <p>Static fields will be not be included.</p>
+ * <p>Static fields will not be included. Superclass fields will be appended.</p>
*
* @param object the Object to be output
* @return the String result
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
public static String reflectionToString(Object object) {
- return reflectionToString(object, null, false);
+ return reflectionToString(object, null, false, null);
}
/**
@@ -265,7 +265,7 @@
* <p>Transient members will be not be included, as they are likely
* derived.</p>
*
- * <p>Static fields will be not be included.</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>
@@ -278,7 +278,7 @@
* <code>ToStringStyle</code> is <code>null</code>
*/
public static String reflectionToString(Object object, ToStringStyle style) {
- return reflectionToString(object, style, false);
+ return reflectionToString(object, style, false, null);
}
/**
@@ -295,7 +295,7 @@
* as they are likely derived fields, and not part of the value of the
* Object.</p>
*
- * <p>Static fields will not be tested.</p>
+ * <p>Static fields will not be included. Superclass fields will be appended.</p>
*
* <p>
* If the style is <code>null</code>, the default
@@ -308,36 +308,85 @@
* @return the String result
* @throws IllegalArgumentException if the Object is <code>null</code>
*/
- public static String reflectionToString(Object object, ToStringStyle style,
- boolean outputTransients) {
+ public static String reflectionToString(Object object, ToStringStyle style, boolean outputTransients) {
+ return reflectionToString(object, style, outputTransients, null);
+ }
+
+ /**
+ * <p>This method uses reflection to build a suitable
+ * <code>toString</code>.</p>
+ *
+ * <p>It uses <code>Field.setAccessible</code> to gain access to private
+ * fields. This means that it will throw a security exception if run
+ * under a security manger, 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 members will be output, otherwise they are ignored,
+ * as they are likely derived fields, and not part of the value of the
+ * Object.</p>
+ *
+ * <p>Static fields will not be included. Superclass fields will be appended
+ * up to and including the specified superclass. A null superclass is treated
+ * as java.lang.Object.</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 reflectUpToClass the superclass to reflect up to (inclusive), may be null
+ * @return the String result
+ * @throws IllegalArgumentException if the Object is <code>null</code>
+ */
+ public static String reflectionToString(Object object, ToStringStyle style, boolean outputTransients, Class reflectUpToClass) {
if (object == null) {
throw new IllegalArgumentException("The object must not be null");
}
if (style == null) {
style = getDefaultStyle();
}
- Field[] fields = object.getClass().getDeclaredFields();
- Field.setAccessible(fields, true);
ToStringBuilder builder = new ToStringBuilder(object, style);
+ Class clazz = object.getClass();
+ reflectionAppend(object, clazz, builder, outputTransients);
+ while (clazz.getSuperclass() != null && clazz != reflectUpToClass) {
+ clazz = clazz.getSuperclass();
+ reflectionAppend(object, clazz, builder, outputTransients);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Appends the fields and values defined by the given object of the
+ * given Class.
+ *
+ * @param object the object to append details of
+ * @param clazz the class to append details of
+ * @param builder the builder to append to
+ * @param outputTransients whether to output transient fields
+ */
+ private static void reflectionAppend(Object object, Class clazz, ToStringBuilder builder, boolean outputTransients) {
+ Field[] fields = clazz.getDeclaredFields();
+ Field.setAccessible(fields, true);
for (int i = 0; i < fields.length; ++i) {
Field f = fields[i];
if (outputTransients || !Modifier.isTransient(f.getModifiers())) {
if (!Modifier.isStatic(f.getModifiers())) {
try {
builder.append(f.getName(), f.get(object));
-
} catch (IllegalAccessException ex) {
//this can't happen. Would get a Security exception instead
//throw a runtime exception in case the impossible happens.
- throw new InternalError("Unexpected IllegalAccessException");
}
}
}
}
- return builder.toString();
- }
-
- //----------------------------------------------------------------------------
+ }
+
+ //----------------------------------------------------------------------------
/**
* <p>Append the <code>toString</code> from the superclass.</p>
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>