AWS SDK for JavaでS3オブジェクトの一覧を取得する2つの方法

## 課題

AWS SDK for Javaで、S3オブジェクトの一覧を取得する機能を利用するとき、日本語でまとまった情報を入手するのに苦労しました。

## 解決方針

どのようにSDKを利用したか、この記事にまとめます。

## 方法

### 前提

- Javaバージョン: 17
- AWS SDKバージョン: v2

### 共通の注意点

- 1回のリクエストで、すべてのオブジェクトが取得されるとは限りません。
  - 取得したオブジェクト一覧を格納したクラスには、以下の情報が含まれます。
    - a. 取得しきれなかったオブジェクトがあるか否か
    - b. 取得したオブジェクト一覧末尾の、次のオブジェクトを示すトークン
      - 取得しきれなかったオブジェクトを取得する際に、このトークンが示す位置から取得を開始します。

### バージョニングが無効のとき

`software.amazon.awssdk.services.s3.model.ListObjectsV2Request`クラスを利用します。

一例として、以下の`getAllS3Contents`メソッドでは、バケット内にあるすべてのオブジェクトを、リストに格納して返却しています。

```Java
  // S3クライアントを用意
  private final S3Client s3Client;

  // 初回に呼び出すメソッド
  public List<S3Object> getAllS3Contents(String bucketName) {
    return getAllS3Contents(bucketName, new ArrayList<S3Object>(), null);
  }

  // 再帰的に呼び出すメソッド
  private List<S3Object> getAllS3Contents(String bucketName, List<S3Object> objects, String continuationToken) {
    // リクエスト作成
    var listReq = ListObjectsV2Request.builder()
                                      .bucket(bucketName)
                                      .continuationToken(continuationToken)
                                      .build();

    // レスポンス取得
    var res = s3Client.listObjectsV2(listReq);
    // S3オブジェクトリスト取得
    var currentObjects = res.contents();
    // 前のステップで取得したS3オブジェクトリストを連結
    objects.addAll(currentObjects);
    // 次のステップで取得を開始する位置
    var nextContinuationToken = res.nextContinuationToken(); // (b, aが`false`の場合は`null`)

    // 一度にすべてのS3オブジェクトを取得しきれなかった場合、S3オブジェクトリストと開始位置を更新して、このメソッドを再帰的に呼び出す
    if (res.isTruncated()) { // (a)
      return getAllS3Contents(bucketName, objects, nextContinuationToken);
    }

    return objects;
  }
```

### バージョニングが有効のとき

`software.amazon.awssdk.services.s3.model.ListObjectVersionsRequest`クラスを利用します。

一例として、以下の`getAllS3Versions`メソッドでは、バケット内にあるすべてのオブジェクトバージョンを、リストに格納して返却しています。

以下の点以外は、バージョニングが無効のときと同じです。

- 返り値の型を`ObjectVersion`に変更。
- 次のオブジェクトを示すトークン(b)に、バージョンを示す情報を追加。

```Java
  // S3クライアントを用意
  private final S3Client s3Client;

  // 初回に呼び出すメソッド
  public List<ObjectVersion> getAllS3Versions(String bucketName) {
    return getAllS3Versions(bucketName, new ArrayList<ObjectVersion>(), null, null);
  }

  // 再帰的に呼び出すメソッド
  private List<ObjectVersion> getAllS3Versions(String bucketName, List<ObjectVersion> objVerList, String keyMarker, String versionIdMarker) {
    // リクエスト作成
    var listReq = ListObjectVersionsRequest.builder()
                                      .bucket(bucketName)
                                      .keyMarker(keyMarker)
                                      .versionIdMarker(versionIdMarker)
                                      .build();

    // レスポンス取得
    var res = s3Client.listObjectVersions(listReq);
    // S3オブジェクトリスト取得
    var currentVersions = res.versions();
    // 前のステップで取得したS3オブジェクトリストを連結
    objVerList.addAll(currentVersions);
    // 次のステップで取得を開始する位置
    var nextKeyMarker = res.nextKeyMarker(); // (b, aが`false`の場合は`null`)
    var nextVersionIdMarker = res.nextVersionIdMarker(); // (b, aが`false`の場合は`null`)

    // 一度にすべてのS3オブジェクトを取得しきれなかった場合、S3オブジェクトリストと開始位置を更新して、このメソッドを再帰的に呼び出す
    if (res.isTruncated()) { // (a)
      return getAllS3Versions(bucketName, objVerList, nextKeyMarker, nextVersionIdMarker);
    }

    return objVerList;
  }
```

## 参考資料

- [ListObjectsV2Request | AWS SDK for Java API Reference - 2.27.23](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/ListObjectsV2Request.html)
- [ListObjectsV2Response | AWS SDK for Java API Reference - 2.27.23](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/ListObjectsV2Response.html)
- [ListObjectVersionsRequest | AWS SDK for Java API Reference - 2.27.23](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/ListObjectVersionsRequest.html)
- [ListObjectVersionsResponse | AWS SDK for Java API Reference - 2.27.23](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/ListObjectVersionsResponse.html)
- [ListObjectsV2Request(AWS SDK for Java)でS3のファイル一覧を取得する | Qiita](https://qiita.com/seijikohara/items/32198148fad35c641cd2)