record-builder icon indicating copy to clipboard operation
record-builder copied to clipboard

Is it possible to provide an interface to the builder?

Open j-bernard opened this issue 9 months ago • 4 comments

Can we make the generated builder implement an interface through an option or by any other means?

j-bernard avatar Apr 14 '25 18:04 j-bernard

I'd need to see an example. If it implements an interface there would have to be an implementation for the methods.

Randgalt avatar Apr 29 '25 09:04 Randgalt

Sure, the idea would be to only provide an interface name. Providing it is crafted correctly, the builder would automatically implement it. Something like this:

@RecordBuilder(implementing="TestInterfaceBuilder")
record Test1WithInterface(String field1, String field2) implements TestInterface {
}

@RecordBuilder(implementing="TestInterfaceBuilder")
record Test2WithInterface(String field1, String field3) implements TestInterface {
}


interface TestInterface {
    String field1();
}


interface TestInterfaceBuilder {
    TestInterfaceBuilder field1(String value);
}

It may also work with a generated interface, by providing the fields you want to be included (@RecordBuilder(withInterfaceFor={"field1"})).

j-bernard avatar Apr 29 '25 13:04 j-bernard

The generated With interface has this. I still don't understand the benefit here.

Randgalt avatar Apr 30 '25 05:04 Randgalt

Sorry for the late reply. My goal is to get multiple builders inheriting a common interface, which I cannot do with the With interface, which is tied to only one builder.

Here is an example that doesn't work due to the missing interface.

public class TestBuilder {

    @RecordBuilder
    record Test1WithInterface(String field1, String field2) implements TestInterface {

    }

    @RecordBuilder
    record Test2WithInterface(String field1, String field3) implements TestInterface {

    }


    interface TestInterface {

        String field1();
    }


    interface TestInterfaceBuilder {

        TestInterfaceBuilder field1(String value);

        <T extends TestInterface> T build();
    }

    static class TestClass<T extends TestInterface> {

        public T compute(TestInterfaceBuilder builder) {
            return builder.field1("value1").build();
        }
    }


    public static void main(String[] args) {
        TestClass<Test1WithInterface> testClass1 = new TestClass<>();
        TestClass<Test2WithInterface> testClass2 = new TestClass<>();
        Test1WithInterface test1 = testClass1.compute(TestBuilderTest1WithInterfaceBuilder.builder().field2("value2"));
        Test2WithInterface test2 = testClass2.compute(TestBuilderTest2WithInterfaceBuilder.builder().field3("value3"));
    }
}

The key point here is the compute method that needs an interface that is implemented by both my builders.

j-bernard avatar Aug 27 '25 16:08 j-bernard