2つのクラスChild
がParent
を拡張しています。ビルダーを自分で作成する必要がないように、クラスに@Builderアノテーションを配置する必要があります。
package jerry;// Internal compiler error: Java.lang.NullPointerException
import lombok.AllArgsConstructor;
import lombok.Builder;
@AllArgsConstructor(onConstructor=@__(@Builder))
public class Child extends Parent {
//Multiple markers at this line
// - Implicit super constructor Parent() is undefined. Must explicitly invoke another constructor
// - overrides Java.lang.Object.toString
private String a;
private int b;
private boolean c;
}
@Builder
public class Parent {
private double d;
private float e;
}
私はそのような子インスタンスを構築できるようにする必要があります
Child child = Child.builder().a("aVal").b(1000).c(true).d(10.1).e(20.0F).build();
しかし、これまでのところ、コードのコメントというサイドで述べたエラーが発生しています。ロンボクまたは他の同様のライブラリでそれを達成する方法を誰かが正しい方向に向けることができますか?
サブ質問
なぜ@AllArgsConstructor(onConstructor=@__(@Autowired))
はコンパイルされるのに@AllArgsConstructor(onConstructor=@__(@Builder))
はコンパイルされないのですか?
https://blog.codecentric.de/en/2016/05/reducing-boilerplate-code-project-lombok/ (@ Builder and inheritancepart)
クラスに合わせて調整
@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;
}
}
このセットアップで
Child child = Child.builder().a("aVal").b(1000).c(true).d(10.1).e(20.0F).build();
正しく動作します
リリース1.18.2以降、lombokには 新しい実験@SuperBuilder
が含まれています。スーパークラス(抽象クラス)からのフィールドをサポートします。これにより、ソリューションは次のように簡単になります。
@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();
PS:@Builder
はコンパイル中にlombokがコードに変換する注釈処理注釈であるため、@AllArgsConstructor(onConstructor=@__(@Builder))
は機能しません。新しいlombok注釈を生成してから翻訳するには、注釈処理を何度か繰り返す必要がありますが、lombokはそれをサポートしていません。対照的に、@Autowired
は、実行時に使用可能な通常のJava注釈です。
似たようなユースケースがあります。私の場合、リクエストを構築して実行する抽象スーパークラスのチェーンがあります。異なる要求はいくつかの共通パラメーターを共有しますが、すべての要求がすべてのパラメーターをサポートするわけではありません。具体的なリクエストのビルダーは、特定のリクエストでサポートされるパラメーターを設定するためのメソッドのみを提供する必要があります。
コンストラクターベースのビルダーの実装から始めましたが、特に多くのフィールドを構成する必要がある場合は、定型コードが多すぎます。私は今、次の解決策を考え出しました。
基本的に、具象サブクラスは、Builderがサポートする実際のフィールドを定義し、Getterアノテーションにより、対応するスーパークラスメソッドがオーバーライドされます。抽象スーパークラスのゲッターを抽象として定義して、これらのフィールドを定義するための具体的な実装を要求することもできます。
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;
// Not supported by this implementation: private final String paramB;
public static void main(String[] args) {
ConcreteClass1.builder()
.paramA("NonDefaultValueA")
.build().doSomething();
}
}
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();
}
}