Author: britter
Date: Sun Nov  9 12:47:12 2014
New Revision: 1637671

URL: http://svn.apache.org/r1637671
Log:
LANG-1052: Multiline recursive to string style. This fixes #34 from github. 
Thanks to Jan Matèrne.

Added:
    
commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java
   (with props)
    
commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java
   (with props)
Modified:
    commons/proper/lang/trunk/src/changes/changes.xml

Modified: commons/proper/lang/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/changes/changes.xml?rev=1637671&r1=1637670&r2=1637671&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/changes/changes.xml [utf-8] (original)
+++ commons/proper/lang/trunk/src/changes/changes.xml [utf-8] Sun Nov  9 
12:47:12 2014
@@ -22,6 +22,7 @@
   <body>
 
   <release version="3.4" date="tba" description="tba">
+    <action issue="LANG-1052" type="add" dev="britter" due-to="Jan 
Matèrne">Multiline recursive to string style</action>
     <action issue="LANG-536" type="add" dev="djones" due-to="James Sawle">Add 
isSorted() to ArrayUtils</action>
     <action issue="LANG-1041" type="fix" dev="britter" due-to="Alexandre 
Bartel">Fix MethodUtilsTest so it does not depend on JDK method 
ordering</action>
     <action issue="LANG-827" type="update" dev="djones">CompareToBuilder's doc 
doesn't specify precedence of fields it uses in performing comparisons</action>

Added: 
commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java
URL: 
http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java?rev=1637671&view=auto
==============================================================================
--- 
commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java
 (added)
+++ 
commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java
 Sun Nov  9 12:47:12 2014
@@ -0,0 +1,219 @@
+/*
+ * 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 org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.SystemUtils;
+
+/**
+ * <p>Works with {@link ToStringBuilder} to create a "deep" 
<code>toString</code>. 
+ * But instead a single line like the {@link RecursiveToStringStyle} this 
creates a multiline String 
+ * similar to the {@link ToStringStyle.MultiLineToStringStyle}.</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 
MultilineRecursiveToStringStyle()).toString();
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>
+ * This will produce a toString of the format:<br>
+ * <code>Person@7f54[ <br>
+ * &nbsp; name=Stephen, <br>
+ * &nbsp; age=29, <br>
+ * &nbsp; smoker=false, <br>
+ * &nbsp; job=Job@43cd2[ <br>
+ * &nbsp; &nbsp; title=Manager <br>
+ * &nbsp;  ] <br>
+ * ]
+ * </code>
+ * </p>
+ * 
+ * @since 3.4
+ * @version $Id$
+ */
+class MultilineRecursiveToStringStyle extends RecursiveToStringStyle {
+
+    /**
+     * Required for serialization support.
+     * @see java.io.Serializable
+     */
+    private static final long serialVersionUID = 1L;
+
+    /** Indenting of inner lines. */
+    private int indent = 2;
+
+    /** Current indenting. */
+    private int spaces = 2;
+
+    /**
+     * Constructor.
+     */
+    public MultilineRecursiveToStringStyle() {
+        super();
+        resetIndent();
+    }
+
+    /**
+     * Resets the fields responsible for the line breaks and indenting. 
+     * Must be invoked after changing the {@link #spaces} value.
+     */
+    private void resetIndent() {
+        setArrayStart("{" + SystemUtils.LINE_SEPARATOR + spacer(spaces));
+        setArraySeparator("," + SystemUtils.LINE_SEPARATOR + spacer(spaces));
+        setArrayEnd(SystemUtils.LINE_SEPARATOR + spacer(spaces - indent) + 
"}");
+
+        setContentStart("[" + SystemUtils.LINE_SEPARATOR + spacer(spaces));
+        setFieldSeparator("," + SystemUtils.LINE_SEPARATOR + spacer(spaces));
+        setContentEnd(SystemUtils.LINE_SEPARATOR + spacer(spaces - indent) + 
"]");
+    }
+
+    /**
+     * Creates a string(buffer) responsible for the indenting.
+     * @param spaces how far to indent
+     * @return
+     */
+    private StringBuilder spacer(int spaces) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < spaces; i++) {
+            sb.append(" ");
+        }
+        return sb;
+    }
+
+    @Override
+    public void appendDetail(StringBuffer buffer, String fieldName, Object 
value) {
+        if (!ClassUtils.isPrimitiveWrapper(value.getClass()) && 
!String.class.equals(value.getClass())
+                && accept(value.getClass())) {
+            spaces += indent;
+            resetIndent();
+            buffer.append(ReflectionToStringBuilder.toString(value, this));
+            spaces -= indent;
+            resetIndent();
+        } else {
+            super.appendDetail(buffer, fieldName, value);
+        }
+    }
+
+    @Override
+    protected void appendDetail(final StringBuffer buffer, final String 
fieldName, final Object[] array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+    @Override
+    protected void reflectionAppendArrayDetail(final StringBuffer buffer, 
final String fieldName, final Object array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+    @Override
+    protected void appendDetail(final StringBuffer buffer, final String 
fieldName, final long[] array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+    @Override
+    protected void appendDetail(final StringBuffer buffer, final String 
fieldName, final int[] array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+    @Override
+    protected void appendDetail(final StringBuffer buffer, final String 
fieldName, final short[] array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+    @Override
+    protected void appendDetail(final StringBuffer buffer, final String 
fieldName, final byte[] array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+    @Override
+    protected void appendDetail(final StringBuffer buffer, final String 
fieldName, final char[] array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+    @Override
+    protected void appendDetail(final StringBuffer buffer, final String 
fieldName, final double[] array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+    @Override
+    protected void appendDetail(final StringBuffer buffer, final String 
fieldName, final float[] array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+    @Override
+    protected void appendDetail(final StringBuffer buffer, final String 
fieldName, final boolean[] array) {
+        spaces += indent;
+        resetIndent();
+        super.appendDetail(buffer, fieldName, array);
+        spaces -= indent;
+        resetIndent();
+    }
+
+}
\ No newline at end of file

Propchange: 
commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: 
commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java?rev=1637671&view=auto
==============================================================================
--- 
commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java
 (added)
+++ 
commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java
 Sun Nov  9 12:47:12 2014
@@ -0,0 +1,264 @@
+/*
+ * 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.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.junit.Test;
+
+/**
+ * @version $Id$
+ */
+public class MultilineRecursiveToStringStyleTest {
+
+    private final String BR = SystemUtils.LINE_SEPARATOR;
+
+    @Test
+    public void simpleObject() {
+        Transaction tx = new Transaction("2014.10.15", 100);
+        String expected = getClassPrefix(tx) + "[" + BR 
+                        + "  amount=100.0," + BR 
+                        + "  date=2014.10.15" + BR 
+                        + "]";
+        assertEquals(expected, toString(tx));
+    }
+
+    @Test
+    public void nestedElements() {
+        Customer customer = new Customer("Douglas Adams");
+        Bank bank = new Bank("ASF Bank");
+        customer.bank = bank;
+        String exp = getClassPrefix(customer) + "[" + BR 
+                   + "  name=Douglas Adams," + BR 
+                   + "  bank=" + getClassPrefix(bank) + "[" + BR 
+                   + "    name=ASF Bank" + BR 
+                   + "  ]," + BR 
+                   + "  accounts=<null>" + BR 
+                   + "]";
+        assertEquals(exp, toString(customer));
+    }
+
+    @Test
+    public void nestedAndArray() {
+        Account acc = new Account();
+        Transaction tx1 = new Transaction("2014.10.14", 100);
+        Transaction tx2 = new Transaction("2014.10.15", 50);
+        acc.transactions.add(tx1);
+        acc.transactions.add(tx2);
+        String expected = getClassPrefix(acc) + "[" + BR 
+                        + "  owner=<null>," + BR 
+                        + "  transactions=" + getClassPrefix(acc.transactions) 
+ "{" + BR 
+                        + "    " + getClassPrefix(tx1) + "[" + BR 
+                        + "      amount=100.0," + BR 
+                        + "      date=2014.10.14" + BR 
+                        + "    ]," + BR 
+                        + "    " + getClassPrefix(tx2) + "[" + BR
+                        + "      amount=50.0," + BR 
+                        + "      date=2014.10.15" + BR 
+                        + "    ]" + BR 
+                        + "  }" + BR 
+                        + "]";
+        assertEquals(expected, toString(acc));
+    }
+
+    @Test
+    public void noArray() {
+        WithArrays wa = new WithArrays();
+        String exp = getClassPrefix(wa) + "[" + BR 
+                   + "  boolArray=<null>," + BR 
+                   + "  charArray=<null>," + BR
+                   + "  intArray=<null>," + BR 
+                   + "  doubleArray=<null>," + BR 
+                   + "  longArray=<null>," + BR 
+                   + "  stringArray=<null>" + BR 
+                   + "]";
+        assertEquals(exp, toString(wa));
+    }
+
+    @Test
+    public void boolArray() {
+        WithArrays wa = new WithArrays();
+        wa.boolArray = new boolean[] { true, false, true };
+        String exp = getClassPrefix(wa) + "[" + BR 
+                   + "  boolArray={" + BR 
+                   + "    true," + BR 
+                   + "    false," + BR 
+                   + "    true" + BR 
+                   + "  }," + BR 
+                   + "  charArray=<null>," + BR 
+                   + "  intArray=<null>," + BR 
+                   + "  doubleArray=<null>," + BR
+                   + "  longArray=<null>," + BR 
+                   + "  stringArray=<null>" + BR 
+                   + "]";
+        assertEquals(exp, toString(wa));
+    }
+
+    @Test
+    public void charArray() {
+        WithArrays wa = new WithArrays();
+        wa.charArray = new char[] { 'a', 'A' };
+        String exp = getClassPrefix(wa) + "[" + BR 
+                   + "  boolArray=<null>," + BR 
+                   + "  charArray={" + BR 
+                   + "    a," + BR 
+                   + "    A" + BR 
+                   + "  }," + BR 
+                   + "  intArray=<null>," + BR 
+                   + "  doubleArray=<null>," + BR 
+                   + "  longArray=<null>," + BR
+                   + "  stringArray=<null>" + BR 
+                   + "]";
+        assertEquals(exp, toString(wa));
+    }
+
+    @Test
+    public void intArray() {
+        WithArrays wa = new WithArrays();
+        wa.intArray = new int[] { 1, 2 };
+        String exp = getClassPrefix(wa) + "[" + BR 
+                   + "  boolArray=<null>," + BR 
+                   + "  charArray=<null>," + BR 
+                   + "  intArray={" + BR 
+                   + "    1," + BR 
+                   + "    2" + BR 
+                   + "  }," + BR 
+                   + "  doubleArray=<null>," + BR 
+                   + "  longArray=<null>," + BR
+                   + "  stringArray=<null>" + BR 
+                   + "]";
+        assertEquals(exp, toString(wa));
+    }
+
+    @Test
+    public void doubleArray() {
+        WithArrays wa = new WithArrays();
+        wa.doubleArray = new double[] { 1, 2 };
+        String exp = getClassPrefix(wa) + "[" + BR 
+                   + "  boolArray=<null>," + BR 
+                   + "  charArray=<null>," + BR
+                   + "  intArray=<null>," + BR 
+                   + "  doubleArray={" + BR 
+                   + "    1.0," + BR 
+                   + "    2.0" + BR 
+                   + "  }," + BR
+                   + "  longArray=<null>," + BR 
+                   + "  stringArray=<null>" + BR 
+                   + "]";
+        assertEquals(exp, toString(wa));
+    }
+
+    @Test
+    public void longArray() {
+        WithArrays wa = new WithArrays();
+        wa.longArray = new long[] { 1L, 2L };
+        String exp = getClassPrefix(wa) + "[" + BR 
+                   + "  boolArray=<null>," + BR 
+                   + "  charArray=<null>," + BR
+                   + "  intArray=<null>," + BR 
+                   + "  doubleArray=<null>," + BR 
+                   + "  longArray={" + BR 
+                   + "    1," + BR 
+                   + "    2" + BR
+                   + "  }," + BR 
+                   + "  stringArray=<null>" + BR 
+                   + "]";
+        assertEquals(exp, toString(wa));
+    }
+
+    @Test
+    public void stringArray() {
+        WithArrays wa = new WithArrays();
+        wa.stringArray = new String[] { "a", "A" };
+        String exp = getClassPrefix(wa) + "[" + BR 
+                   + "  boolArray=<null>," + BR 
+                   + "  charArray=<null>," + BR
+                   + "  intArray=<null>," + BR 
+                   + "  doubleArray=<null>," + BR 
+                   + "  longArray=<null>," + BR 
+                   + "  stringArray={" + BR
+                   + "    a," + BR 
+                   + "    A" + BR 
+                   + "  }" + BR 
+                   + "]";
+        assertEquals(exp, toString(wa));
+    }
+
+    private String getClassPrefix(Object object) {
+        return object.getClass().getName() + "@" + 
Integer.toHexString(System.identityHashCode(object));
+    }
+
+    private String toString(Object object) {
+        return new ReflectionToStringBuilder(object, new 
MultilineRecursiveToStringStyle()).toString();
+    }
+
+    static class WithArrays {
+        boolean[] boolArray;
+        char[] charArray;
+        int[] intArray;
+        double[] doubleArray;
+        long[] longArray;
+        String[] stringArray;
+    }
+
+    static class Bank {
+        String name;
+
+        public Bank(String name) {
+            this.name = name;
+        }
+    }
+
+    static class Customer {
+        String name;
+        Bank bank;
+        List<Account> accounts;
+
+        public Customer(String name) {
+            this.name = name;
+        }
+    }
+
+    static class Account {
+        Customer owner;
+        List<Transaction> transactions = new ArrayList<Transaction>();
+
+        public double getBalance() {
+            double balance = 0;
+            for (Transaction tx : transactions) {
+                balance += tx.amount;
+            }
+            return balance;
+        }
+    }
+
+    static class Transaction {
+        double amount;
+        String date;
+
+        public Transaction(String datum, double betrag) {
+            this.date = datum;
+            this.amount = betrag;
+        }
+    }
+
+}

Propchange: 
commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL


Reply via email to