Home > Enterprise >  How to use generics with @SuperBuilder to common logic to a base class builder?
How to use generics with @SuperBuilder to common logic to a base class builder?

Time:12-23

I have 2 DTOs that share common base - typical inheritance. I also want to use builder pattern, so Lombok's @SuperBuilder comes to the rescue. Now I want to apply common logic to the "common" part of builders.

I am able to do it with casting, but I don't know how to keep it typesafe using generics.

Using following (runnable) example, how to define generics in commonize method so that testGeneric will work and stop yelding compilation errors?

    public class Example {
        static <C extends Base, BUILDER extends Base.BaseBuilder<C, BUILDER>> BUILDER commonize(BUILDER builder) {
            return builder.someName("commonName");
        }
        static < BUILDER extends Base.BaseBuilder> BUILDER rawComminize(BUILDER builder) {
            return (BUILDER)builder.someName("commonName");
        }
    
        static void testGeneric(){
            //that yelds compilation errors - how to fix it?
            Foo foo = commonize(Foo.builder()).fooProp("foo?").build();
            Bar bar = commonize(Bar.builder()).barProp("bar?").build();
            System.out.println(foo);
            System.out.println(bar);
        }
        static void testCasts(){
            //thats fine and works as expected - but not strictly type safe
            Foo foo = rawComminize(Foo.builder()).fooProp("foo?").build();
            Bar bar = rawComminize(Bar.builder()).barProp("bar?").build();
            System.out.println(foo);
            System.out.println(bar);
        }
        public static void main(String[] args) {
            testGeneric();
            testCasts();
        }
    }
    
    @SuperBuilder
    @ToString
    class Base {
        String someName;
    }
    @ToString(callSuper = true)
    @SuperBuilder
    class Foo extends Base {
        String fooProp;
    }
    @ToString(callSuper = true)
    @SuperBuilder
    class Bar extends Base {
        String barProp;
    }

CodePudding user response:

That's quite a tricky one, but you nearly had it. This is way to go:

public static <B extends BUILDER, BUILDER extends Base.BaseBuilder<?, B>> BUILDER commonize(BUILDER builder) {
    return builder.someName("commonName");
}

If you are feeling jaunty today, you may even go further with @ExtensionMethod:

@ExtensionMethod({ Extensions.class })
public class Example {
    static void testGeneric() {
        Foo foo = Foo.builder().commonize().fooProp("foo?").build();
        Bar bar = Bar.builder().commonize().barProp("foo?").build();
        System.out.println(foo);
        System.out.println(bar);
    }
}

class Extensions {
    public static <B extends BUILDER, BUILDER extends Base.BaseBuilder<?, B>> BUILDER commonize(BUILDER builder) {
        return builder.someName("commonName");
    }
}
  • Related