Lombok has introduced experimental features with version: 1.18.2 for inheritance issues faced with Builder annotation, and can be resolved with @SuperBuilder annotation as below.
@SuperBuilder
public class ParentClass {
private final String a;
private final String b;
}
@SuperBuilder
public class ChildClass extends ParentClass{
private final String c;
}
Now, one can use Builder class as below (that was not possible with @Builder annotation)
ChildClass.builder().a("testA").b("testB").c("testC").build();
Answer from Amit Kaneria on Stack OverflowLombok has introduced experimental features with version: 1.18.2 for inheritance issues faced with Builder annotation, and can be resolved with @SuperBuilder annotation as below.
@SuperBuilder
public class ParentClass {
private final String a;
private final String b;
}
@SuperBuilder
public class ChildClass extends ParentClass{
private final String c;
}
Now, one can use Builder class as below (that was not possible with @Builder annotation)
ChildClass.builder().a("testA").b("testB").c("testC").build();
I leave this here for reference, as other answers demonstrate there is now (not at the time this answer was posted) a @SuperBuilder feature available now in the library which seems more fitting.
It´s a bit hidden, but people have had this question before, see:
https://reinhard.codes/2015/09/16/lomboks-builder-annotation-and-inheritance/
To summarise the blog post
@AllArgsConstructor
public class Parent {
private String a;
}
public class Child extends Parent {
private String b;
@Builder
private Child(String a, String b){
super(a);
this.b = b;
}
}
Would allow you to use
Child.builder().a("testA").b("testB").build()
java - Lombok @Builder with inheritance that requires a certain field - Stack Overflow
java - Lombok @builder on a class that extends another class - Stack Overflow
java - Inheritance for builders in lombok - Stack Overflow
java - Lombok @Builder inheritance for 3 Classes - Stack Overflow
Since you can't use @SuperBuilder annotation, beacause you don't have access to ApplicationEvent class, as far as I can see, the only solution is to do something like following:
Assume that you have TrackedEvent class wich looks something like this:
public class TrackedEvent extends ApplicationEvent {
protected String correlationId;
protected String description;
public TrackedEvent(Object source, String correlationId, String description) {
super(source);
this.correlationId = correlationId;
this.description = description;
}
public TrackedEvent(Object source) {
super(source);
}
}
And you have OperationalEvent class wich extends above class.
Than, you can implement builder pattern in OptionalEvent class like this:
public class OperationalEvent extends TrackedEvent {
private String type;
private String status;
public OperationalEvent(Object source) {
super(source);
}
@Builder(builderMethodName = "optionalEvent")
public OperationalEvent(Object source, String correlationId, String description, String type, String status) {
super(source, correlationId, description);
this.type = type;
this.status = status;
}
@Override
public String toString() {
return "OperationalEvent{" +
"type='" + type + '\'' +
", status='" + status + '\'' +
"correlationId:" + correlationId +
'}';
}
}
And than the following code should work as expected:
public static void main(String[] args) {
ApplicationEvent applicationEvent = new ApplicationEvent(new Object()) {
@Override
public Object getSource() {
return super.getSource();
}
};
OperationalEvent opsEvent = OperationalEvent.optionalEvent()
.description("something happened")
.source(applicationEvent)
.status("status")
.correlationId("1")
.build();
}
You can use @SuperBuilder together with an intermediate abstract class, as described here.
The advantage over using customized @Builders is that you only have to manually implement this single custom intermediate class once. There is no need for customization in every subclass.
In this case, the intermediate class looks as follows:
public abstract class ApplicationEventSuperBuilderEnabler extends ApplicationEvent {
public static abstract class ApplicationEventSuperBuilderEnablerBuilder<C extends ApplicationEventSuperBuilderEnabler, B extends ApplicationEventSuperBuilderEnablerBuilder<C, B>> {
private Object source;
public B source(Object source) {
this.source = source;
return self();
}
protected abstract B self();
public abstract C build();
}
protected ApplicationEventSuperBuilderEnabler(ApplicationEventSuperBuilderEnablerBuilder<?, ?> b) {
super(b.source);
}
}
Next, let all your direct subclasses extend ApplicationEventSuperBuilderEnabler (instead of ApplicationEvent) and put a @SuperBuilder on all classes:
@SuperBuilder
public abstract class TrackedEvent extends ApplicationEventSuperBuilderEnabler { ... }
@SuperBuilder
public class OperationalEvent extends TrackedEvent { ... }
Now you can use it like this:
OperationalEvent opsEvent = OperationalEvent.builder()
.source(this)
.description("something happened")
.status(OperationalStatus.THE_THING)
.build();
Since release 1.18.2 lombok includes the new experimental @SuperBuilder. It supports fields from superclasses (also abstract ones). With it, the solution is as simple as this:
@SuperBuilder
public class Child extends Parent {
private String a;
private int b;
private boolean c;
}
@SuperBuilder
public class Parent {
private double d;
private float e;
}
Child instance = Child.builder().b(7).e(6.3).build();
Update 2019-10-09: If you use IntelliJ, you need at least version 0.27 of the IntelliJ Lombok plugin to use @SuperBuilder.
PS: @AllArgsConstructor(onConstructor=@__(@Builder)) does not work because @Builder is an annotation-processing annotation that lombok translates to code during compilation. Generating and then translating new lombok annotation would require several iterations of annotation processing, and lombok does not support that. @Autowired, in contrast, is a regular Java annotation available at runtime.
See in https://blog.codecentric.de/en/2016/05/reducing-boilerplate-code-project-lombok/ (@Builder and inheritance part)
Adjusted to your classes
@AllArgsConstructor
public class Parent {
private double d;
private float e;
}
public class Child extends Parent {
private String a;
private int b;
private boolean c;
@Builder
public Child(String a, int b, boolean c, double d, float e) {
super(d, e);
this.a = a;
this.b = b;
this.c = c;
}
}
With this setup
Child child = Child.builder().a("aVal").b(1000).c(true).d(10.1).e(20.0F).build();
works correctly
Here we just need to call super of the builder.
@Data
public class B extends A {
Integer b1;
@Builder
public B(Integer b1, Integer a1) {
super(a1);
this.b1 = b1;
}
public static class BBuilder extends ABuilder{
BBuilder() {
super();
}
}
}
Both child and parent should be marked with @SuperBuilder.
Having both parent and child as @Builder won't work.
Parent class A:
@Data
@SuperBuilder
public class A {
Integer a1;
}
Child class B:
@Data
@SuperBuilder
public class B extends A {
Integer b1;
}