Search code examples
javajooq

Using row() in jooq to map result into custom seekStep class


Since I don't want to use RecordX class (in my case I am returning 11 fields from query) I've created custom mapper to map SelectSeekStep result into it. The problem occurs when I have fields that are part of joined table. E.g.

@Value
public class CustomMapperSelectSeekStep {
  private final String field1;
  private final String field2;
  private final String field3;
  private final String field4;
  private final String field5;
  private final String field6;
  private final String field7;
  private final String test_id;
  private final String field9;
  private final String field10;
}

Let's say that all fields except test_id fields are part of main table (let's call it dummy) and that field is part of test table which we will connect with left join.

dslContext
.select(
row(DUMMY.FIELD1,
    DUMMY.FIELD2,
    DUMMY.FIELD3,
    DUMMY.FIELD4,
    DUMMY.FIELD5,
    DUMMY.FIELD6,
    DUMMY.FIELD7,
    TEST.TEST_NAME,
    DUMMY.FIELD8,
    DUMMY.FIELD9,
    DUMMY.FIELD10).mapping(CustomMapperSelectSeekStep::new))
.from(DUMMY)
.leftJoin(TEST).on(TEST.ID.eq(DUMMY.TEST_ID))
.orderBy(DUMMY.FIELD1);

Exception I am getting:

java.lang.IllegalArgumentException: Field ("test"."test_name") is not contained in Row 
(row (
"DUMMY"."FIELD1",
"DUMMY"."FIELD2",
"DUMMY"."FIELD3",
"DUMMY"."FIELD4",
"DUMMY"."FIELD5",
"DUMMY"."FIELD6",
"DUMMY"."FIELD7",
"DUMMY"."FIELD8",
"TEST"."TEST_NAME",
"DUMMY"."FIELD9",
"DUMMY"."FIELD10"
))  

UPDATE: added entire method call:

dslContext.transaction(configuration -> {
DSLContext localDsl = DSL.using(configuration);
try (Cursor<Record1<CustomMapperSelectSeekStep>> records = 
selectRecords(localDsl)
    .fetchSize(1000)
    .resultSetType(ResultSet.TYPE_FORWARD_ONLY)
    .resultSetConcurrency(ResultSet.CONCUR_READ_ONLY)
    .fetchLazy()) {
        processRecords(records);
    }
});
//method
private SelectSeekStep1<Record1<CustomMapperSelectSeekStep>,Timestamp> selectRecords(DSLContext dslContext) {
return dslContext.select(
    row(DUMMY.FIELD1,
        DUMMY.FIELD2,
        DUMMY.FIELD3,
        DUMMY.FIELD4,
        DUMMY.FIELD5,
        DUMMY.FIELD6,
        DUMMY.FIELD7,
        TEST.TEST_NAME,
        DUMMY.FIELD8,
        DUMMY.FIELD9,
        DUMMY.FIELD10).mapping(CustomMapperSelectSeekStep::new))
    .from(DUMMY)
    .leftJoin(TEST).on(TEST.ID.eq(DUMMY.TEST_ID))
    .orderBy(DUMMY.FIELD1);
    }

Inside process record I am mapping Record objects to desired object type.

void processRecords(List<Records> records) {
record.map(recordMapper);
} 

I have custom recordMapper implementation where i am doing logic like this:

testName = record.get(TEST.TEST_NAME, Test.class);

Stack trace:

    at org.jooq.impl.Tools.indexFail(Tools.java:1769)
at org.jooq.impl.AbstractRecord.get(AbstractRecord.java:331)
at org.jooq.impl.AbstractRecord.get(AbstractRecord.java:336)
at org.test.CustomMapper.map(CustomMapper.java:42)
at org.test.CustomMapper.map(CustomMapper.java:16)
at org.jooq.impl.AbstractRecord.map(AbstractRecord.java:904)
at org.test.Processor.processRecords(Processor.java:88)
at org.test.Repository.lambda$fetchLazy$0(Repository.java:78)
at org.jooq.impl.DefaultDSLContext.lambda$transaction$5(DefaultDSLContext.java:611)
at org.jooq.impl.DefaultDSLContext.lambda$transactionResult0$3(DefaultDSLContext.java:549)

Solution

  • The problem is that you've nested your record to have a type like this

    Cursor<Record1<CustomMapperSelectSeekStep>>
    

    When you thought you had a type like this:

    Cursor<Record10<T1, T2, ..., T10>>
    

    In the latter case, you could simply extract the projected column like you did:

    record.get(TEST.TEST_NAME);
    

    But when you have a nested record, that column no longer exists, it's nested in an anonymous Record1<?> type. Not only that, but because you used an ad-hoc converter using convertFrom(), there's no nested record anymore, but jOOQ projected your custom POJO type CustomMapperSelectSeekStep for you.

    So, just read your value like this:

    void processRecords(List<Record1<CustomMapperSelectSeekStep>> records) {
        for (Record1<CustomMapperSelectSeekStep> record : records) {
            CustomMapperSelectSeekStep pojo : record.value1();
        }
    }