---
name: aws-sdk-java-v2-s3
description: Amazon S3 patterns and examples using AWS SDK for Java 2.x. Use when working with S3 buckets, uploading/downloading objects, multipart uploads, presigned URLs, S3 Transfer Manager, object operations, or S3-specific configurations.
category: aws
tags: [aws, s3, java, sdk, storage, objects, transfer-manager, presigned-urls]
version: 1.1.0
allowed-tools: Read, Write, Bash
---
# AWS SDK for Java 2.x - Amazon S3
## When to Use
Use this skill when:
- Creating, listing, or deleting S3 buckets with proper configuration
- Uploading or downloading objects from S3 with metadata and encryption
- Working with multipart uploads for large files (>100MB) with error handling
- Generating presigned URLs for temporary access to S3 objects
- Copying or moving objects between S3 buckets with metadata preservation
- Setting object metadata, storage classes, and access controls
- Implementing S3 Transfer Manager for optimized file transfers
- Integrating S3 with Spring Boot applications for cloud storage
- Setting up S3 event notifications for object lifecycle management
- Managing bucket policies, CORS configuration, and access controls
- Implementing retry mechanisms and error handling for S3 operations
- Testing S3 integrations with LocalStack for development environments
## Dependencies
```xml
software.amazon.awssdk
s3
2.20.0 // Use the latest stable version
software.amazon.awssdk
s3-transfer-manager
2.20.0 // Use the latest stable version
software.amazon.awssdk
netty-nio-client
2.20.0 // Use the latest stable version
```
## Client Setup
### Basic Synchronous Client
```java
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
S3Client s3Client = S3Client.builder()
.region(Region.US_EAST_1)
.build();
```
### Basic Asynchronous Client
```java
import software.amazon.awssdk.services.s3.S3AsyncClient;
S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
.region(Region.US_EAST_1)
.build();
```
### Configured Client with Retry Logic
```java
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.core.retry.RetryPolicy;
import software.amazon.awssdk.core.retry.backoff.ExponentialRetryBackoff;
import java.time.Duration;
S3Client s3Client = S3Client.builder()
.region(Region.US_EAST_1)
.httpClientBuilder(ApacheHttpClient.builder()
.maxConnections(200)
.connectionTimeout(Duration.ofSeconds(5)))
.overrideConfiguration(b -> b
.apiCallTimeout(Duration.ofSeconds(60))
.apiCallAttemptTimeout(Duration.ofSeconds(30))
.retryPolicy(RetryPolicy.builder()
.numRetries(3)
.retryBackoffStrategy(ExponentialRetryBackoff.builder()
.baseDelay(Duration.ofSeconds(1))
.maxBackoffTime(Duration.ofSeconds(30))
.build())
.build()))
.build();
```
## Basic Bucket Operations
### Create Bucket
```java
import software.amazon.awssdk.services.s3.model.*;
import java.util.concurrent.CompletableFuture;
public void createBucket(S3Client s3Client, String bucketName) {
try {
CreateBucketRequest request = CreateBucketRequest.builder()
.bucket(bucketName)
.build();
s3Client.createBucket(request);
// Wait until bucket is ready
HeadBucketRequest waitRequest = HeadBucketRequest.builder()
.bucket(bucketName)
.build();
s3Client.waiter().waitUntilBucketExists(waitRequest);
System.out.println("Bucket created successfully: " + bucketName);
} catch (S3Exception e) {
System.err.println("Error creating bucket: " + e.awsErrorDetails().errorMessage());
throw e;
}
}
```
### List All Buckets
```java
public List listAllBuckets(S3Client s3Client) {
ListBucketsResponse response = s3Client.listBuckets();
return response.buckets().stream()
.map(Bucket::name)
.collect(Collectors.toList());
}
```
### Check if Bucket Exists
```java
public boolean bucketExists(S3Client s3Client, String bucketName) {
try {
HeadBucketRequest request = HeadBucketRequest.builder()
.bucket(bucketName)
.build();
s3Client.headBucket(request);
return true;
} catch (NoSuchBucketException e) {
return false;
}
}
```
## Basic Object Operations
### Upload File to S3
```java
import software.amazon.awssdk.core.sync.RequestBody;
import java.nio.file.Paths;
public void uploadFile(S3Client s3Client, String bucketName, String key, String filePath) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket(bucketName)
.key(key)
.build();
s3Client.putObject(request, RequestBody.fromFile(Paths.get(filePath)));
System.out.println("File uploaded: " + key);
}
```
### Download File from S3
```java
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import java.nio.file.Paths;
public void downloadFile(S3Client s3Client, String bucketName, String key, String destPath) {
GetObjectRequest request = GetObjectRequest.builder()
.bucket(bucketName)
.key(key)
.build();
s3Client.getObject(request, Paths.get(destPath));
System.out.println("File downloaded: " + destPath);
}
```
### Get Object Metadata
```java
public Map getObjectMetadata(S3Client s3Client, String bucketName, String key) {
HeadObjectRequest request = HeadObjectRequest.builder()
.bucket(bucketName)
.key(key)
.build();
HeadObjectResponse response = s3Client.headObject(request);
return response.metadata();
}
```
## Advanced Object Operations
### Upload with Metadata and Encryption
```java
public void uploadWithMetadata(S3Client s3Client, String bucketName, String key,
String filePath, Map metadata) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket(bucketName)
.key(key)
.metadata(metadata)
.contentType("application/pdf")
.serverSideEncryption(ServerSideEncryption.AES256)
.storageClass(StorageClass.STANDARD_IA)
.build();
PutObjectResponse response = s3Client.putObject(request,
RequestBody.fromFile(Paths.get(filePath)));
System.out.println("Upload completed. ETag: " + response.eTag());
}
```
### Copy Object Between Buckets
```java
public void copyObject(S3Client s3Client, String sourceBucket, String sourceKey,
String destBucket, String destKey) {
CopyObjectRequest request = CopyObjectRequest.builder()
.sourceBucket(sourceBucket)
.sourceKey(sourceKey)
.destinationBucket(destBucket)
.destinationKey(destKey)
.build();
s3Client.copyObject(request);
System.out.println("Object copied: " + sourceKey + " -> " + destKey);
}
```
### Delete Multiple Objects
```java
public void deleteMultipleObjects(S3Client s3Client, String bucketName, List keys) {
List objectIds = keys.stream()
.map(key -> ObjectIdentifier.builder().key(key).build())
.collect(Collectors.toList());
Delete delete = Delete.builder()
.objects(objectIds)
.build();
DeleteObjectsRequest request = DeleteObjectsRequest.builder()
.bucket(bucketName)
.delete(delete)
.build();
DeleteObjectsResponse response = s3Client.deleteObjects(request);
response.deleted().forEach(deleted ->
System.out.println("Deleted: " + deleted.key()));
response.errors().forEach(error ->
System.err.println("Failed to delete " + error.key() + ": " + error.message()));
}
```
## Presigned URLs
### Generate Download URL
```java
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.*;
import java.time.Duration;
public String generateDownloadUrl(String bucketName, String key) {
try (S3Presigner presigner = S3Presigner.builder()
.region(Region.US_EAST_1)
.build()) {
GetObjectRequest getObjectRequest = GetObjectRequest.builder()
.bucket(bucketName)
.key(key)
.build();
GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(10))
.getObjectRequest(getObjectRequest)
.build();
PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(presignRequest);
return presignedRequest.url().toString();
}
}
```
### Generate Upload URL
```java
public String generateUploadUrl(String bucketName, String key) {
try (S3Presigner presigner = S3Presigner.create()) {
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(bucketName)
.key(key)
.build();
PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(5))
.putObjectRequest(putObjectRequest)
.build();
PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest);
return presignedRequest.url().toString();
}
}
```
## S3 Transfer Manager
### Upload with Transfer Manager
```java
import software.amazon.awssdk.transfer.s3.*;
import software.amazon.awssdk.transfer.s3.model.*;
public void uploadWithTransferManager(String bucketName, String key, String filePath) {
try (S3TransferManager transferManager = S3TransferManager.create()) {
UploadFileRequest uploadRequest = UploadFileRequest.builder()
.putObjectRequest(req -> req
.bucket(bucketName)
.key(key))
.source(Paths.get(filePath))
.build();
FileUpload upload = transferManager.uploadFile(uploadRequest);
// Monitor progress
upload.progressFuture().thenAccept(progress -> {
System.out.println("Upload progress: " + progress.progressPercent() + "%");
});
CompletedFileUpload result = upload.completionFuture().join();
System.out.println("Upload complete. ETag: " + result.response().eTag());
}
}
```
### Download with Transfer Manager
```java
public void downloadWithTransferManager(String bucketName, String key, String destPath) {
try (S3TransferManager transferManager = S3TransferManager.create()) {
DownloadFileRequest downloadRequest = DownloadFileRequest.builder()
.getObjectRequest(req -> req
.bucket(bucketName)
.key(key))
.destination(Paths.get(destPath))
.build();
FileDownload download = transferManager.downloadFile(downloadRequest);
CompletedFileDownload result = download.completionFuture().join();
System.out.println("Download complete. Size: " + result.response().contentLength());
}
}
```
## Spring Boot Integration
### Configuration Properties
```java
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "aws.s3")
public class S3Properties {
private String accessKey;
private String secretKey;
private String region = "us-east-1";
private String endpoint;
private String defaultBucket;
private boolean asyncEnabled = false;
private boolean transferManagerEnabled = true;
// Getters and setters
public String getAccessKey() { return accessKey; }
public void setAccessKey(String accessKey) { this.accessKey = accessKey; }
// ... other getters and setters
}
```
### S3 Configuration Class
```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.regions.Region;
import java.net.URI;
@Configuration
public class S3Configuration {
private final S3Properties properties;
public S3Configuration(S3Properties properties) {
this.properties = properties;
}
@Bean
public S3Client s3Client() {
S3Client.Builder builder = S3Client.builder()
.region(Region.of(properties.getRegion()));
if (properties.getAccessKey() != null && properties.getSecretKey() != null) {
builder.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create(
properties.getAccessKey(),
properties.getSecretKey())));
}
if (properties.getEndpoint() != null) {
builder.endpointOverride(URI.create(properties.getEndpoint()));
}
return builder.build();
}
@Bean
public S3AsyncClient s3AsyncClient() {
S3AsyncClient.Builder builder = S3AsyncClient.builder()
.region(Region.of(properties.getRegion()));
if (properties.getAccessKey() != null && properties.getSecretKey() != null) {
builder.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create(
properties.getAccessKey(),
properties.getSecretKey())));
}
if (properties.getEndpoint() != null) {
builder.endpointOverride(URI.create(properties.getEndpoint()));
}
return builder.build();
}
@Bean
public S3TransferManager s3TransferManager() {
return S3TransferManager.builder()
.s3Client(s3Client())
.build();
}
}
```
### S3 Service
```java
import org.springframework.stereotype.Service;
import software.amazon.awssdk.transfer.s3.S3TransferManager;
import software.amazon.awssdk.services.s3.model.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@Service
@RequiredArgsConstructor
public class S3Service {
private final S3Client s3Client;
private final S3AsyncClient s3AsyncClient;
private final S3TransferManager transferManager;
private final S3Properties properties;
public CompletableFuture uploadFileAsync(String key, Path file) {
PutObjectRequest request = PutObjectRequest.builder()
.bucket(properties.getDefaultBucket())
.key(key)
.build();
return CompletableFuture.runAsync(() -> {
s3Client.putObject(request, RequestBody.fromFile(file));
});
}
public CompletableFuture downloadFileAsync(String key) {
GetObjectRequest request = GetObjectRequest.builder()
.bucket(properties.getDefaultBucket())
.key(key)
.build();
return CompletableFuture.supplyAsync(() -> {
try (ResponseInputStream response = s3Client.getObject(request)) {
return response.readAllBytes();
} catch (IOException e) {
throw new RuntimeException("Failed to read S3 object", e);
}
});
}
public CompletableFuture generatePresignedUrl(String key, Duration duration) {
return CompletableFuture.supplyAsync(() -> {
try (S3Presigner presigner = S3Presigner.builder()
.region(Region.of(properties.getRegion()))
.build()) {
GetObjectRequest getRequest = GetObjectRequest.builder()
.bucket(properties.getDefaultBucket())
.key(key)
.build();
GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder()
.signatureDuration(duration)
.getObjectRequest(getRequest)
.build();
return presigner.presignGetObject(presignRequest).url().toString();
}
});
}
public Flux listObjects(String prefix) {
ListObjectsV2Request request = ListObjectsV2Request.builder()
.bucket(properties.getDefaultBucket())
.prefix(prefix)
.build();
return Flux.create(sink -> {
s3Client.listObjectsV2Paginator(request)
.contents()
.forEach(sink::next);
sink.complete();
});
}
}
```
## Examples
### Basic File Upload Example
```java
public class S3UploadExample {
public static void main(String[] args) {
// Initialize client
S3Client s3Client = S3Client.builder()
.region(Region.US_EAST_1)
.build();
String bucketName = "my-example-bucket";
String filePath = "document.pdf";
String key = "uploads/document.pdf";
// Create bucket if it doesn't exist
if (!bucketExists(s3Client, bucketName)) {
createBucket(s3Client, bucketName);
}
// Upload file
Map metadata = Map.of(
"author", "John Doe",
"content-type", "application/pdf",
"upload-date", java.time.LocalDate.now().toString()
);
uploadWithMetadata(s3Client, bucketName, key, filePath, metadata);
// Generate presigned URL
String downloadUrl = generateDownloadUrl(bucketName, key);
System.out.println("Download URL: " + downloadUrl);
// Close client
s3Client.close();
}
}
```
### Batch File Processing Example
```java
import java.nio.file.*;
import java.util.stream.*;
public class S3BatchProcessing {
public void processDirectoryUpload(S3Client s3Client, String bucketName, String directoryPath) {
try (Stream paths = Files.walk(Paths.get(directoryPath))) {
List> futures = paths
.filter(Files::isRegularFile)
.map(path -> {
String key = bucketName + "/" + path.getFileName().toString();
return CompletableFuture.runAsync(() -> {
uploadFile(s3Client, bucketName, key, path.toString());
});
})
.collect(Collectors.toList());
// Wait for all uploads to complete
CompletableFuture.allOf(
futures.toArray(new CompletableFuture[0])
).join();
System.out.println("All files uploaded successfully");
} catch (IOException e) {
throw new RuntimeException("Failed to process directory", e);
}
}
}
```
## Best Practices
### Performance Optimization
1. **Use S3 Transfer Manager**: Automatically handles multipart uploads, parallel transfers, and progress tracking for files >100MB
2. **Reuse S3 Client**: Clients are thread-safe and should be reused throughout the application lifecycle
3. **Enable async operations**: Use S3AsyncClient for I/O-bound operations to improve throughput
4. **Configure proper timeouts**: Set appropriate timeouts for large file operations
5. **Use connection pooling**: Configure HTTP client for optimal connection management
### Security Considerations
1. **Use temporary credentials**: Always use IAM roles or AWS STS for short-lived access tokens
2. **Enable server-side encryption**: Use AES-256 or AWS KMS for sensitive data
3. **Implement access controls**: Use bucket policies and IAM roles instead of access keys in production
4. **Validate object metadata**: Sanitize user-provided metadata to prevent header injection
5. **Use presigned URLs**: Avoid exposing credentials by using temporary access URLs
### Error Handling
1. **Implement retry logic**: Network operations should have exponential backoff retry strategies
2. **Handle throttling**: Implement proper handling of 429 Too Many Requests responses
3. **Validate object existence**: Check if objects exist before operations that require them
4. **Clean up failed operations**: Abort multipart uploads that fail
5. **Log appropriately**: Log successful operations and errors for monitoring
### Cost Optimization
1. **Use appropriate storage classes**: Choose STANDARD, STANDARD_IA, INTELLIGENT_TIERING based on access patterns
2. **Implement lifecycle policies**: Automatically transition or expire objects
3. **Enable object versioning**: For important data that needs retention
4. **Monitor usage**: Track data transfer and storage costs
5. **Minimize API calls**: Use batch operations when possible
## Constraints and Limitations
- **File size limits**: Single PUT operations limited to 5GB; use multipart uploads for larger files
- **Batch operations**: Maximum 1000 objects per DeleteObjects operation
- **Metadata size**: User-defined metadata limited to 2KB
- **Concurrent transfers**: Transfer Manager handles up to 100 concurrent transfers by default
- **Region consistency**: Cross-region operations may incur additional costs and latency
- **S3 eventual consistency**: New objects might not be immediately visible after upload
## References
For more detailed information, see:
- [AWS S3 Object Operations Reference](./references/s3-object-operations.md)
- [S3 Transfer Manager Patterns](./references/s3-transfer-patterns.md)
- [Spring Boot Integration Guide](./references/s3-spring-boot-integration.md)
- [AWS S3 Developer Guide](https://docs.aws.amazon.com/AmazonS3/latest/userguide/)
- [AWS SDK for Java 2.x S3 API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/package-summary.html)
## Related Skills
- `aws-sdk-java-v2-core` - Core AWS SDK patterns and configuration
- `spring-boot-dependency`-injection - Spring dependency injection patterns
- `unit-test-service-layer` - Testing service layer patterns
- `unit-test-wiremock-rest-api` - Testing external API integrations