概要
こんにちは。STORES 決済でJavaエンジニアをしているnannanyです。
今回はファイル生成処理に使ってみて便利だった、Lombokの@Builder
のオプション機能を紹介していきます。
説明しないこと
Lombokの@Builder
のオプション機能に焦点を当てるので、
については述べません。
背景
APIによる情報連携が盛んになった世の中ですが、企業間の情報連携においてはまだまだCSV・TSV・Excelといったファイル形式での情報連携が多いです。
そんな中、ファイル生成する処理を最近実装しました。
実装を進めていく中で@Builder
にとても助けられているなぁ、と感じることが多かったので、具体例を交えながらその機能を紹介していきます。
前提
以下のようなCSVファイルを作成することを念頭に説明していきます。
(1行目はヘッダーです)
店名,住所,電話番号,提出元企業,同一店舗フラグ 恵比寿商店,東京都渋谷区南1,080-xxxx-xxxx,STORES,0 渋谷商店,東京都渋谷区南2,090-xxxx-xxxx,STORES,0 渋谷商店,東京都渋谷区南2,090-xxxx-xxxx,STORES,1
また、上記のCSVファイルの各行の値を格納するクラスとして、下記のCSVRecord
クラスを利用するものとします。
(CSVRecord
クラスに設定した値がCSVファイルに書き出されるイメージ)
@Builder public class CSVRecord { private String storeName; // 店名 private String address; // 住所 private String phoneNumber; // 電話番号 private String companyName; // 提出元企業 private Integer sameFlag; // 同一店舗フラグ }
@Builder.Default
例で挙げたCSVの提出元企業
というカラムについて、STORES から提出先の企業へと提出する資料であるため、このカラムには必ずSTORES
という値が入ります。
そのため、組み立てのロジックの中で値を入れるのではなく、デフォルト値としてSTORES
を設定しておきたいです。
そんなときに使えるのが@Builder.Default
です。
@Builder.Default
を付与したフィールドには、デフォルト値を設定できます。
下記のように記述すると、companyName
にはSTORES
がデフォルト値として設定されます。
@Builder public class CSVRecord { private String storeName; private String address; private String phoneNumber; @Builder.Default // <-ここ private String companyName = "STORES"; // <-ここ private Integer sameFlag; }
Builderのメソッドを追加
@Builder
を付与したクラスには、ビルダークラスが作られ、ビルダークラスには各フィールドの値を設定するメソッドが作られます。
上記の例では、
storeName
に値を設定するstoreName(String storeName)
address
に値を設定するaddress(String address)
phoneNumber
に値を設定するphoneNumber(String phoneNumber)
companyName
に値を設定するcompanyName(String companyName)
sameFlag
に値を設定するsameFlag(Integer sameFlag)
がビルダークラスのメソッドとして作られます。
これだけでも便利なのですが、複数の値を含んだレコード・クラスを受け取って、その中身をビルダーに設定したい時もあります。
例えば、下記のようなレコード・クラスがあったとします。
public record StoreInfo(
String storeName,
String address,
String phoneNumber
) {
}
このレコード・クラスを受け取って、CSVRecord
のビルダーに設定したいような場合、下記のようにビルダークラスにメソッドを追加することで解決できます。
(CSVRecordに@Builder
をつけた場合には自動的にCSVRecordBuilder
というクラスができるので下記のような書き方になります。builderClassName
を利用して任意のビルダークラス名にした場合、おそらく該当の名前のインナークラスを定義し、その中にメソッドを書くことになるはずです)
@Builder public class CSVRecord { private String storeName; private String address; private String phoneNumber; @Builder.Default private String companyName = "STORES"; private Integer sameFlag; public static CSVRecordBuilder storeInfo(StoreInfo storeInfo) { // <-ここ return builder() .storeName(storeInfo.storeName()) .address(storeInfo.address()) .phoneNumber(storeInfo.phoneNumber()); } }
toBuilder = true
例のCSVにおいて、同一店舗フラグ
が0
の場合、該当の店舗は同一CSVファイル内で初出の店舗であることを示しています。
逆に、同一店舗フラグ
が1
の場合、同一CSVファイル内で2回目以降の出現であることを示しています。
つまり、同一店舗の情報を複数行記載する場合、同一店舗フラグ
以外は同じインスタンスを生成することになります。
そんなときに使えるのがtoBuilder = true
です。
@Builder(toBuilder = true)
とすることで、該当クラスのインスタンスを元にあたらしいビルダーインスタンスを生成するtoBulder()
メソッドを作ることができます。
@Builder(toBuilder = true) // <-ここ public class CSVRecord { private String storeName; private String address; private String phoneNumber; @Builder.Default private String companyName = "STORES"; private Integer sameFlag; public static CSVRecordBuilder storeInfo(StoreInfo storeInfo) { return builder() .storeName(storeInfo.storeName()) .address(storeInfo.address()) .phoneNumber(storeInfo.phoneNumber()); } }
こうすることによって、CSVRecord
クラス内に下記のようなメソッドが作られます。
// 上記をdelombokしたもの public CSVRecordBuilder toBuilder() { return (new CSVRecordBuilder()) .storeName(this.storeName) .address(this.address) .phoneNumber(this.phoneNumber) .companyName(this.companyName) .sameFlag(this.sameFlag); }
これを使って、特定の店舗の行を2行以上出力したい場合は、
という流れで記述できます。 この流れをコードにすると下記のようになります。
CsvRecord csvRecord = ...; ... // CSVRecordのインスタンスを組み立てる処理 for (int i = 0; i < count - 1; i++) { // countは同一店舗の情報を何行出力するかを表す csvRecords.add(csvRecord.toBuilder() // csvRecordsはCSVRecordのリスト .sameFlag("1") .build()); }
このようにして、構成要素の一部だけ異なる行を作成するという処理が書きやすくなりました。
まとめ
今回は、Lombokの@Builder
のオプション機能について紹介しました。内容をまとめると以下の3点になります。