[#3900] Implement better formatting for nested Records
This commit is contained in:
parent
7a3e9fbd47
commit
0ad56f5385
@ -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
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user