The AWS SDK for Java v2 makes S3 access straightforward once you’ve seen the right shape for it. This post walks through a minimal Spring Boot configuration, the YAML settings that drive it, a small service with the S3 operations you’ll use most, and an integration test that runs against a real S3 API — without touching AWS — using Testcontainers and LocalStack.

Dependencies

xml

<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.x.x</version>
</dependency>

application.yml

Keep credentials out of the YAML in real deployments — use environment variables, an instance profile, or a secrets manager. The block below shows the settings worth externalizing either way.

yaml

aws:
s3:
region: eu-central-1
bucket: my-app-bucket
endpoint: ${AWS_S3_ENDPOINT:} # only set for LocalStack/MinIO; blank for real AWS
path-style-access: false # true for LocalStack/MinIO

A matching @ConfigurationProperties class:

java

@ConfigurationProperties(prefix = "aws.s3")
public record S3Properties(
String region,
String bucket,
String endpoint,
boolean pathStyleAccess) {}

The S3Client bean

java

@Configuration
@EnableConfigurationProperties(S3Properties.class)
public class S3Config {
@Bean
public S3Client s3Client(S3Properties props) {
S3ClientBuilder builder = S3Client.builder()
.region(Region.of(props.region()))
.credentialsProvider(DefaultCredentialsProvider.create())
.serviceConfiguration(b -> b.pathStyleAccessEnabled(props.pathStyleAccess()));
if (props.endpoint() != null && !props.endpoint().isBlank()) {
builder.endpointOverride(URI.create(props.endpoint()));
}
return builder.build();
}
}

DefaultCredentialsProvider checks environment variables, system properties, the shared ~/.aws/credentials file, and the EC2/ECS instance role, in that order — so the same code works locally and in production without changes.

A minimal S3 service

java

@Service
public class S3StorageService {
private final S3Client s3Client;
private final String bucket;
public S3StorageService(S3Client s3Client, S3Properties props) {
this.s3Client = s3Client;
this.bucket = props.bucket();
}
public void upload(String key, byte[] content, String contentType) {
s3Client.putObject(
PutObjectRequest.builder()
.bucket(bucket)
.key(key)
.contentType(contentType)
.build(),
RequestBody.fromBytes(content));
}
public byte[] download(String key) {
return s3Client.getObject(
GetObjectRequest.builder().bucket(bucket).key(key).build(),
ResponseTransformer.toBytes()).asByteArray();
}
public List<String> listKeys(String prefix) {
return s3Client.listObjectsV2(
ListObjectsV2Request.builder()
.bucket(bucket)
.prefix(prefix)
.build())
.contents()
.stream()
.map(S3Object::key)
.toList();
}
public void delete(String key) {
s3Client.deleteObject(
DeleteObjectRequest.builder().bucket(bucket).key(key).build());
}
}

Four methods cover most day-to-day usage: putObject, getObject, listObjectsV2, and deleteObject. Everything else in the SDK is a variation on this same request/response builder pattern.

Kommentar verfassen

I’m Iman

Mein Name ist Iman Dabbaghi. Ich arbeite als Senior Software Engineer in der Schweiz. Außerdem interessiere ich mich sehr für gewaltfreie Kommunikation, Bachata-Tanz und Musik sowie fürs die Persönlichkeitsentwicklung.

Ich habe einen Masterabschluss in Informatik von der Universität Freiburg in Deutschland, bin Spring/Java Certified Professional (OCP), Certified Professional for Software Architecture (CPSA-F) und ein lebenslanger Lernender 🎓.

EN:

My name is Iman Dabbaghi. I work as a Senior Software Engineer in Switzerland. I am also very interessted in nonviolent communication, Bachata dance and music and also for personal development.

I hold a masters degree in computer science from the university of Freiburg in Germany, am a Spring / Java Certified Professional (OCP), Certified Software Architecture (CPSA-F) and Life Long Learner🎓

Let’s connect