12
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Lombok活用法(JUnitを中心に説明)

Last updated at Posted at 2019-07-14

概要

Lombokの基礎については、すでにたくさんの説明ページがあるので、Lombokの活用方法について主にJUnitを中心に記載していく.

記載対象のアノテーション

  1. @EqualsHashcode
  2. @ToString
  3. @Dataの功罪

@EqualsHashCodeについて

このアノテーションを付与すると、boolean:equals(Object)int hashCode()が自動生成される。
どちらもObjectクラスのメソッドのオーバーライドとなる.

equalsで作成されるコードは、ざっくりいうと配下のフィールドをすべて比較してすべて同一であったらtrueを返却する.

細かく書くと 以下順に精査を行う 1. 引数のNullチェック 2. 引数が同じクラスで作成されたインスタンスか? 3. (この精査は別途`protected boolean canEqual(Object other)`というメソッドが作成されるので、継承先でoverride可能) 3. フィールドがすべて同じか?

JUnitでの用途

@EqualsAndHashCodeを実装すると、JUnitを行う際に、フィールドについて精査を行ってくれるので作成インスタンス自体に精査を行えば事足りる

(その後フィールドの増減が発生した際にもequals(Object)書き換わるので精査し忘れを防ぐことができる)

EqualsHashCodeの注意点

あるクラスAを継承したクラスBに対して、@EqualsHashCodeを付与した場合、そのままだとB配下のフィールドしか判定対象とならず、Aが保持しているフィールドは判定対象にならない.

@EqualsAndHashCode
@Setter
@Getter
class A {
  private String aField
}
@Setter
@Getter
@EqualsAndHashCode
class B extends A {
  private String bField
}

とクラスBを定義した場合

    @org.junit.Test
    public void test(){
        BDto b1 = new BDto();
        b1.setBField("b1");
        b1.setAField("a1");

        BDto b2 = new BDto();
        b2.setBField("b1");
        b2.setAField("aXXXXXXXXXX"); //b1と異なる値を設定

        assertEquals(b2,b1);
    }

上記テストは通ってしまう(本来はaFieldの値が異なるのでエラーとしたいのに)

そのため、とあるクラスを継承した場合は@EqualsAndHashCode(callSuper = true)と指定する。
ただし継承元のクラスがequalsを継承している場合に限る

上記の場合は、Bの定義を以下のように書き換えると正しく判定を行えるようになる

@Setter
@Getter
@EqualsAndHashCode(callSuper = true)
class B extends A {
  private String bField
}

@ToStringについて

JUnitでの用途

@ToStringを付与しないクラスの場合、下記テストでエラーになっても

    @org.junit.Test
    public void test(){
        BDto b1 = new BDto();
        b1.setBField("b1");
        b1.setAField("a1");

        BDto b2 = new BDto();
        b2.setBField("b1");
        b2.setAField("aXXXXXXXXXX"); //b1と異なる値を設定

        assertEquals(b2,b1);
    }
java.lang.AssertionError: 
Expected :BDto@81666743
Actual   :BDto@2d9f8

となって、何が悪いか全くわからない

その対応として@ToStringを設定すると何が悪いかわかるようになるが、@EqualsAndHashCodeと同様とあるクラスを継承した場合は(callSuper = true)をつけるのを忘れないようにすること

(callSuper = true)つけなかった場合の出力例(@ToStringとだけ指定)

java.lang.AssertionError: expected: BDto<BDto(bField=b1)> but was: B<B(bField=b1)>
Expected :B<B(bField=b1)> 
Actual   :B<B(bField=b1)>

継承元の値が出力されないので何が悪いかわからない

(callSuper = true)つけた場合何が悪いか一目瞭然となる(@ToString()と指定)

java.lang.AssertionError: 
Expected :B(super=A(aField=aXXXXXXXXXX), bField=b1)
Actual   :B(super=A(aField=a1), bField=b1)

クラスAとBの定義はこのような形となる

継承元

@EqualsAndHashCode
@Getter
@Setter
@ToString
public class A {
    private String aField;
}

継承先

@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class B extends A {
    private String bField;
}

@Dataの功罪

@Dataを付与すると以下アノテーションを付与したのと同じになるので、楽に記載できる

  • @ToString
  • @Getter
  • @Setter
  • @RequiredArgsConstructor
  • @EqualsAndHashCode

上記の指定を一括で行ってくれるが、何もわからず使ってしまうと(callSuper = true)の設定ができないので、意図した実装にならない可能性があるので注意が必要

12
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?