デフォルト値を持つLombok Builder

1前書き

このクイックチュートリアルでは、 Lombok でビルダーパターンを使用するときに、属性にデフォルト値を指定する方法について説明します。

intro to Lombok もチェックしてください。

2依存関係

このチュートリアルではhttps://search.maven.org/artifact/org.projectlombok/lombok/1.18.2/jar[Lombok]を使用します。そのためには、1つの依存関係のみが必要です。

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.18</version>
    <scope>provided</scope>
</dependency>

3ロンボクビルダーとのPOJO

最初に、Lombokがどのようにしてビルダーパターンを実装するのに必要な定型コードを取り除くことができるかを見てみましょう。

簡単なPOJOから始めましょう。

public class Pojo {
    private String name;
    private boolean original;
}

このクラスが役に立つためには、ゲッターが必要です。また、たとえば、このクラスをORMとともに使用する場合は、おそらくデフォルトのコンストラクタが必要になります。

これらの上に、このクラス用のビルダーが欲しいです。 Lombokを使えば、これらすべてを簡単なアノテーションで実現できます。

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Pojo {
    private String name;
    private boolean original;
}

4期待を定義する

達成したいことへの期待を単体テストの形で定義しましょう。

最初のそして基本的な必要条件はビルダーでオブジェクトを構築した後のデフォルト値の存在です:

@Test
public void givenBuilderWithDefaultValue__ThanDefaultValueIsPresent() {
    Pojo build = Pojo.builder()
        .build();
    Assert.assertEquals("foo", build.getName());
    Assert.assertTrue(build.isOriginal());
}
  • @ Builder アノテーションに値が入力されていないため、もちろん、このテストは失敗します。** もうすぐ修正します。

ORMを使用する場合、通常はデフォルトのコンストラクタに依存しています。そのため、デフォルトコンストラクタからも、ビルダからの動作と同じ動作が期待されます。

@Test
public void givenBuilderWithDefaultValue__NoArgsWorksAlso() {
    Pojo build = Pojo.builder()
        .build();
    Pojo pojo = new Pojo();
    Assert.assertEquals(build.getName(), pojo.getName());
    Assert.assertTrue(build.isOriginal() == pojo.isOriginal());
}

この段階で、このテストは合格です。

それでは、両方のテストに合格する方法を見てみましょう。

5 Lombokの Builder.Default 注釈

Lombok v1.16.16以降、私たちは @ Builder の内部アノテーションを使うことができます。

----//class annotations as before
public class Pojo {
    @Builder.Default
    private String name = "foo";
    @Builder.Default
    private boolean original = true;
}
----

それはシンプルで読みやすいですが、それはいくつかの欠陥があります。

これにより、デフォルト値がビルダーに表示され、最初のテストケースに合格します。 残念ながら、引数なしのコンストラクタはデフォルト値を取得できず、2番目のテストケースは失敗します 。引数のないコンストラクタが生成されず明示的に記述されている場合でも

Builder.Default アノテーションのこの副作用は最初から存在しており、おそらくそれは長い間私たちにあるでしょう。

6. ビルダーを初期化する

最小限のビルダー実装でデフォルト値を定義することで、両方のテストに合格することを試みることができます。

----//class annotations as before
public class Pojo {
    private String name = "foo";
    private boolean original = true;
    public static class PojoBuilder {
        private String name = "foo";
        private boolean original = true;
    }
}
こうすれば、両方のテストに合格します。

残念ながら、価格はコードの重複です。 ** 数十個のフィールドを持つ__POJO__の場合、二重初期化を維持することは誤りがちです。

しかし、私たちがこの代金を払っても構わないと思っているのであれば、もう1つ注意を払う必要があります。 IDE内でリファクタリングを使用してクラスの名前を変更しても、静的な内部クラスの名前は自動的には変更されません。それから、ロンボクはそれを見つけることができません、そして、我々のコードは壊れるでしょう。

このリスクを排除するために、ビルダーアノテーションを装飾することができます。

[source,java,gutter:,false]

----//class annotations as before
@Builder(builderClassName = "PojoBuilder")
public class Pojo {
    private String name = "foo";
    private boolean original = true;

    public static class PojoBuilder {
        private String name = "foo";
        private boolean original = true;
    }
}

7. toBuilder を使用する

__ @ビルダー __また、元のクラスのインスタンスからビルダーのインスタンスを生成することもできます。この機能はデフォルトでは有効になっていません。

これを有効にするには、ビルダーアノテーションに toBuilder パラメータを設定します。

----//class annotations as before
@Builder(toBuilder = true)
public class Pojo {
    private String name = "foo";
    private boolean original = true;
}
----

これで、二重初期化を取り除くことができます。

もちろん、それには代償があります。 ビルダーを作成するためにクラスをインスタンス化しなければなりません それで、テストも修正しなければなりません:

@Test
public void givenBuilderWithDefaultValue__ThenDefaultValueIsPresent() {
    Pojo build =  new Pojo().toBuilder()
        .build();
    Assert.assertEquals("foo", build.getName());
    Assert.assertTrue(build.isOriginal());
}

@Test
public void givenBuilderWithDefaultValue__thenNoArgsWorksAlso() {
    Pojo build = new Pojo().toBuilder()
        .build();
    Pojo pojo = new Pojo();
    Assert.assertEquals(build.getName(), pojo.getName());
    Assert.assertTrue(build.isOriginal() == pojo.isOriginal());
}
  • 繰り返しますが、両方のテストに合格するので、ビルダーを使用したときと同じデフォルト値をno-argsコンストラクターを使用して使用します。

8結論

そこで、Lombok Builderにデフォルト値を提供するためのいくつかのオプションを調べました。

Builder . Default アノテーションの副作用は、注目する価値があります。しかし、他の方法にも欠点があります。だから我々は現在の状況に基づいて慎重に選ばなければなりません。

いつものように、コードはhttps://github.com/eugenp/tutorials/tree/master/lombok[over on GitHub]から入手できます。