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>