I have a similar but slightly different use case. In my case, I have a chain of abstract superclasses that build and execute queries. Different queries have common parameters, but not every query supports all parameters. Builders for specific queries should only provide methods for setting the supported parameters for a given query.
I started working with a constructor-based implementation of the constructor, but this led to too much code template, especially if you have many fields to configure. Now I have come up with the following solutions that look a lot cleaner for me.
Basically, specific subclasses define the actual fields that Builder must support, and the Getter annotation overrides the corresponding methods in the superclass. Getters in abstract superclasses can even be defined as abstract to require specific implementations to define these fields.
public abstract class AbstractSuperClass1 { protected String getParamA() { return "defaultValueA"; } public final void doSomething() { System.out.println(getParamA()); doSomeThingElse(); } protected abstract void doSomeThingElse(); }
public abstract class AbstractSuperClass2 extends AbstractSuperClass1 { protected String getParamB() { return "defaultValueB"; } protected void doSomeThingElse() { System.out.println(getParamB()); } }
import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @Getter(AccessLevel.PROTECTED) @Builder public class ConcreteClass1 extends AbstractSuperClass2 { private final String paramA;
import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @Getter(AccessLevel.PROTECTED) @Builder public class ConcreteClass2 extends AbstractSuperClass2 { private final String paramA; private final String paramB; public static void main(String[] args) { ConcreteClass2.builder() .paramA("NonDefaultValueA").paramB("NonDefaultValueB") .build().doSomething(); } }
source share