親バカエンジニアのナレッジ帳

webのエンジニアをやっており、日頃の開発で詰まったことや書き残しておきたいことを載せています。

@Builderのクラスに引数なしのコンストラクタを設置したい


@Builderでコンストラクタを作成

@BuilderはLombokにより使えるライブラリで、
エンティティ呼び出し時にbuilderの生成を簡単にしてくれます。

仕組みとして、例えば

@Builder
public class Test() {
    private int id;
    private String name;
}

とすれば、実際には以下のようなコンストラクタが作られており、

public class Test() {
    private int id;
    private String name;
 
    public Test(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

以下のように簡単にビルダーできます。

Test test = Test.builder().name('TEST').build();

デフォルトのコンストラクタが存在しないと言われる...

便利だな〜、と思っていたのですが、このままでは不都合なことが...
例えばリポジトリクラスを通じて、findByName();とかをしようとすると、以下のようなエラーメッセージが出て上手く動かないと思います。

no default constructor for entity

あれ?
「エンティティにデフォルトのコンストラクタがありません」と出ますね。
@Builderでコンストラクタが作られてるはずでは...?
と思ったのですが、findで求められているコンストラクタは引数なしのコンストラクタです。
(public Test(){};のような)

普通インスタンスを作成する時に、クラス中にコンストラクタの定義が存在していればその定義を読み込みますが、存在していなければ、引数なしのコンストラクタを読み込みます。

今回は@Builderにより引数ありのコンストラクタが作られていたので、引数なしのコンストラクタは呼ばれません。
そうすると、
求められているコンストラクタ → 引数なしのコンストラクタ(デフォルトのコンストラクタ)
なのに、
呼ばれたコンストラクタ → 引数ありのコンストラクタ

となり、エラーが出てしまうのです。



@Tolerateで解決!

じゃあ@Builderで引数ありのコンストラクタが作られるなら、
引数なしのデフォルトのコンストラクタも用意しよう!
と思い、単純に

Public Test();

だけを用意しても残念ながらダメです。
今度はコンパイル時に、

コンストラクタ Testは指定された型に適用できません。...実引数リストと仮引数リストの長さが異なります

的なエラーが出てしまいます。

@Builderでは、すでに同じ名前のメソッドが存在している時、追加でメソッドを作らないのです。
片方を立てれば片方が立たず...
さあどうしましょう。
buiderを諦めようか...

と思いましたが、
こんな場合は、Tolerateアノテーションを使えば回避できることを発見!

@Tolerate
Public Test();

このアノテーションを使えば、エンティティ内にコンストラクタが定義されている場合でも、
@Builderで引数ありのコンストラクタが定義されるのです!


Fire TV Stick

Fire TV Stick

新登場  Fire TV Stick 4K - Alexa対応音声認識リモコン付属

新登場 Fire TV Stick 4K - Alexa対応音声認識リモコン付属

Fire HD 10 タブレット (10インチHDディスプレイ) 64GB

Fire HD 10 タブレット (10インチHDディスプレイ) 64GB