[#3900] Implement better formatting for nested Records

This commit is contained in:
Lukas Eder 2015-01-06 11:59:11 +01:00
parent 7a3e9fbd47
commit 0ad56f5385
2 changed files with 69 additions and 3 deletions

View File

@ -51,6 +51,7 @@ import static org.jooq.impl.Utils.hasColumnAnnotations;
import static org.jooq.impl.Utils.indexOrFail;
import static org.jooq.impl.Utils.resetChangedOnNotNull;
import static org.jooq.impl.Utils.settings;
import static org.jooq.impl.Utils.ThreadGuard.Guard.RECORD_TOSTRING;
import java.lang.reflect.Method;
import java.sql.ResultSet;
@ -95,6 +96,8 @@ import org.jooq.Table;
import org.jooq.UniqueKey;
import org.jooq.exception.InvalidResultException;
import org.jooq.exception.MappingException;
import org.jooq.impl.Utils.ThreadGuard;
import org.jooq.impl.Utils.ThreadGuard.GuardedOperation;
import org.jooq.tools.Convert;
import org.jooq.tools.StringUtils;
@ -970,9 +973,20 @@ abstract class AbstractRecord extends AbstractStore implements Record {
@Override
public String toString() {
Result<AbstractRecord> result = new ResultImpl<AbstractRecord>(configuration(), fields.fields.fields);
result.add(this);
return result.toString();
// [#3900] Nested records should generate different toString() behaviour
return ThreadGuard.run(RECORD_TOSTRING, new GuardedOperation<String>() {
@Override
public String unguarded() {
Result<AbstractRecord> result = new ResultImpl<AbstractRecord>(configuration(), fields.fields.fields);
result.add(AbstractRecord.this);
return result.toString();
}
@Override
public String guarded() {
return valuesRow().toString();
}
});
}
@Override

View File

@ -1845,6 +1845,58 @@ final class Utils {
// XXX: [#2965] Reflection cache
// ------------------------------------------------------------------------
/**
* This API acts as a "guard" to prevent the same code from being executed
* recursively within the same thread.
*/
static class ThreadGuard {
/**
* The type of guard.
*/
static enum Guard {
RECORD_TOSTRING;
ThreadLocal<Object> tl = new ThreadLocal<Object>();
}
/**
* A guarded operation.
*/
static interface GuardedOperation<V> {
/**
* This callback is executed only once on the current stack.
*/
V unguarded();
/**
* This callback is executed if {@link #unguarded()} has already been executed on the current stack.
*/
V guarded();
}
/**
* Run an operation using a guard.
*/
static final <V> V run(Guard guard, GuardedOperation<V> operation) {
boolean unguarded = (guard.tl.get() != null);
if (unguarded)
guard.tl.set(Guard.class);
try {
if (unguarded)
return operation.unguarded();
else
return operation.guarded();
}
finally {
if (unguarded)
guard.tl.remove();
}
}
}
/**
* [#2965] This is a {@link Configuration}-based cache that can cache reflection information and other things
*/