[jOOQ/jOOQ#15085] Confusing error message when reading a non-existing

Field from a Record containing accidentally nested row types
This commit is contained in:
Lukas Eder 2024-05-28 10:04:56 +02:00
parent 6a42a7e888
commit d47a597431
4 changed files with 58 additions and 8 deletions

View File

@ -386,7 +386,7 @@ implements
if (index >= 0 && index < values.length)
return index;
throw new IllegalArgumentException("No field at index " + index + " in Record type " + fields);
throw indexFail(fields, index);
}
/**

View File

@ -38,9 +38,11 @@
package org.jooq.impl;
import static org.jooq.impl.DSL.row;
import static org.jooq.impl.QueryPartListView.wrap;
import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.converterOrFail;
import static org.jooq.impl.Tools.indexFail;
import static org.jooq.impl.Tools.indexOrFail;
import static org.jooq.impl.Tools.map;
import static org.jooq.impl.Tools.newRecord;
@ -78,7 +80,14 @@ import org.jooq.tools.JooqLogger;
*
* @author Lukas Eder
*/
final class FieldsImpl<R extends Record> extends AbstractQueryPart implements RecordType<R>, Mappable<R>, UTransient {
final class FieldsImpl<R extends Record>
extends
AbstractQueryPart
implements
RecordType<R>,
Mappable<R>,
UTransient
{
private static final JooqLogger log = JooqLogger.getLogger(FieldsImpl.class);
Field<?>[] fields;
@ -407,7 +416,7 @@ final class FieldsImpl<R extends Record> extends AbstractQueryPart implements Re
if (index >= 0 && index < fields.length)
return index;
throw new IllegalArgumentException("No field at index " + index + " in Record type " + fields);
throw indexFail(this, index);
}
@Override
@ -660,4 +669,9 @@ final class FieldsImpl<R extends Record> extends AbstractQueryPart implements Re
public int hashCode() {
return Arrays.hashCode(fields);
}
@Override
public String toString() {
return row(fields).toString();
}
}

View File

@ -40,6 +40,7 @@ package org.jooq.impl;
import static org.jooq.Records.intoList;
import static org.jooq.Records.intoResultGroups;
import static org.jooq.impl.Tools.indexFail;
import static org.jooq.impl.Tools.indexOrFail;
import java.lang.reflect.Array;
@ -1068,7 +1069,7 @@ final class ResultImpl<R extends Record> extends AbstractResult<R> implements Re
if (index >= 0 && index < fields.size())
return index;
throw new IllegalArgumentException("No field at index " + index + " in Record type " + fields);
throw indexFail(fields, index);
}
// -------------------------------------------------------------------------

View File

@ -2238,7 +2238,26 @@ final class Tools {
}
static final IllegalArgumentException indexFail(Fields row, Field<?> field) {
return new IllegalArgumentException("Field (" + field + ") is not contained in Row " + row);
if (lookupNested(row, field))
return new IllegalArgumentException("Field " + field + " is not contained at the top level of row type containing nested row types. Unnest the nested row type first and access the field from there: " + row);
else
return new IllegalArgumentException("Field " + field + " is not contained in row type " + row);
}
private static final boolean lookupNested(Fields row, Field<?> field) {
// [#15085] [#16721] Help users spot the problem if they accidentally nest row types
if (row.field(field) != null)
return true;
for (Field<?> f : row.fields()) {
if (f instanceof AbstractRowAsField<?> rf) {
if (lookupNested(rf.fields0(), field))
return true;
}
}
return false;
}
static final int indexOrFail(Fields row, Field<?> field) {
@ -2251,7 +2270,7 @@ final class Tools {
}
static final IllegalArgumentException indexFail(Fields row, String fieldName) {
throw new IllegalArgumentException("Field (" + fieldName + ") is not contained in Row " + row);
return indexFail(row, DSL.name(fieldName));
}
static final int indexOrFail(Fields row, String fieldName) {
@ -2264,7 +2283,7 @@ final class Tools {
}
static final IllegalArgumentException indexFail(Fields row, Name fieldName) {
throw new IllegalArgumentException("Field (" + fieldName + ") is not contained in Row " + row);
return indexFail(row, DSL.field(fieldName));
}
static final int indexOrFail(Fields row, Name fieldName) {
@ -2277,7 +2296,23 @@ final class Tools {
}
static final IllegalArgumentException indexFail(Fields row, int fieldIndex) {
throw new IllegalArgumentException("Field (" + fieldIndex + ") is not contained in Row " + row);
if (fieldIndex < countFlattened(row, 0))
return new IllegalArgumentException("No field at index " + fieldIndex + " is not contained at the top level of row type containing nested row types. Unnest the nested row types first and access the field from there: " + row);
else
return new IllegalArgumentException("No field at index " + fieldIndex + " in row type " + row);
}
private static final int countFlattened(Fields row, int count) {
// [#15085] [#16721] Help users spot the problem if they accidentally nest row types
for (Field<?> f : row.fields()) {
if (f instanceof AbstractRowAsField<?> rf)
count += countFlattened(rf.fields0(), count);
else
count++;
}
return count;
}
static final int indexOrFail(Fields row, int fieldIndex) {