JDBI 3 Nested object with lombok

733 Views Asked by At

First of all, I already tried this JDBI 3: Nested SQLObject and it didn't work

I'm trying basically the same thing as the other person, to gather some nested objects in jdbi 3 but using RegisterConstructorMapper instead.

This is my code:

ClassA.java

@Value
@AllArgsConstructor
@Jacksonized
@Builder(toBuilder = true)
public class ClassA {

    @Nested
    ClassB classB;
    String someString;
}

ClassB.java

@Value
@AllArgsConstructor
@Jacksonized
@Builder(toBuilder = true)
public class ClassB {
    Long id;
}

The code in my dao:

@SqlQuery("""
SELECT
    a.some_string as someString,
    b.id as b_id
FROM table_a a
INNER JOIN table_b b on a.b_id = b.id
WHERE a.id = :id
""")
@RegisterConstructorMapper(value = ClassB.class, prefix = "b")
@RegisterConstructorMapper(ClassA.class)
Optional<ClassA> findClassA(long id);

But when I run the code I keep getting this error:

Instance factory 'public com.blah.ClassA(com.blah.ClassB,java.lang.String)' parameter '[classB]' has no matching columns in the result set. Verify that the Java compiler is configured to emit parameter names, that your result set has the columns expected, annotate the parameter names explicitly with @ColumnName, or annotate nullable parameters as @Nullable Blockquote Blockquote

2

There are 2 best solutions below

0
On

What you need is a row reducer. With a join you will get the same A for every B (that is for an left join the default). You have an inner join so not sure if that is true for this case but I think your problem will be solved with a row reducer. Something like this:

    class AReducer implements LinkedHashMapRowReducer<Integer, ClassA> {
    @Override
    public void accumulate(Map<Integer, ClassA> map, RowView rowView) {
        ClassA a = map.computeIfAbsent(
                rowView.getColumn("id", Integer.class),
                id -> rowView.getRow(ClassA.class));

        final ClassB b= rowView.getRow(ClassB.class);
        if (b != null ) {
            a.setB(b);
        }
    }
}

and add the reducer to your method:

     @UseRowReducer(AReducer.class)
0
On

I encountered the same problem and found your post when trying to solve it. Incase you still haven't found a workaround, what I did was use mutable mapperobjects so that I was able to use BeanMapper instead of ConstructorMapper, which I then passed to my immutable @Value objects after doing the reduction.