[email protected]注意すべき穴

2378 ワード

最近の開発では、エンティティークラスのbooleanフィールドをtrueとしてデフォルト化したいので、フィールド定義後にtrueとして値を付けます.また、クラスに@Builder注記があります.builder方式でインスタンスを作成するときにもtrueとしてデフォルト化したいと思っています.資料を見て、@Builder.Default注記が適切であることがわかりました.実際にコードを実行した後、builderモードではデフォルト値が有効になりますが、newを使用して得られたインスタンスのデフォルト値はfalseです.テストコードを貼って、はっきりしてください.
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.ToString;

public class testLombok {
  public static void main(String[] args) {
    People p1 = new People();
    System.out.println(p1); //People(old=false)
    People p2 = People.builder().build(); //People(old=true)
    System.out.println(p2);
  }
}


@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
class People {
  @Builder.Default
  private boolean old = true;
}

どうしてこんなことになったの?心の中で1万頭のアルパカが走った...
逆コンパイルされたPeopleコードを見てみましょう
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import java.beans.ConstructorProperties;

class People {
  private boolean old;

  private static boolean $default$old() {
    return true;
  }

  public static People.PeopleBuilder builder() {
    return new People.PeopleBuilder();
  }

  public String toString() {
    return "People(old=" + this.old + ")";
  }

  public People() {
  }

  @ConstructorProperties({"old"})
  public People(boolean old) {
    this.old = old;
  }

  public static class PeopleBuilder {
    private boolean old$set;
    private boolean old;

    PeopleBuilder() {
    }

    public People.PeopleBuilder old(boolean old) {
      this.old = old;
      this.old$set = true;
      return this;
    }

    public People build() {
      return new People(this.old$set ? this.old : People.$default$old());
    }

    public String toString() {
      return "People.PeopleBuilder(old=" + this.old + ")";
    }
  }
}

最初から、コードのoldフィールドに初期値が付与されず、staticメソッド$default$oldが追加され、メソッドの戻り値が設定されたデフォルト値となります.次に、静的内部クラスPeopleBuilderのbuildメソッドでoldフィールドを判断し、値が設定されていない場合は$default$oldメソッドのデフォルト値をPeopleインスタンスに割り当てます.今やっと以前の困惑を理解して、@Builder.Defaultの実現原理を理解しました.
@Builder.Defaultで問題を解決できない以上、どうすればいいのでしょうか.
考えを変えて、インスタンスを初期化するとbooleanフィールドがfalseに初期化され、この特性を利用してフィールド名をnotOldに変更すればよい.コードは次のとおりです.
public class People {
  private boolean notOld;
}