> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tensor9.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AWS Java SDK Guide

> Configure the AWS SDK for Java to use a Cloud Adapter endpoint and verify an object lifecycle.

Cloud Adapter preserves the AWS service model at the application boundary. Your Java code keeps using AWS request and response types; the client factory selects the adapter endpoint.

This example uses AWS SDK for Java 2.x and S3. Check [S3 service coverage](/cloud-adapter/service-catalog/aws/databases-storage/s3) for the target environment and operations your application uses.

## Choose how to set the endpoint

### Set it for the process

The AWS-standard S3 environment variable applies to every S3 client created by a supported SDK in this process:

```bash theme={null}
export AWS_ENDPOINT_URL_S3="https://adapter.example.test"
```

Build the client normally and omit `endpointOverride`:

```java theme={null}
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

S3Client s3 = S3Client.builder()
    .region(Region.US_EAST_1)
    .credentialsProvider(ProfileCredentialsProvider.create("adapter-test"))
    .forcePathStyle(true)
    .build();
```

### Set it on one client

Keep endpoint selection in one factory rather than scattering it through business logic.

```bash theme={null}
export T9_CLOUD_ADAPTER_ENDPOINT="https://adapter.example.test"
```

```java theme={null}
import java.net.URI;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

URI endpoint = URI.create(System.getenv("T9_CLOUD_ADAPTER_ENDPOINT"));

S3Client s3 = S3Client.builder()
    .endpointOverride(endpoint)
    .region(Region.US_EAST_1)
    .credentialsProvider(ProfileCredentialsProvider.create("adapter-test"))
    .forcePathStyle(true)
    .build();
```

`endpointOverride` changes where the AWS request is sent. It does not change the service model, add unsupported operations, or provide credentials to the target service. Backend credentials stay in the service adapter configuration.

An explicit client override takes precedence over `AWS_ENDPOINT_URL_S3`. Choose one approach for a client factory so configuration remains easy to audit.

For SDK 1.x, use `AmazonS3ClientBuilder` with an endpoint configuration and path-style access. Do not mix 1.x and 2.x configuration examples in the same client factory.

## Verify a lifecycle

Use a unique key and a small payload:

```java theme={null}
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import software.amazon.awssdk.core.ResponseBytes;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;

String bucket = System.getenv("TEST_BUCKET");
String key = "java/" + System.currentTimeMillis() + "-hello.txt";
byte[] expected = "hello through Cloud Adapter\n".getBytes(StandardCharsets.UTF_8);

s3.putObject(builder -> builder.bucket(bucket).key(key).contentType("text/plain"),
    RequestBody.fromBytes(expected));
s3.headObject(builder -> builder.bucket(bucket).key(key));

ResponseBytes<GetObjectResponse> downloaded = s3.getObjectAsBytes(
    GetObjectRequest.builder().bucket(bucket).key(key).build());
if (!Arrays.equals(expected, downloaded.asByteArray())) {
    throw new IllegalStateException("Downloaded object differs from uploaded bytes");
}

s3.deleteObject(builder -> builder.bucket(bucket).key(key));
```

Verify the object in the target service after `putObject`, not only through the adapter. That catches name, region, metadata, and identity mistakes that an origin-shaped response alone may hide.

## Preserve failure evidence

Catch service and transport failures separately:

```java theme={null}
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.services.s3.model.S3Exception;

try {
    s3.headObject(builder -> builder.bucket(bucket).key("missing-key"));
} catch (S3Exception error) {
    System.err.printf("status=%d requestId=%s code=%s%n",
        error.statusCode(), error.requestId(), error.awsErrorDetails().errorCode());
} catch (SdkClientException error) {
    System.err.println("No service response: " + error.getMessage());
}
```

Do not automatically retry a timed-out mutation until you have checked target state and the operation's idempotency. Retain the SDK request ID and Cloud Adapter diagnostic headers in structured logs, while excluding credentials and payload bodies.

## Production client checklist

* Make endpoint, origin region, and credential provider explicit.
* Bound connection, request, and retry timeouts for the target path.
* Reuse the client; do not create one per request.
* Test the exact paginator, waiter, conditional request, and multipart features the application uses.
* Keep AWS-origin credentials separate from the adapter's target-cloud identity.
* Run an expected not-found or validation error to verify error translation.

For a deeper failure, preserve the SDK request ID and follow [Debugging Your Adapters](/cloud-adapter/debugging/overview).
