aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenedikt Ritter <britter@apache.org>2014-11-09 12:47:12 +0000
committerBenedikt Ritter <britter@apache.org>2014-11-09 12:47:12 +0000
commit635e41ea181c5fee8860a7044c84ae3557b51189 (patch)
tree25af4307eb31d4e40adb24de66ad6f7b917a03f7 /src
parent85c18d0ee864d07081cc2af43d760f752496a7d3 (diff)
downloadapache-commons-lang-635e41ea181c5fee8860a7044c84ae3557b51189.tar.gz
LANG-1052: Multiline recursive to string style. This fixes #34 from github. Thanks to Jan Matèrne.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1637671 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/changes/changes.xml1
-rw-r--r--src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java219
-rw-r--r--src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java264
3 files changed, 484 insertions, 0 deletions
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 2ddb50e8e..501a78b49 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -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>
diff --git a/src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java b/src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java
new file mode 100644
index 000000000..1a0ec05f0
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java
@@ -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
diff --git a/src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java b/src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java
new file mode 100644
index 000000000..abf64f005
--- /dev/null
+++ b/src/test/java/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyleTest.java
@@ -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;
+ }
+ }
+
+}