aws-sdk-java
You must generate an Access Key before getting started. All examples will utilize access_key_id
and access_key_secret
variables which represent the Access Key ID and Secret Access Key values you generated.
This example uses version 2 of the aws-sdk-java ↗ package. You must pass in the R2 configuration credentials when instantiating your S3
service client:
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;import software.amazon.awssdk.regions.Region;import software.amazon.awssdk.services.s3.S3Client;import software.amazon.awssdk.services.s3.model.*;import software.amazon.awssdk.services.s3.S3Configuration;import java.net.URI;import java.util.List;
/** * Client for interacting with Cloudflare R2 Storage using AWS SDK S3 compatibility */public class CloudflareR2Client { private final S3Client s3Client;
/** * Creates a new CloudflareR2Client with the provided configuration */ public CloudflareR2Client(S3Config config) { this.s3Client = buildS3Client(config); }
/** * Configuration class for R2 credentials and endpoint */ public static class S3Config { private final String accountId; private final String accessKey; private final String secretKey; private final String endpoint;
public S3Config(String accountId, String accessKey, String secretKey) { this.accountId = accountId; this.accessKey = accessKey; this.secretKey = secretKey; this.endpoint = String.format("https://%s.r2.cloudflarestorage.com", accountId); }
public String getAccessKey() { return accessKey; } public String getSecretKey() { return secretKey; } public String getEndpoint() { return endpoint; } }
/** * Builds and configures the S3 client with R2-specific settings */ private static S3Client buildS3Client(S3Config config) { AwsBasicCredentials credentials = AwsBasicCredentials.create( config.getAccessKey(), config.getSecretKey() );
S3Configuration serviceConfiguration = S3Configuration.builder() .pathStyleAccessEnabled(true) .build();
return S3Client.builder() .endpointOverride(URI.create(config.getEndpoint())) .credentialsProvider(StaticCredentialsProvider.create(credentials)) .region(Region.of("auto")) .serviceConfiguration(serviceConfiguration) .build(); }
/** * Lists all buckets in the R2 storage */ public List<Bucket> listBuckets() { try { return s3Client.listBuckets().buckets(); } catch (S3Exception e) { throw new RuntimeException("Failed to list buckets: " + e.getMessage(), e); } }
/** * Lists all objects in the specified bucket */ public List<S3Object> listObjects(String bucketName) { try { ListObjectsV2Request request = ListObjectsV2Request.builder() .bucket(bucketName) .build();
return s3Client.listObjectsV2(request).contents(); } catch (S3Exception e) { throw new RuntimeException("Failed to list objects in bucket " + bucketName + ": " + e.getMessage(), e); } }
public static void main(String[] args) { S3Config config = new S3Config( "your_account_id", "your_access_key", "your_secret_key" );
CloudflareR2Client r2Client = new CloudflareR2Client(config);
// List buckets System.out.println("Available buckets:"); r2Client.listBuckets().forEach(bucket -> System.out.println("* " + bucket.name()) );
// List objects in a specific bucket String bucketName = "demos"; System.out.println("\nObjects in bucket '" + bucketName + "':"); r2Client.listObjects(bucketName).forEach(object -> System.out.printf("* %s (size: %d bytes, modified: %s)%n", object.key(), object.size(), object.lastModified()) ); }}
You can also generate presigned links that can be used to temporarily share public write access to a bucket.
// import required packages for presigning// Rest of the packages are same as aboveimport software.amazon.awssdk.services.s3.presigner.S3Presigner;import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;import java.time.Duration;
public class CloudflareR2Client { private final S3Client s3Client; private final S3Presigner presigner;
/** * Creates a new CloudflareR2Client with the provided configuration */ public CloudflareR2Client(S3Config config) { this.s3Client = buildS3Client(config); this.presigner = buildS3Presigner(config); }
/** * Builds and configures the S3 presigner with R2-specific settings */ private static S3Presigner buildS3Presigner(S3Config config) { AwsBasicCredentials credentials = AwsBasicCredentials.create( config.getAccessKey(), config.getSecretKey() );
return S3Presigner.builder() .endpointOverride(URI.create(config.getEndpoint())) .credentialsProvider(StaticCredentialsProvider.create(credentials)) .region(Region.of("auto")) .serviceConfiguration(S3Configuration.builder() .pathStyleAccessEnabled(true) .build()) .build(); }
public String generatePresignedUploadUrl(String bucketName, String objectKey, Duration expiration) { PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder() .signatureDuration(expiration) .putObjectRequest(builder -> builder .bucket(bucketName) .key(objectKey) .build()) .build();
PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest); return presignedRequest.url().toString(); }
// Rest of the methods remains the same
public static void main(String[] args) { // config the client as before
// Generate a pre-signed upload URL valid for 15 minutes String uploadUrl = r2Client.generatePresignedUploadUrl( "demos", "README.md", Duration.ofMinutes(15) ); System.out.println("Pre-signed Upload URL (valid for 15 minutes):"); System.out.println(uploadUrl); }
}