@lombok.Builder と Optional の狭間

# `@lombok.Builder`の不満点
`@lombok.Builder`は無かったら超困る程度には便利だが, 不満点もある. それは`Optional`との相性の悪さだ.

以下のようなデータ保持クラスがあるとしよう.

```java:ValueClass.java
@Value
@Builder
public class ValueClass {
    private final @Nonnull String requiredField;
    private final Optional<String> optionalField;
}
```

`requiredField`は必須フィールド, `optionalField`は空かもしれないフィールドとする.
こいつのBuilderを呼ぶとき, `optionalField`に空を渡したい場合, 以下のように書きたいだろう.

```java:ValueClassTest.java
public class ValueClassTest{
    @Test
    public void testBuilder() {
        // optionalField にわざわざ Optional.empty() を指定したくない
        val vo = ValueClass.builder()
                .requiredField("required")
                .build();
        
        assertThat(vo.getRequiredField(), is("required"));
        assertThat(vo.getOptionalField(), is(Optional.empty())); // このassertは通らない.
    }
}
```

しかし, このようにBuilderを呼び出すと, `optionalField`には無情にも`null`が入ってしまう. そこで`ValueClass`自体にデフォルト値を与えようなどと考え, 以下のようなことをしてみるのだが, 上手く行かない.

```java:ValueClass.java
@Value
@Builder
public class ValueClass {
    private final @Nonnull String requiredField;
    private Optional<String> optionalField = Optional.empty(); // こんな感じで初期値を与えたい
}
```

これをやると, そもそも`ValueClass`のBuilderに`optionalFiled`のセッタが生成されなくなってしまう. 結局のところ, Builderの呼び出し側コードでセッタに`Optional.empty()`を渡すしかない. つらい.

さらに, Builderに空でない値を渡す場合も, 以下のようなコードになり, 嬉しくない.

```java:ValueClassTest.java
public class ValueClassTest {
    @Test
    public void testBuilder() {
        val vo = ValueClass.builder()
                .requiredField("required")
                .optionalField(Optional.of("optional")) // 本当は .optionalField("optional") と書きたい
                .build();

        assertThat(vo.getRequiredField(), is("required"));
        assertThat(vo.getOptionalField(), is(Optional.of("optional")));
    }
}
```

`Optional.of`, じゃあないんだよ. 型で空許容を明示して幸せな世界にしようとしたのに, Builderの呼び出しが`Optional.of`だらけになって, なんだか逆に不幸になってしまった.

# 解決策
妥協の末, 下記のように折り合いをつけた.

* `@Builder`をつけるクラスのフィールドには`Optional`型を使わない.
* 必須フィールドには`@Nonnull`をつける.
* 空許容フィールドでは, 空表現を`null`で行う.
* すべての`@Nonnull`がついていないフィールドのゲッタを`Optional`型を返すように自作する.

先ほどの`ValueClass`に適用すると, 以下のようになる.

```java:ValueClass.java
@Value
@Builder
public class ValueClass {
    private final @Nonnull String requiredField;
    private final String optionalField;

    public Optional<String> getOptionalField() {
        return Optional.ofNullable(optionalField);
    }
}
```

呼び出し側のコードは, 以下のようになる.

```java:ValueClassTest.java
public class ValueClassTest {
    @Test
    public void testBuilderEmpty() {
        val vo = ValueClass.builder()
                .requiredField("required")
                .build();
        
        assertThat(vo.getRequiredField(), is("required"));
        assertThat(vo.getOptionalField(), is(Optional.empty()));
    }

    @Test
    public void testBuilderNotEmpty() {
        val vo = ValueClass.builder()
                .requiredField("required")
                .optionalField("optional")
                .build();
        
        assertThat(vo.getRequiredField(), is("required"));
        assertThat(vo.getOptionalField(), is(Optional.of("optional")));
    }
}
```

少しだけ, 幸せな世界に近づいた気がする.

## デメリット
* 空許容フィールドが多いクラスの定義がつらい.
* フィールド名が変わったとき, 自作のゲッタも合わせて改名しないといけない.
* Builderに対して`Optional`型を渡せない.
  * 明示的な空表現のために`null`が登場する...
  * 全部のクラスをこのルールで作ってみると, 空許容フィールドの同士の受け渡しで `vo.getOptionalField().orElse(null)` とかが必要になる.