Lombokの@ToString(lombok.ToString)アノテーションの利用サンプルです。
@ToString
アノテーションを付与することで、toString
メソッドを適切にオーバーライドしてくれます。
アノテーションにパラメータを与えることでtoStringメソッドでの文字列化処理や文字列化対象について、制御を行うことができます。
ちなみに、@Data
や@Value
のアノテーションを付与すると、内部的に@ToString
アノテーションが付与されたのと同じことが起こります。
@ToStringの文字列出力はどんな動きか?
delombokすればいいだけのことですが、実際にコードを動かして確認してみます
■@ToStringアノテーションを付与したクラス
- 以下のようなクラスを用意しました
@ToString
アノテーションを付与@Getter
,@Setter
アノテーションは使用しない- getter/setter を自前で記述
- getterメソッドのないフィールドが存在する
- 配列のフィールドが存在する
- フィールドの値を装飾して返すgetterが存在する
- prefixが"get"ではないアクセサを持つフィールドが存在する
- staticフィールドを配置
import lombok.ToString; @ToString public class Person1 { // staticフィールド private static final String DEFALUT_REMARKS = "none"; // getter無し private long id; // getterでは装飾した文字列が返される private String name; private int age; // 配列のメンバ private String[] memos; // prefixが"get"ではないアクセサを持つ private String remarks = DEFALUT_REMARKS; public void setId(long id) { this.id = id; } public String getName() { return "####" + name + "#####"; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String[] getMemos() { return memos; } public void setMemos(String[] memoArray) { this.memos = memoArray; } public String remarks() { return "備考…" + remarks; } public void remarks(String remarks) { this.remarks = remarks; } }
■利用側のコード
toStringメソッドの呼び出しとgetterメソッドの呼び出しを行っています。
public class Person1Client { public static void main(String[] args) { Person1 p = new Person1(); p.setId(10L); p.setName("Kernel Taro"); p.setAge(55); p.setMemos(new String[] {"memo1", "memo2", "memo3"}); p.remarks("逮捕歴無し"); System.out.println(p); System.out.println("----------"); System.out.println("p#getName: " + p.getName()); System.out.println("p#getAge: " + p.getAge()); System.out.println("p#getMemos: " + p.getMemos()); System.out.println("p#remarks: " + p.remarks()); } }
■実行結果
Person1(id=10, name=####Kernel Taro#####, age=55, memos=[memo1, memo2, memo3], remarks=逮捕歴無し) ---------- p#getName: ####Kernel Taro##### p#getAge: 55 p#getMemos: [Ljava.lang.String;@79f1d448 p#remarks: 備考…逮捕歴無し
実行結果から見ても分かることは以下です
- toStringの処理内では各メンバの値取得はgetterを通して行われる
- ただし、getterメソッドなければ直接メンバの値が使用される
- アクセサの名前の先頭が"get"でなければ直接メンバの値が使用される
- 配列の値は適切に文字列化処理が行われる
- staticメンバはtoStringの対象にならない
■実際に生成されているコード
実際に生成されているソースコードをdelombokを使って確認してみました
public class Person1 { private static final String DEFALUT_REMARKS = "none"; private long id; private String name; private int age; private String[] memos; private String remarks = DEFALUT_REMARKS; public void setId(long id) { this.id = id; } public String getName() { return "####" + name + "#####"; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String[] getMemos() { return memos; } public void setMemos(String[] memoArray) { this.memos = memoArray; } public String remarks() { return "備考…" + remarks; } public void remarks(String remarks) { this.remarks = remarks; } @Override public String toString() { return "Person1(id=" + this.id + ", name=" + this.getName() + ", age=" + this.getAge() + ", memos=" + java.util.Arrays.deepToString(this.getMemos()) + ", remarks=" + this.remarks + ")"; } }
デフォルトの@ToStringアノテーション
対象クラスに@ToString
アノテーションを付与します。パラメータの指定はしません
■@ToStringアノテーションを付与したクラス
import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString public class Account1 { private String id; private String password; private String name; }
■利用側のコード
public class Account1Client { public static void main(String[] args) { Account1 account = new Account1(); account.setId("abc-0001"); account.setPassword("pass-012345"); account.setName("LombokJiro"); System.out.println("Account1#toString: " + account); } }
■実行結果
Account1#toString: Account1(id=abc-0001, password=pass-012345, name=LombokJiro)
特定のメンバをtoStringの対象から除外する
セキュリティ的な問題や諸々の理由で特定のメンバをtoStringの結果に含めたくない場合があります。
その場合は exclude
パラメータに除外対象のフィールド名を指定します
■@ToStringアノテーションを付与したクラス
@Getter @Setter @ToString(exclude="password") public class Account2 { private String id; private String password; private String name; }
■利用側のコード
public class Account2Client { public static void main(String[] args) { Account2 account = new Account2(); account.setId("abc-0001"); account.setPassword("pass-012345"); account.setName("LombokJiro"); System.out.println("Account2#toString: " + account); } }
■実行結果
Account2#toString: Account2(id=abc-0001, name=LombokJiro)
toStringの結果にフィールド名を含めない
デフォルトでは@ToString
アノテーションを付与するとtoStringの結果には各フィールド名も出力されます
このフィールド名が不要という場合には、includeFieldNames=false
の指定を行うことで実現できます。
■@ToStringアノテーションを付与したクラス
import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString(includeFieldNames=false) public class Account3 { private String id; private String password; private String name; }
■利用側のコード
public class Account3Client { public static void main(String[] args) { Account3 account = new Account3(); account.setId("abc-0001"); account.setPassword("pass-012345"); account.setName("LombokJiro"); System.out.println("Account3#toString: " + account); } }
■実行結果
Account3#toString: Account3(abc-0001, pass-012345, LombokJiro)
継承クラスにおける@ToStringアノテーションの動作
デフォルトでは、@ToString
アノテーションを付与したクラスのtoStringは親クラスのtoStringの呼び出しを行いません。
親クラスのtoStringの呼び出しを行いたい場合は、callSuper=true
を指定します。
■@ToStringアノテーションを付与したクラス
- Account4a・・・デフォルトの
@ToString
アノテーション付与 - Account4b・・・
@ToString
アノテーションにcallSuper=true
の指定あり
import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString public class Account4 { private String id; private String password; private String name; @Getter @Setter @ToString public static class Account4a extends Account4 { private String remarks; } @Getter @Setter @ToString(callSuper=true) public static class Account4b extends Account4 { private String remarks; } }
■利用側のコード
public class Account4Client { public static void main(String[] args) { Account4a account1 = new Account4a(); account1.setId("abc-0001"); account1.setPassword("pass-012345"); account1.setName("LombokJiro"); account1.setRemarks("備考です001"); System.out.println("Account4a#toString: " + account1); Account4b account2 = new Account4b(); account2.setId("abc-0001"); account2.setPassword("pass-012345"); account2.setName("LombokJiro"); account2.setRemarks("備考です001"); System.out.println("Account4b#toString: " + account2); } }
■実行結果
Account4a#toString: Account4.Account4a(remarks=備考です001) Account4b#toString: Account4.Account4b(super=Account4(id=abc-0001, password=pass-012345, name=LombokJiro), remarks=備考です001)
toStringでgetterを利用しないようにする
デフォルトの@ToString
アノテーションでは、先の例に示した通りgetterメソッドを通じて各メンバへアクセスが行われます。
getterを利用してほしくない場合は、doNotUseGetters=true
を指定します。
■@ToStringアノテーションを付与したクラス
import lombok.Setter; import lombok.ToString; @Setter @ToString(doNotUseGetters=true) public class Account5 { private String id; private String password; private String name; public String getId() { return id; } public String getPassword() { return password; } // 装飾した文字列を返す public String getName() { return "#### " + name + " ####"; } }
■利用側のコード
public class Account5Client { public static void main(String[] args) { Account5 account = new Account5(); account.setId("abc-0001"); account.setPassword("pass-012345"); account.setName("LombokJiro"); System.out.println("Account5#toString: " + account); } }
■実行結果
Account5#toString: Account5(id=abc-0001, password=pass-012345, name=LombokJiro)
toStringに含めるメンバを明示的に指定する
exclude
とは逆にof
を利用することでtoStringの結果に含めるメンバを明示的に指定することができます
■@ToStringアノテーションを付与したクラス
import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString(of={"id", "name"}) public class Account6 { private String id; private String password; private String name; }
■利用側のコード
public class Account6Client { public static void main(String[] args) { Account6 account = new Account6(); account.setId("abc-0001"); account.setPassword("pass-012345"); account.setName("LombokJiro"); System.out.println("Account6#toString: " + account); } }
■実行結果
Account6#toString: Account6(id=abc-0001, name=LombokJiro)
@Data + @ToString
@Data
アノテーションと@ToString
アノテーションを同時に付与して@ToString
にパラメータを指定した場合、
@ToString
に指定したパラメータは有効に働きます
■@Dataと@ToStringアノテーションを付与したクラス
import lombok.Data; import lombok.ToString; @Data @ToString(exclude="password") public class Account7 { private String id; private String password; private String name; }
■利用側のコード
public class Account7Client { public static void main(String[] args) { Account7 account = new Account7(); account.setId("abc-0001"); account.setPassword("pass-012345"); account.setName("LombokJiro"); System.out.println("Account7#toString: " + account); } }
■実行結果
Account7#toString: Account7(id=abc-0001, name=LombokJiro)