覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Lombok - コンストラクタの生成(xArgsConstructor)

Lombokのコンストラクタ生成に関する以下アノテーションの利用サンプルです。

  • @NoArgsConstructor(lombok.NoArgsConstructor)
  • @AllArgsConstructor(lombok.AllArgsConstructor)
  • @RequiredArgsConstructor(lombok.RequiredArgsConstructor)


デフォルトコンストラクタを生成する

@NoArgsConstructorをクラスに付与することでデフォルトコンストラクタを自動生成することができます。

■@NoArgsConstructorを付与したクラス

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Person1 {

    private long id;

    private String name;

    private int age;
}

■実際に生成されるソースコード

実際に生成されているソースコードは以下です(delombokで確認)
デフォルトコンストラクタが生成されていることが分かります。

public class Person1 {
    private long id;
    private String name;
    private int age;

    public Person1() {
    }
}


全メンバをセットするためのコンストラクタを生成する

@AllArgsConstructorをクラスに付与することで全メンバへ値をセットするための引数付きコンストラクタを自動生成することができます。

■@AllArgsConstructorを付与したクラス

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class Person2 {

    private long id;

    private String name;

    private int age;
}

■実際に生成されるソースコード

実際に生成されているソースコードは以下です(delombokで確認)
全メンバをセットするための引数付きコンストラクタが生成されていることが分かります。

public class Person2 {
    private long id;
    private String name;
    private int age;

    public Person2(final long id, final String name, final int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}


@NoArgsConstructor + @AllArgsConstructor

@NoArgsConstructor@AllArgsConstructorをクラスに付与することでデフォルトコンストラクタと全メンバへ値をセットするための引数付きコンストラクタの両方を自動生成することができます。

■@NoArgsConstructorと@AllArgsConstructorを付与したクラス

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
public class Person3 {

    private long id;

    private String name;

    private int age;
}

■実際に生成されるソースコード

実際に生成されているソースコードは以下です(delombokで確認)
デフォルトコンストラクタと全メンバをセットするための引数付きコンストラクタが生成されていることが分かります。

public class Person3 {
    private long id;
    private String name;
    private int age;

    public Person3() {
    }

    public Person3(final long id, final String name, final int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}


必須のメンバへ値をセットするコンストラクタを生成する

@RequiredArgsConstructorをクラスに付与することで必須のメンバ(finalのメンバ)へ値をセットするための引数付きコンストラクタを自動生成することができます。

■@RequiredArgsConstructorを付与したクラス

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class Person4 {

    private final long id;

    private String name;

    private int age;
}

■実際に生成されるソースコード

実際に生成されているソースコードは以下です(delombokで確認)
finalのメンバ(id)へ値をセットするためのコンストラクタが生成されています。

public class Person4 {
    private final long id;
    private String name;
    private int age;

    public Person4(final long id) {
        this.id = id;
    }
}


@RequiredArgsConstructor + @AllArgsConstructor

@RequiredArgsConstructor@AllArgsConstructorをクラスに付与することで必須メンバへ値をセットするためのコンストラクタと全メンバへ値をセットするためのコンストラクタの両方を自動生成することができます。

■@RequiredArgsConstructorと@AllArgsConstructorを付与したクラス

import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@AllArgsConstructor
public class Person5 {

    private final long id;

    private String name;

    private int age;
}

■実際に生成されるソースコード

実際に生成されているソースコードは以下です(delombokで確認)
必須メンバへ値をセットするコンストラクタと全メンバをセットするためのコンストラクタが生成されていることが分かります。

public class Person5 {
    private final long id;
    private String name;
    private int age;

    public Person5(final long id) {
        this.id = id;
    }

    public Person5(final long id, final String name, final int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}


コンストラクタのアクセスレベルを制御する

コンストラクタを生成するためのアノテーションを使用した場合、デフォルトではコンストラクタのアクセスレベルはpublicになります。 このアクセスレベルを制御したい場合は、accessパラメータを使用します。

■サンプルコード

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;

public class Person6 {

    @NoArgsConstructor(access=AccessLevel.PRIVATE)
    public static class Person6a {

        private long id;

        private String name;

        private int age;
    }

    @RequiredArgsConstructor(access=AccessLevel.PROTECTED)
    public static class Person6b {

        private final long id;

        private String name;

        private int age;
    }
}

■実際に生成されるソースコード

実際に生成されているソースコードは以下です(delombokで確認)
Person6aのコンストラクタのアクセスレベルがprivateに、Person6bのコンストラクタのアクセスレベルがprotectedになっていることが分かります。

public class Person6 {

    public static class Person6a {
        private long id;
        private String name;
        private int age;

        private Person6a() {
        }
    }


    public static class Person6b {
        private final long id;
        private String name;
        private int age;

        protected Person6b(final long id) {
            this.id = id;
        }
    }
}


ファクトリメソッドを定義する

コンストラクタを直接呼ばせずにファクトリメソッドを呼ばせるようにしたい場合があります。
そのような場合は、staticNameパラメータを使用することで、ファクトリメソッドを定義できます。

■サンプルコード

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;

public class Person7 {

    @RequiredArgsConstructor(staticName="of")
    public static class Person7a {

        private final long id;

        private String name;

        private int age;
    }

    @NoArgsConstructor(staticName="create")
    @AllArgsConstructor(staticName="create")
    public static class Person7b {

        private long id;

        private String name;

        private int age;
    }
}

■実際に生成されるソースコード

実際に生成されているソースコードは以下です(delombokで確認)
staticNameで指定した名前のファクトリメソッドが定義されていることが分かります。また、コンストラクタはprivateになっていることも分かります。

public class Person7 {

    public static class Person7a {
        private final long id;
        private String name;
        private int age;

        private Person7a(final long id) {
            this.id = id;
        }

        public static Person7a of(final long id) {
            return new Person7a(id);
        }
    }


    public static class Person7b {
        private long id;
        private String name;
        private int age;

        private Person7b() {
        }

        public static Person7b create() {
            return new Person7b();
        }

        private Person7b(final long id, final String name, final int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }

        public static Person7b create(final long id, final String name, final int age) {
            return new Person7b(id, name, age);
        }
    }
}


@NonNullと組み合わせる

必須メンバ(finalのメンバ)が存在するクラスに、@RequiredArgsConstructor@AllArgsConstructorを付与しただけだと、対象メンバにnullをセットすることが許容されてしまいます。
メンバがnullになることが許容できない場合は、@NonNullアノテーションを組み合わせましょう。

■サンプルコード

import lombok.AllArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

public class Person8 {

    @RequiredArgsConstructor
    public static class Person8a {

        private long id;

        @NonNull
        private final String name;

        private int age;
    }

    @AllArgsConstructor
    public static class Person8b {

        private final long id;

        @NonNull
        private final String name;

        @NonNull
        private final String description;
    }
}

■実際に生成されるソースコード

実際に生成されているソースコードは以下です(delombokで確認)
コンストラクタの処理内でnullがガードされていることが分かります。

import lombok.NonNull;

public class Person8 {

    public static class Person8a {
        private long id;
        @NonNull
        private final String name;
        private int age;

        public Person8a(@NonNull final String name) {
            if (name == null) {
                throw new NullPointerException("name");
            }
            this.name = name;
        }
    }


    public static class Person8b {
        private final long id;
        @NonNull
        private final String name;
        @NonNull
        private final String description;

        public Person8b(final long id, @NonNull final String name, @NonNull final String description) {
            if (name == null) {
                throw new NullPointerException("name");
            }
            if (description == null) {
                throw new NullPointerException("description");
            }
            this.id = id;
            this.name = name;
            this.description = description;
        }
    }
}


コンストラクタにアノテーションを付与する

DIコンテナを使用していて、コンストラクタインジェクションをやりたい場合などに、コンストラクタに@Injectアノテーションを付与します。
このように、コンストラクタへ何らかのアノテーションを付与したい場合は、onConstructorパラメータを利用します。
パラメータは以下のように記述します。

onConstructor=@__({付与したいアノテーション})

■サンプルコード

onConstructorパラメータで、@Injectアノテーションを付与するように指定しています。

import javax.inject.Inject;

import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;

public class Person9 {

    @RequiredArgsConstructor(onConstructor=@__({@Inject}))
    public static class Person9a {

        private long id;

        private final String name;

        private int age;
    }

    @AllArgsConstructor(onConstructor=@__({@Inject}))
    public static class Person9b {

        private final long id;

        private final String name;

        private int age;
    }
}

■実際に生成されるソースコード

実際に生成されているソースコードは以下です(delombokで確認)
コンストラクタに@Injectアノテーションが付与されていることが分かります。

import javax.inject.Inject;

public class Person9 {

    public static class Person9a {
        private long id;
        private final String name;
        private int age;

        @Inject
        public Person9a(final String name) {
            this.name = name;
        }
    }


    public static class Person9b {
        private final long id;
        private final String name;
        private int age;

        @Inject
        public Person9b(final long id, final String name, final int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
    }
}



関連エントリ