若手SEを救いたい社畜の手記

わかすくしゅき

ExtendsしたクラスにおけるLombokの@Dataで親クラスのtoStrinngメソッドを呼び出す方法

2021年2月7日

この記事に書いてあること

この辺でEntityの分割に触れたのですが、Entityクラスのように複数のフィールドを持つクラスの場合、超便利ツールのLombokを使うとGetter/Setterの自動生成だけでなく、toStringメソッドをオーバーライドしてフィールド変数を一覧表示してくれるようにすることができます。

通常、toStringを自動実装しようとした場合に使用するアノテーションは@ToStringや@Dataです。

しかし、先の記事にあるような継承関係にあるクラスにおいてそのまま@Dataや@ToStringを使用すると、親クラスのフィールドを出力することができません。
これはアノテーションによって生成されるtoStringメソッドが自クラスのみを対象にしているためです。
Lombokではこのような問題にもしっかり対応できるようになっているのでメモ。

結論1-@Dataでは実現不可能

先に一つめの結論を書くと、@Dataではこのようなことはできません。
@Dataは以下の挙動を1行で設定してくれる便利アノテーションです。

  • 全てのフィールドのgetter
  • 全てのフィールドのsetter
  • デフォルトで用意されているhashCodeのオーバライド
  • デフォルトで用意されているtoStringのオーバライド
  • デフォルトで用意されているequalsのオーバライド

Lombokそのものの使い方は別の方の記事譲るということでここでは特に書きません。

今大事なのは、@Dataを付与した場合は親クラスのsuper()を実行することはできないということです。
@Getterや@ToStringを個別に使うしかありません。

※というか経験上、「@Dataを使ってる人って何が起こってるか分からないけど@Getterとかを個別に指定しなくていいから楽だよね」くらいの理解の人が多いのですが、ちゃんと何が起こっているかを調査して欲しいなと思うことはあります

結論2-@ToString(callSuper=true)なら実現可能

@Dataではなく、個別に@Getterや@ToStringを設定する場合なら親クラスのメソッドを呼び出すように指定してやることが可能です。

@ToString(callSuper=true)を使います。

以下のクラス図を見てください。ParendDtoに複数のフィールドがあり、ChildDtoに拡張項目として追加のフィールドがあります。

この時、やりたい事としてはChildDtoに@ToStringを付与して、ChildDtoの項目とParentDtoの項目を一覧表示したいというものです。
そこで例えばParentDtoに@DataをつけてtoStringメソッドをオーバーライドしてあるとしましょう。
親クラスには@Data、子クラスには@ToStringをつけています。

ダメな例

import java.util.Map;

import lombok.AccessLevel;
import lombok.Data;

@Data
public class ParentDto {

	private String userId;

	private int empNo;

	private String userName;
}

import lombok.Data;

@ToString
public class ChildDto extends ParentDto{

	private String place;

	private int departNo;
}

期待する動作としては、ChildDtoのtoStringメソッドを実行した場合、ParentDtoのフィールド情報も一緒に出力されるですよね。
しかし、結果は以下のようになります。

ChildDto(place=TOKYO, departNo=3)

ParentDtoの情報は出力されていません。

なぜかというと、とても単純な話でしてLombokが生成するChildDtoのtoStringメソッドは親クラスのオーバーライド元メソッドを実行しないためです。

良い例

そこで、Lombokが生成するtoStringメソッドに親クラスのメソッドを実行してねという情報を引き渡します。
それが(callSuper=true)です。

(callSuper=true)を指定することにより、親クラスのスーパーメソッドを実行してくれます。
先の、ChildDtoを以下のように書き換えます。

import lombok.Data;

@ToString(callSuper=true)
public class ChildDto extends ParentDto{

	private String place;

	private int departNo;
}

この状態で先ほどと同様にChildDtoのtoStringメソッドを実行すると以下のようになります。

ChildDto(super=ParentDto(userID=user01, userName=TARO, empNo=14002), place=TOKYO, departNo=3)

この通り、toStringの結果に親クラスのtoStringの結果が出力されました!!!

(callSuper=true)の注意点

いくつか注意点があります。

  • @Dataには使用できないため、個別に@Getterや@ToStringをつけてやる必要がある
  • 親クラスにも@Dataや@ToStringを付けておかないと、Java標準のtoStringメソッドが実行され、オブジェクト情報のみが出力される

2点でしたね・・・・

簡単なコードでtoStringを追加できて素敵ですね!!Lombokは!!

  • B!