Programming > Java > am > ik > s3
Jul 8, 2024
Jul 9, 2024
N/A Views
MD

JavaでS3にアクセスする場合には、

が候補に挙がります。メンテナンスされており、機能が豊富である一方、これらのライブラリは依存ライブラリが非常に多いです。

AWS SDK for Java 2.0の場合、

\- software.amazon.awssdk:s3:jar:2.26.16:compile
   +- software.amazon.awssdk:aws-xml-protocol:jar:2.26.16:compile
   |  \- software.amazon.awssdk:aws-query-protocol:jar:2.26.16:compile
   +- software.amazon.awssdk:protocol-core:jar:2.26.16:compile
   +- software.amazon.awssdk:arns:jar:2.26.16:compile
   +- software.amazon.awssdk:profiles:jar:2.26.16:compile
   +- software.amazon.awssdk:crt-core:jar:2.26.16:compile
   +- software.amazon.awssdk:http-auth:jar:2.26.16:compile
   +- software.amazon.awssdk:identity-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:http-auth-spi:jar:2.26.16:compile
   |  \- org.reactivestreams:reactive-streams:jar:1.0.4:compile
   +- software.amazon.awssdk:http-auth-aws:jar:2.26.16:compile
   +- software.amazon.awssdk:checksums:jar:2.26.16:compile
   +- software.amazon.awssdk:checksums-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:retries-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:sdk-core:jar:2.26.16:compile
   |  +- software.amazon.awssdk:retries:jar:2.26.16:compile
   |  \- org.slf4j:slf4j-api:jar:2.0.13:compile
   +- software.amazon.awssdk:auth:jar:2.26.16:compile
   |  \- software.amazon.eventstream:eventstream:jar:1.0.1:compile
   +- software.amazon.awssdk:http-client-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:regions:jar:2.26.16:compile
   +- software.amazon.awssdk:annotations:jar:2.26.16:compile
   +- software.amazon.awssdk:utils:jar:2.26.16:compile
   +- software.amazon.awssdk:aws-core:jar:2.26.16:compile
   +- software.amazon.awssdk:metrics-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:json-utils:jar:2.26.16:compile
   |  \- software.amazon.awssdk:third-party-jackson-core:jar:2.26.16:compile
   +- software.amazon.awssdk:endpoints-spi:jar:2.26.16:compile
   +- software.amazon.awssdk:apache-client:jar:2.26.16:runtime
   |  +- org.apache.httpcomponents:httpclient:jar:4.5.13:runtime
   |  |  \- commons-logging:commons-logging:jar:1.2:runtime
   |  +- org.apache.httpcomponents:httpcore:jar:4.4.16:runtime
   |  \- commons-codec:commons-codec:jar:1.16.1:runtime
   \- software.amazon.awssdk:netty-nio-client:jar:2.26.16:runtime
      +- io.netty:netty-codec-http:jar:4.1.111.Final:runtime
      +- io.netty:netty-codec-http2:jar:4.1.111.Final:runtime
      +- io.netty:netty-codec:jar:4.1.111.Final:runtime
      +- io.netty:netty-transport:jar:4.1.111.Final:runtime
      +- io.netty:netty-common:jar:4.1.111.Final:runtime
      +- io.netty:netty-buffer:jar:4.1.111.Final:runtime
      +- io.netty:netty-handler:jar:4.1.111.Final:runtime
      |  \- io.netty:netty-transport-native-unix-common:jar:4.1.111.Final:runtime
      +- io.netty:netty-transport-classes-epoll:jar:4.1.111.Final:runtime
      \- io.netty:netty-resolver:jar:4.1.111.Final:runtime

MinIO Java SDKの場合、

\- io.minio:minio:jar:8.5.11:compile
   +- com.carrotsearch.thirdparty:simple-xml-safe:jar:2.7.1:compile
   +- com.google.guava:guava:jar:33.0.0-jre:compile
   |  +- com.google.guava:failureaccess:jar:1.0.2:compile
   |  +- com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:compile
   |  +- com.google.code.findbugs:jsr305:jar:3.0.2:compile
   |  +- org.checkerframework:checker-qual:jar:3.41.0:compile
   |  +- com.google.errorprone:error_prone_annotations:jar:2.23.0:compile
   |  \- com.google.j2objc:j2objc-annotations:jar:2.8:compile
   +- com.squareup.okhttp3:okhttp:jar:4.12.0:compile
   |  +- com.squareup.okio:okio:jar:3.6.0:compile
   |  |  \- com.squareup.okio:okio-jvm:jar:3.6.0:compile
   |  |     \- org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.9.24:compile
   |  \- org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.9.24:compile
   |     +- org.jetbrains.kotlin:kotlin-stdlib:jar:1.9.24:compile
   |     |  \- org.jetbrains:annotations:jar:13.0:compile
   |     \- org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.9.24:compile
   +- com.fasterxml.jackson.core:jackson-annotations:jar:2.17.1:compile
   +- com.fasterxml.jackson.core:jackson-core:jar:2.17.1:compile
   +- com.fasterxml.jackson.core:jackson-databind:jar:2.17.1:compile
   +- org.bouncycastle:bcprov-jdk18on:jar:1.78:compile
   +- org.apache.commons:commons-compress:jar:1.26.0:compile
   |  +- commons-io:commons-io:jar:2.15.1:compile
   |  \- org.apache.commons:commons-lang3:jar:3.14.0:compile
   +- commons-codec:commons-codec:jar:1.16.1:compile
   \- org.xerial.snappy:snappy-java:jar:1.1.10.5:compile

となります。

Note

EoLが近づいているAWS SDK for Javaの場合は、幾分ましな依存関係です。

\- com.amazonaws:aws-java-sdk-s3:jar:1.12.757:compile
   +- com.amazonaws:aws-java-sdk-kms:jar:1.12.757:compile
   +- com.amazonaws:aws-java-sdk-core:jar:1.12.757:compile
   |  +- commons-logging:commons-logging:jar:1.1.3:compile
   |  +- commons-codec:commons-codec:jar:1.16.1:compile
   |  +- org.apache.httpcomponents:httpclient:jar:4.5.13:compile
   |  |  \- org.apache.httpcomponents:httpcore:jar:4.4.16:compile
   |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.17.1:compile
   |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.17.1:compile
   |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.17.1:compile
   |  +- com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:jar:2.17.1:compile
   |  \- joda-time:joda-time:jar:2.12.7:compile
   \- com.amazonaws:jmespath-java:jar:1.12.757:compile

他のAWSのサービスも使用している場合は、AWS SDK for Java 2.0でも良いかもしれませんが、
例えば、S3互換なObject Storageにシンプルなput/getくらいしかしていない場合は、これらのライブラリはtoo muchです。
また、AWS SDKの場合はApache HTTP Client or Netty、MinIO SDKの場合は(Kotlinで実装された)OkHttpとHTTPクライアントがそれぞれ組み込まれています。

Spring Bootでアプリを作成する場合、通常RestTemplateRestClientを使用します。
SDK側でHTTPクライアントが別途使われている場合、アプリ側で設定したObservability, Logging, RetryなどのInterceptorを共通的に利用できなくなり不便です。

アクセスキーとシークレットキーによる認証でput/getくらいしかしないようなシンプルなユースケースでは、単純にS3用にHTTP Headersを作成し、XMLのマーシャル・アンマーシャルだけ行えれば十分です。
それはSDKを使わずともRestTemplateRestClientだけで事足ります。

というわけでsimple-s3-clientというライブラリを作りました。
"s3-client"という名前がついていますが、HTTP Headersを作るユーティリティとよく使うAPIのデータクラスが含まれているだけです。

以下のdependencyを追加すれば使えます。

<dependency>
    <groupId>am.ik.s3</groupId>
    <artifactId>simple-s3-client</artifactId>
    <version>0.2.2</version>
</dependency>

使い方は次の通りです。

import static am.ik.s3.S3RequestBuilder.s3Request;

URI endpoint = URI.create("https://...");
String region = "...";
String accessKeyId = "...";
String secretAccessKey = "...";
String bucket = "...";

ObjectのPUTは次のように行えます。

// Put an object
String body = "Hello World!";
S3Request putObjectRequest = s3Request().endpoint(endpoint)
    .region(region)
    .accessKeyId(accessKeyId)
    .secretAccessKey(secretAccessKey)
    .method(HttpMethod.PUT)
    .path(b -> b.bucket(bucket).key("hello.txt"))
    .content(S3Content.of(body, MediaType.TEXT_PLAIN))
    .build();

RestTemplateの場合

restTemplate.exchange(putObjectRequest.toEntityBuilder().body(body), Void.class);

RestClientの場合

restClient.put()
    .uri(putObjectRequest.uri())
    .headers(putObjectRequest.headers())
    .body(body)
    .retrieve()
    .toBodilessEntity();

Note

マルチパートは未対応です。

ObjectのGETは次のように行えます。

// Get an object
S3Request getObjectRequest = s3Request().endpoint(endpoint)
    .region(region)
    .accessKeyId(accessKeyId)
    .secretAccessKey(secretAccessKey)
    .method(HttpMethod.GET)
    .path(b -> b.bucket(bucket).key("hello.txt"))
    .build();

RestTemplateの場合

String response = restTemplate.exchange(getObjectRequest.toEntityBuilder().build(), String.class).getBody();
System.out.println("Response: " + response); // Response: Hello World!

RestClientの場合

String response = restClient.get()
    .uri(getObjectRequest.uri())
    .headers(getObjectRequest.headers())
    .retrieve()
    .body(String.class);
System.out.println("Response: " + response); // Response: Hello World!

その他の使い方はREADMEを確認してください。

依存ライブラリは次の通りで、Spring BootでWebアプリを作るのに必須なspring-webとJacksonでXMLを扱うためのjackson-dataformat-xmlだけなので、
一般的なSpring Bootアプリ観点ではjackson-dataformat-xmlが足されただけで済みます。

\- am.ik.s3:simple-s3-client:jar:0.2.2:compile
   +- org.springframework:spring-web:jar:6.1.10:compile
   |  +- org.springframework:spring-beans:jar:6.1.10:compile
   |  +- org.springframework:spring-core:jar:6.1.10:compile
   |  |  \- org.springframework:spring-jcl:jar:6.1.10:compile
   |  \- io.micrometer:micrometer-observation:jar:1.13.1:compile
   |     \- io.micrometer:micrometer-commons:jar:1.13.1:compile
   +- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.17.1:compile
   |  +- com.fasterxml.jackson.core:jackson-core:jar:2.17.1:compile
   |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.17.1:compile
   |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.17.1:compile
   |  \- org.codehaus.woodstox:stax2-api:jar:4.2.2:compile
   \- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.17.1:compile
Found a mistake? Update the entry.
Share this article: