I'm trying to implement a BuilderPattern, where a subclass must extend a superclass.
Superclass:
@Getter
public abstract class CommonValidatorConfig<VC extends CommonValidatorConfig<VC>> {
private boolean canBeNull;
private boolean canBeEmpty;
public static abstract class CommonValidatorConfigBuilder<VC, VCB extends CommonValidatorConfigBuilder<VC, VCB>> {
protected boolean canBeNull;
protected boolean canBeEmpty;
@SuppressWarnings("unchecked")
public VCB canBeNull(boolean canBeNull) {
this.canBeNull = canBeNull;
return (VCB) this;
}
@SuppressWarnings("unchecked")
public VCB canBeEmpty(boolean canBeEmpty) {
this.canBeEmpty = canBeEmpty;
return (VCB) this;
}
@SuppressWarnings("unchecked")
public VCB setDefault() {
this.canBeNull = false;
this.canBeEmpty = false;
return (VCB) this;
}
public abstract VC build();
}
}
Subclass:
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class StringValidatorConfig extends CommonValidatorConfig<StringValidatorConfig> {
public static class StringValidatorConfigBuilder extends CommonValidatorConfigBuilder<StringValidatorConfig, StringValidatorConfigBuilder> {
@Override
public StringValidatorConfig build() {
return new StringValidatorConfig(false, false); // ERROR
}
}
}
The AllArgsConstructor AccessLevel is set to PRIVATE because I want to create a new instance using only Builders.
I was expecting an AllArgsConstructor for StringValidatorConfig with two variables (canBeNull and canBeEmpty), but the AllArgsConstructor takes no arguments for the constructor.
this means that the variables of the CommonValidatorConfig are not inherited.
Any help, also tutorials/docs/references or improvements of code are welcomed.
@SuperBuilder
will do all the work for you:
@Getter
@SuperBuilder
public abstract class CommonValidatorConfig {
private boolean canBeNull;
private boolean canBeEmpty;
}
@SuperBuilder
public class StringValidatorConfig extends CommonValidatorConfig {
}
That's it.
If you need to add a custom method inside your builder, you can do so by adding the class header of the (abstract) builder class and add your method. Lombok will add all the rest of its methods. I suggest you copy the class header from the delombok output (run java -jar path/to/lombok.jar delombok -p path/to/ClassWithSuperBuilder.java
).
@Getter
@SuperBuilder
public abstract class CommonValidatorConfig {
private boolean canBeNull;
private boolean canBeEmpty;
public static abstract class CommonValidatorConfigBuilder<C extends CommonValidatorConfig, B extends CommonValidatorConfig.CommonValidatorConfigBuilder<C, B>> {
public B setDefault() {
this.canBeNull = false;
this.canBeEmpty = false;
return self();
}
}
}
The "experimental" status of @SuperBuilder
just means it may not receive bugfixes as quickly as stable features. Furthermore, there are plans to promote @SuperBuilder
to stable.
The code Lombok generates is completely type-safe, there are no unchecked type conversions. So even if you later decide that you don't want @SuperBuilder
anymore, you can simply de-lombok it. The resulting code will be better than your manual solution.