commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ki...@apache.org
Subject svn commit: r1569028 - in /commons/proper/lang/trunk/src: changes/ main/java/org/apache/commons/lang3/builder/ test/java/org/apache/commons/lang3/builder/
Date Mon, 17 Feb 2014 15:45:17 GMT
Author: kinow
Date: Mon Feb 17 15:45:17 2014
New Revision: 1569028

URL: http://svn.apache.org/r1569028
Log:
LANG-621: ReflectionToStringBuilder.toString does not debug 3rd party object fields within
3rd party object. Suggested by Philip Hodges. Final patch from Thomas Neidhart.

Added:
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/RecursiveToStringStyle.java
    commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/RecursiveToStringStyleTest.java
Modified:
    commons/proper/lang/trunk/src/changes/changes.xml
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java

Modified: commons/proper/lang/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/changes/changes.xml?rev=1569028&r1=1569027&r2=1569028&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/changes/changes.xml [utf-8] (original)
+++ commons/proper/lang/trunk/src/changes/changes.xml [utf-8] Mon Feb 17 15:45:17 2014
@@ -22,6 +22,7 @@
   <body>
 
   <release version="3.3" date="TBA" description="Bugfix and Feature release">
+    <action issue="LANG-621" type="fix" dev="kinow" due-to="Philip Hodges, Thomas Neidhart">ReflectionToStringBuilder.toString
does not debug 3rd party object fields within 3rd party object</action>
     <action issue="LANG-955" type="add" dev="britter" due-to="Adam Hooper">Add methods
for removing all invalid characters according to XML 1.0 and XML 1.1 in an input string to
StringEscapeUtils</action>
     <action issue="LANG-977" type="fix" dev="britter" due-to="Chris Karcher">NumericEntityEscaper
incorrectly encodes supplementary characters</action>
     <action issue="LANG-973" type="fix" dev="sebb">Make some private fields final</action>

Added: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/RecursiveToStringStyle.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/RecursiveToStringStyle.java?rev=1569028&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/RecursiveToStringStyle.java
(added)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/RecursiveToStringStyle.java
Mon Feb 17 15:45:17 2014
@@ -0,0 +1,84 @@
+package org.apache.commons.lang3.builder;
+
+import java.util.Collection;
+
+import org.apache.commons.lang3.ClassUtils;
+
+/**
+ * <p>Works with {@link ToStringBuilder} to create a "deep" <code>toString</code>.</p>
+ *
+ * <p>To use this class write code as follows:</p>
+ *
+ * <pre>
+ * public class Job {
+ *   String title;
+ *   ...
+ * }
+ * 
+ * public class Person {
+ *   String name;
+ *   int age;
+ *   boolean smoker;
+ *   Job job;
+ *
+ *   ...
+ *
+ *   public String toString() {
+ *     return new ReflectionToStringBuilder(this, new RecursiveToStringStyle()).toString();
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>This will produce a toString of the format:
+ * <code>Person@7f54[name=Stephen,age=29,smoker=false,job=Job@43cd2[title=Manager]]</code></p>
+ * 
+ * @since 3.2
+ * @version $Id$
+ */
+public class RecursiveToStringStyle extends ToStringStyle {
+
+    /**
+     * Required for serialization support.
+     * 
+     * @see java.io.Serializable
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * <p>Constructor.</p>
+     */
+    public RecursiveToStringStyle() {
+        super();
+    }
+
+    @Override
+    public void appendDetail(StringBuffer buffer, String fieldName, Object value) {
+        if (!ClassUtils.isPrimitiveWrapper(value.getClass()) &&
+            !String.class.equals(value.getClass()) &&
+            accept(value.getClass())) {
+            buffer.append(ReflectionToStringBuilder.toString(value, this));
+        } else {
+            super.appendDetail(buffer, fieldName, value);
+        }
+    }
+
+    @Override
+    protected void appendDetail(StringBuffer buffer, String fieldName, Collection<?>
coll) {
+        appendClassName(buffer, coll);
+        appendIdentityHashCode(buffer, coll);
+        appendDetail(buffer, fieldName, coll.toArray());
+    }
+    
+    /**
+     * Returns whether or not to recursively format the given <code>Class</code>.
+     * By default, this method always returns {@code true}, but may be overwritten by
+     * sub-classes to filter specific classes.
+     *
+     * @param clazz
+     *            The class to test.
+     * @return Whether or not to recursively format the given <code>Class</code>.
+     */
+    protected boolean accept(final Class<?> clazz) {
+        return true;
+    }
+}

Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java?rev=1569028&r1=1569027&r2=1569028&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java
(original)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java
Mon Feb 17 15:45:17 2014
@@ -81,7 +81,12 @@ import org.apache.commons.lang3.ClassUti
  * <p>
  * The exact format of the <code>toString</code> is determined by the {@link
ToStringStyle} passed into the constructor.
  * </p>
- * 
+ *
+ * <p>
+ * <b>Note:</b> the default {@link ToStringStyle} will only do a "shallow" formatting,
i.e. composed objects are not
+ * further traversed. To get "deep" formatting, use an instance of {@link RecursiveToStringStyle}.
+ * </p>
+ *
  * @since 2.0
  * @version $Id$
  */

Added: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/RecursiveToStringStyleTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/RecursiveToStringStyleTest.java?rev=1569028&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/RecursiveToStringStyleTest.java
(added)
+++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/RecursiveToStringStyleTest.java
Mon Feb 17 15:45:17 2014
@@ -0,0 +1,163 @@
+/*
+ * 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.apache.commons.lang3.builder;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests {@link org.apache.commons.lang3.builder.RecursiveToStringStyleTest}.
+ *
+ * @version $Id$
+ */
+public class RecursiveToStringStyleTest {
+
+    private final Integer base = Integer.valueOf(5);
+    private final String baseStr = base.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(base));
+    
+    @Before
+    public void setUp() throws Exception {
+        ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        ToStringBuilder.setDefaultStyle(ToStringStyle.DEFAULT_STYLE);
+    }
+
+    //----------------------------------------------------------------
+    
+    @Test
+    public void testBlank() {
+        assertEquals(baseStr + "[]", new ToStringBuilder(base).toString());
+    }
+
+    @Test
+    public void testAppendSuper() {
+        assertEquals(baseStr + "[]", new ToStringBuilder(base).appendSuper("Integer@8888[]").toString());
+        assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").toString());
+        
+        assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[]").append("a",
"hello").toString());
+        assertEquals(baseStr + "[<null>,a=hello]", new ToStringBuilder(base).appendSuper("Integer@8888[<null>]").append("a",
"hello").toString());
+        assertEquals(baseStr + "[a=hello]", new ToStringBuilder(base).appendSuper(null).append("a",
"hello").toString());
+    }
+    
+    @Test
+    public void testObject() {
+        final Integer i3 = Integer.valueOf(3);
+        final Integer i4 = Integer.valueOf(4);
+        assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object)
null).toString());
+        assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(i3).toString());
+        assertEquals(baseStr + "[a=<null>]", new ToStringBuilder(base).append("a",
(Object) null).toString());
+        assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", i3).toString());
+        assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", i3).append("b",
i4).toString());
+        assertEquals(baseStr + "[a=<Integer>]", new ToStringBuilder(base).append("a",
i3, false).toString());
+        assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a",
new ArrayList<Object>(), false).toString());
+        assertEquals(baseStr + "[a=[]]", new ToStringBuilder(base).append("a", new ArrayList<Object>(),
true).toString());
+        assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a",
new HashMap<Object, Object>(), false).toString());
+        assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", new HashMap<Object,
Object>(), true).toString());
+        assertEquals(baseStr + "[a=<size=0>]", new ToStringBuilder(base).append("a",
(Object) new String[0], false).toString());
+        assertEquals(baseStr + "[a={}]", new ToStringBuilder(base).append("a", (Object) new
String[0], true).toString());
+    }
+
+    @Test
+    public void testPerson() {
+        final Person p = new Person();
+        p.name = "John Doe";
+        p.age = 33;
+        p.smoker = false;
+        p.job = new Job();
+        p.job.title = "Manager";
+        final String pBaseStr = p.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(p));
+        final String pJobStr  = p.job.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(p.job));
+        assertEquals(pBaseStr + "[name=John Doe,age=33,smoker=false,job=" + pJobStr + "[title=Manager]]",
+                     new ReflectionToStringBuilder(p, new RecursiveToStringStyle()).toString());
+    }
+
+    @Test
+    public void testLong() {
+        assertEquals(baseStr + "[3]", new ToStringBuilder(base).append(3L).toString());
+        assertEquals(baseStr + "[a=3]", new ToStringBuilder(base).append("a", 3L).toString());
+        assertEquals(baseStr + "[a=3,b=4]", new ToStringBuilder(base).append("a", 3L).append("b",
4L).toString());
+    }
+
+    @Test
+    public void testObjectArray() {
+        Object[] array = new Object[] {null, base, new int[] {3, 6}};
+        assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append(array).toString());
+        assertEquals(baseStr + "[{<null>,5,{3,6}}]", new ToStringBuilder(base).append((Object)
array).toString());
+        array = null;
+        assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
+        assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object)
array).toString());
+    }
+
+    @Test
+    public void testLongArray() {
+        long[] array = new long[] {1, 2, -3, 4};
+        assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append(array).toString());
+        assertEquals(baseStr + "[{1,2,-3,4}]", new ToStringBuilder(base).append((Object)
array).toString());
+        array = null;
+        assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
+        assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object)
array).toString());
+    }
+
+    @Test
+    public void testLongArrayArray() {
+        long[][] array = new long[][] {{1, 2}, null, {5}};
+        assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append(array).toString());
+        assertEquals(baseStr + "[{{1,2},<null>,{5}}]", new ToStringBuilder(base).append((Object)
array).toString());
+        array = null;
+        assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append(array).toString());
+        assertEquals(baseStr + "[<null>]", new ToStringBuilder(base).append((Object)
array).toString());
+    }
+
+    static class Person {
+        /**
+         * Test String field.
+         */
+        String name;
+
+        /**
+         * Test integer field.
+         */
+        int age;
+
+        /**
+         * Test boolean field.
+         */
+        boolean smoker;
+        
+        /**
+         * Test Object field.
+         */
+        Job job;
+    }
+    
+    static class Job {
+        /**
+         * Test String field.
+         */
+        String title;
+    }
+
+}



Mime
View raw message