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");
}
}