ロンボクでスーパーコンストラクターを呼び出す方法


118

クラスがあります

@Value
@NonFinal
public class A {
    int x;
    int y;
}

私は別のクラスBを持っています

@Value
public class B extends A {
    int z;
}

lombokは、A()コンストラクターを見つけることができないというエラーをスローしています。これを明示的に呼び出して、次のコードを生成するようにクラスbに注釈を付けます。

public class B extends A {
    int z;
    public B( int x, int y, int z) {
        super( x , y );
        this.z = z;
    }
}

ロンボクでそれを行うための注釈はありますか?

回答:


169

これはロンボクでは不可能です。これは本当に素晴らしい機能ですが、スーパークラスのコンストラクターを見つけるには解決が必要です。スーパークラスは、Lombokが呼び出された瞬間にのみ名前で認識されます。importステートメントとクラスパスを使用して実際のクラスを見つけることは簡単ではありません。また、コンパイル中にリフレクションを使用してコンストラクターのリストを取得することはできません。

それは完全に不可能ではないが、結果はで解像度を使用valし、@ExtensionMethodそれが困難でエラーが発生しやすいことを私たちに教えてきました。

情報開示:私はロンボクの開発者です。


@ roel-spilkerその背後にある複雑さを理解しています。しかし、Lombokは、生成されたコンストラクターにLombokが注入するinConstructorコンストラクターを指定できるコンストラクターアノテーションのメソッドを提供できますsuperか?
Manu Manjunath 2016

1
afterConstructorもいくつかの自動初期化を行うとよいでしょう
Pawel

@ Manu / @ Pawel:ロンボク拡張リクエストを参照:github.com/peichhorn/lombok-pg/issues/78 (現在オープン)
JJ Zabkar

@Builderは公式リリースなので、次を参照してください:github.com/rzwitserloot/lombok/issues/853
Sebastian

4
それでも不可能ですか?
FearX

21

Lombok Issue#78はこのページhttps://www.donneo.de/2015/09/16/lomboks-builder-annotation-and-inheritance/を参照しており、次の素敵な説明があります。

@AllArgsConstructor 
public class Parent {   
     private String a; 
}

public class Child extends Parent {
  private String b;

  @Builder
  public Child(String a, String b){
    super(a);
    this.b = b;   
  } 
} 

その結果、生成されたビルダーを次のように使用できます。

Child.builder().a("testA").b("testB").build(); 

公式ドキュメントはこのことを説明するが、それは明示的にあなたがこの方法でそれを容易にすることができることを指摘しません。

また、これがSpring Data JPAでうまく機能することもわかりました。


Spring Data JPAで使用されているこの例を提供できますか?
Marc Zampetti、2016年

29
これは質問にまったく答えません。代わりに、手動で作業を行いますが、問題はそれをどのように生成するかでした。同時に、@ Builderをドラッグすることで全体がさらに混乱しますが、これは質問とは関係ありません。
Jasper

8
実際、これは継承構造を作成してビルダーを使用したいだけの人にとって非常に便利です。これが私がとにかく#lombokを使用する99%の理由です。時々私たちはそれを私たちが望むように機能させるためにものを手作りする必要があるだけです。@ jj-zabkarに感謝します
ババジデプリンス

しかしその後; self + parent argコンストラクタをコーディングするだけです。ビルダーを使用する必要はありません
Juh_

STSとEclipseで動作しますが、アプリケーションのJARファイルを生成すると、おそらく失敗します。SuperBuilderとBuilderを継承してみました。どちらも失敗しました。注意してください !!
P Satish Patro、

6

Lombokは、@Value注釈付きクラスを作成することで示されるfinal(を使用して知っているように@NonFinal)こともサポートしていません。

私が見つけた唯一の回避策は、すべてのメンバーを最終的に宣言し、@Data代わりにアノテーションを使用することです。@EqualsAndHashCodeLombokはスーパークラスのすべての引数を使用して作成する方法を知らないため、これらのサブクラスには注釈を付ける必要があり、明示的にすべての引数のコンストラクターが必要です。

@Data
public class A {
    private final int x;
    private final int y;
}

@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A {
    private final int z;

    public B(int x, int y, int z) {
        super(x, y);
        this.z = z;
    }
}

特に、サブクラスのコンストラクターは、多くのメンバーを持つスーパークラスに対して、解決策を少し整頓していません。


1
「サブクラスに注釈を付ける必要がある」理由をもう少し説明していただけませ@EqualsAndHashCodeんか?この注釈は含まれてい@Dataませんか?Thx :)
ジェラールボッシュ

1
@GerardB @Dataは、equals()とhashCode()も作成しますが、継承については気にしません。必ずスーパークラスが(等しいようにするには)とhashCode()が使用されている、あなたはcallSuperと明示的な世代必要
アルネBurmeister

5

多くのメンバーを持つスーパークラスの場合、@ Delegateを使用することをお勧めします

@Data
public class A {
    @Delegate public class AInner{
        private final int x;
        private final int y;
    }
}

@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A {
    private final int z;

    public B(A.AInner a, int z) {
        super(a);
        this.z = z;
    }
}

これは、そのような興味深いアプローチです。
Arne Burmeister 2017

@Delegateです@Target({ElementType.FIELD, ElementType.METHOD})AInner のフィールドである必要がありますA
boriselec

3

子クラスに親よりも多くのメンバーがある場合、あまりクリーンではなく、短い方法で実行できます。

@Data
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class User extends BaseEntity {
    private @NonNull String fullName;
    private @NonNull String email;
    ... 

    public User(Integer id, String fullName, String email, ....) {
        this(fullName, email, ....);
        this.id = id;
    }
}

@Data
@AllArgsConstructor
abstract public class BaseEntity {
   protected Integer id;

   public boolean isNew() {
      return id == null;
   }
}

3

Lombokのバージョン1.18では、@ SuperBuilderアノテーションが導入されました。これを使用して、問題をより簡単に解決できます。

https://www.baeldung.com/lombok-builder-inheritance#lombok-builder-and-inheritance-3を参照できます

そのため、子クラスでは、次の注釈が必要になります。

@Data
@SuperBuilder
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)

あなたの親クラスで:

@Data
@SuperBuilder
@NoArgsConstructor

0

オプションとして、com.fasterxml.jackson.databind.ObjectMapper親から子クラスを初期化するために使用できます

public class A {
    int x;
    int y;
}

public class B extends A {
    int z;
}

ObjectMapper MAPPER = new ObjectMapper(); //it's configurable
MAPPER.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
MAPPER.configure( SerializationFeature.FAIL_ON_EMPTY_BEANS, false );

//Then wherever you need to initialize child from parent:
A parent = new A(x, y);
B child = MAPPER.convertValue( parent, B.class);
child.setZ(z);

lombok必要に応じて、AおよびBの注釈を引き続き使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.