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
This commit is contained in:
parent
85c18d0ee8
commit
635e41ea18
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
* name=Stephen, <br>
|
||||
* age=29, <br>
|
||||
* smoker=false, <br>
|
||||
* job=Job@43cd2[ <br>
|
||||
* title=Manager <br>
|
||||
* ] <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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue