-
-
Notifications
You must be signed in to change notification settings - Fork 263
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2642 from ebean-orm/feature/2641-ToStringBuilder
#2641 - Provide a decent default toString() implementation for entity beans
- Loading branch information
Showing
15 changed files
with
447 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package io.ebean.bean; | ||
|
||
/** | ||
* A type that can participate in building toString content with ToStringBuilder. | ||
*/ | ||
public interface ToStringAware { | ||
|
||
/** | ||
* Append to the ToStringBuilder. | ||
*/ | ||
void toString(ToStringBuilder builder); | ||
} |
163 changes: 163 additions & 0 deletions
163
ebean-api/src/main/java/io/ebean/bean/ToStringBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
package io.ebean.bean; | ||
|
||
import java.util.Collection; | ||
import java.util.IdentityHashMap; | ||
|
||
/** | ||
* Helps build toString content taking into account recursion. | ||
* <p> | ||
* That is, it detects and handles the case where there are relationships that recurse | ||
* and would otherwise become an infinite loop (e.g. bidirectional parent child). | ||
*/ | ||
public final class ToStringBuilder { | ||
|
||
/** | ||
* The max number of objects that we allow before stopping content being appended. | ||
*/ | ||
private static final int MAX = 100; | ||
|
||
/** | ||
* Max length of content in string form added for any given value. | ||
*/ | ||
private static final int TRIM_LENGTH = 500; | ||
|
||
/** | ||
* The max total content after which we stop content being appended. | ||
*/ | ||
private static final int MAX_TOTAL_CONTENT = 2000; | ||
|
||
private final IdentityHashMap<Object, Integer> id = new IdentityHashMap<>(); | ||
private final StringBuilder sb = new StringBuilder(50); | ||
private boolean first = true; | ||
private int counter; | ||
|
||
@Override | ||
public String toString() { | ||
return sb.toString(); | ||
} | ||
|
||
/** | ||
* Set of an object being added. | ||
*/ | ||
public void start(Object bean) { | ||
if (counter == 0) { | ||
id.putIfAbsent(bean, 0); | ||
} | ||
if (counter <= MAX) { | ||
sb.append(bean.getClass().getSimpleName()).append("@").append(counter).append("("); | ||
} | ||
} | ||
|
||
/** | ||
* Add a property as name value pair. | ||
*/ | ||
public void add(String name, Object value) { | ||
if (value != null && counter <= MAX) { | ||
if (value instanceof BeanCollection) { | ||
if (((BeanCollection<?>)value).isReference()) { | ||
// suppress unloaded bean collections | ||
return; | ||
} | ||
} | ||
key(name); | ||
value(value); | ||
} | ||
} | ||
|
||
/** | ||
* Add raw content. | ||
*/ | ||
public void addRaw(String content) { | ||
sb.append(content); | ||
} | ||
|
||
/** | ||
* End of an object. | ||
*/ | ||
public void end() { | ||
if (counter <= MAX) { | ||
sb.append(")"); | ||
} | ||
} | ||
|
||
private void key(String name) { | ||
if (counter > MAX) { | ||
return; | ||
} | ||
if (first) { | ||
first = false; | ||
} else { | ||
sb.append(", "); | ||
} | ||
sb.append(name).append(":"); | ||
} | ||
|
||
private void value(Object value) { | ||
if (counter > MAX) { | ||
return; | ||
} | ||
if (value instanceof ToStringAware) { | ||
if (value instanceof BeanCollection) { | ||
((ToStringAware) value).toString(this); | ||
} else if (push(value)) { | ||
((ToStringAware) value).toString(this); | ||
} | ||
} else if (value instanceof Collection) { | ||
addCollection((Collection<?>) value); | ||
} else { | ||
String content = String.valueOf(value); | ||
if (content.length() > TRIM_LENGTH) { | ||
content = content.substring(0, TRIM_LENGTH) + " <trimmed>"; | ||
} | ||
sb.append(content); | ||
if (sb.length() >= MAX_TOTAL_CONTENT) { | ||
sb.append(" ..."); | ||
counter += MAX; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Add a collection of values. | ||
*/ | ||
public void addCollection(Collection<?> c) { | ||
if (c == null || c.isEmpty()) { | ||
sb.append("[]"); | ||
return; | ||
} | ||
boolean firstElement = true; | ||
sb.append("["); | ||
for (Object o : c) { | ||
if (firstElement) { | ||
firstElement = false; | ||
} else { | ||
sb.append(", "); | ||
} | ||
value(o); | ||
if (counter > MAX) { | ||
return; | ||
} | ||
} | ||
sb.append("]"); | ||
} | ||
|
||
private boolean push(Object bean) { | ||
if (counter > MAX) { | ||
return false; | ||
} | ||
if (counter == MAX) { | ||
sb.append(" ..."); | ||
counter++; | ||
return false; | ||
} | ||
Integer idx = id.putIfAbsent(bean, counter++); | ||
if (idx != null) { | ||
--counter; | ||
sb.append(bean.getClass().getSimpleName()).append("@").append(idx); | ||
return false; | ||
} | ||
first = true; | ||
return true; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.