Repository: aws/aws-sdk-java-v2
Pull request #6024: Change response types for POJOs that map one to many
Author: login: davidh44
Created: 2025-04-10T22:56:25Z | Merged: 2025-04-16T03:33:42Z

<!--- Provide a general summary of your changes in the Title above -->

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here -->
There are a handful of POJOs in v1 that map to two types in v2. For instance, v1 `AccessControlList` is used as input to `setObjectAcl()`, and also returned as response from `getObjectAcl()`.

In v2, `AccessControlPolicy` is used as input, while `GetObjectAclResponse` is returned as the response.

## Modifications
<!--- Describe your changes in detail -->
Forked `ChangeMethodInvocationReturnType` recipe from OpenRewrite. It is a newer recipe so requires OR version bump, which introduces breaking changes with existing SDK recipes.

https://github.com/openrewrite/rewrite/blob/main/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodInvocationReturnType.java

Using this recipe to correctly change response types based on the method, returning the following responses:

```
GetObjectResponse
GetBucketAclResponse
GetObjectAclResponse
GetBucketAccelerateConfigurationResponse
GetBucketLifecycleConfigurationResponse
GetBucketCorsResponse
GetBucketLoggingResponse
GetBucketNotificationConfigurationResponse
GetBucketPolicyResponse
GetBucketReplicationResponse
GetBucketTaggingResponse
GetBucketVersioningResponse
GetBucketWebsiteResponse
```

Additional changes:

- Map `AmazonS3Exception` to `S3Exception`
- Map `BucketLoggingConfiguration` to `BucketLoggingStatus`
- Revert converting `CannedAccessControlList` to `ObjectCannedACL`
  - We will leave as v1 POJO, and add comments in follow up PR to tell users to manually change to the appropriate v2 enum based on the method used, i.e. `BucketCannedACL` or `ObjectCannedACL`
- Replace `BucketName` with `Bucket` in getter methods (already in place for setters)
- Transform `getBucketLocation()` to append `locationConstraint().toString()` as v1 returns the String region


## Testing
<!--- Please describe in detail how you tested your changes -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
Added end to end tests



Diff:
diff --git a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-nocompile/after/src/main/java/foo/bar/S3Transforms.java b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-nocompile/after/src/main/java/foo/bar/S3Transforms.java
index 477446b0d64d..a55fd9c439d1 100644
--- a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-nocompile/after/src/main/java/foo/bar/S3Transforms.java
+++ b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven-nocompile/after/src/main/java/foo/bar/S3Transforms.java
@@ -49,11 +49,11 @@ void s3Pojos() {
     }
 
     void setBucketAcl() {
-        /*AWS SDK for Java v2 migration: Transform for AccessControlList and CannedAccessControlList not supported. In v2, CannedAccessControlList is replaced by BucketCannedACL for buckets and ObjectCannedACL for objects.*/s3.setBucketAcl(bucket, ObjectCannedACL.AUTHENTICATED_READ);
+        /*AWS SDK for Java v2 migration: Transform for AccessControlList and CannedAccessControlList not supported. In v2, CannedAccessControlList is replaced by BucketCannedACL for buckets and ObjectCannedACL for objects.*/s3.setBucketAcl(bucket, CannedAccessControlList.AuthenticatedRead);
     }
 
     void setObjectAcl() {
-        /*AWS SDK for Java v2 migration: Transform for AccessControlList and CannedAccessControlList not supported. In v2, CannedAccessControlList is replaced by BucketCannedACL for buckets and ObjectCannedACL for objects.*/s3.setObjectAcl(bucket, key, ObjectCannedACL.PUBLIC_READ);
+        /*AWS SDK for Java v2 migration: Transform for AccessControlList and CannedAccessControlList not supported. In v2, CannedAccessControlList is replaced by BucketCannedACL for buckets and ObjectCannedACL for objects.*/s3.setObjectAcl(bucket, key, CannedAccessControlList.PublicRead);
     }
 
     void upload_streamWithLiteralLength(S3TransferManager tm) {
diff --git a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3.java b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3.java
index 7a04f09d2965..d7ae361af563 100644
--- a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3.java
+++ b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3.java
@@ -253,7 +253,7 @@ private void singleBucketArgMethods(S3Client s3, String bucket) {
         s3.getBucketPolicy(GetBucketPolicyRequest.builder().bucket(bucket)
             .build());
         s3.getBucketLocation(GetBucketLocationRequest.builder().bucket(bucket)
-            .build());
+            .build()).locationConstraint().toString();
         s3.deleteBucketLifecycle(DeleteBucketLifecycleRequest.builder().bucket(bucket)
             .build());
         s3.deleteBucketReplication(DeleteBucketReplicationRequest.builder().bucket(bucket)
diff --git a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3RequestConstructor.java b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3RequestConstructor.java
index 9bbc79e56fd9..c8a659be9f70 100644
--- a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3RequestConstructor.java
+++ b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3RequestConstructor.java
@@ -21,6 +21,7 @@
 import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.AbortMultipartUploadRequest;
 import software.amazon.awssdk.services.s3.model.AnalyticsConfiguration;
+import software.amazon.awssdk.services.s3.model.Bucket;
 import software.amazon.awssdk.services.s3.model.BucketLifecycleConfiguration;
 import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest;
 import software.amazon.awssdk.services.s3.model.CompletedMultipartUpload;
@@ -45,10 +46,13 @@
 import software.amazon.awssdk.services.s3.model.DeleteObjectsRequest;
 import software.amazon.awssdk.services.s3.model.DeletePublicAccessBlockRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketAccelerateConfigurationRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketAccelerateConfigurationResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketAclRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketAclResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketAnalyticsConfigurationRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketAnalyticsConfigurationResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketCorsRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketCorsResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketEncryptionRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketEncryptionResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketIntelligentTieringConfigurationRequest;
@@ -56,22 +60,31 @@
 import software.amazon.awssdk.services.s3.model.GetBucketInventoryConfigurationRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketInventoryConfigurationResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketLifecycleConfigurationRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketLifecycleConfigurationResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketLocationRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketLoggingRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketLoggingResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketMetricsConfigurationRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketMetricsConfigurationResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketNotificationConfigurationRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketNotificationConfigurationResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketOwnershipControlsRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketOwnershipControlsResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketPolicyRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketPolicyResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketPolicyStatusRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketPolicyStatusResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketReplicationRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketReplicationResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketRequestPaymentRequest;
 import software.amazon.awssdk.services.s3.model.GetBucketTaggingRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketTaggingResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketVersioningRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketVersioningResponse;
 import software.amazon.awssdk.services.s3.model.GetBucketWebsiteRequest;
+import software.amazon.awssdk.services.s3.model.GetBucketWebsiteResponse;
 import software.amazon.awssdk.services.s3.model.GetObjectAclRequest;
+import software.amazon.awssdk.services.s3.model.GetObjectAclResponse;
 import software.amazon.awssdk.services.s3.model.GetObjectLegalHoldRequest;
 import software.amazon.awssdk.services.s3.model.GetObjectLegalHoldResponse;
 import software.amazon.awssdk.services.s3.model.GetObjectLockConfigurationRequest;
@@ -205,12 +218,11 @@ public void requestconstructor() {
         s3.deletePublicAccessBlock(DeletePublicAccessBlockRequest.builder()
             .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketAccelerateConfiguration(GetBucketAccelerateConfigurationRequest.builder().bucket(bucketName)
-            .build());
+        GetBucketAccelerateConfigurationResponse bucketAccelerateConfiguration =
+            s3.getBucketAccelerateConfiguration(GetBucketAccelerateConfigurationRequest.builder().bucket(bucketName)
+                .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketAcl(GetBucketAclRequest.builder().bucket(bucketName)
+        GetBucketAclResponse bucketAcl = s3.getBucketAcl(GetBucketAclRequest.builder().bucket(bucketName)
             .build());
 
         GetBucketAnalyticsConfigurationResponse analyticsConfig = s3.getBucketAnalyticsConfiguration(
@@ -221,9 +233,9 @@ public void requestconstructor() {
             GetBucketAnalyticsConfigurationRequest.builder().bucket("1").id("2")
                 .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketCors(GetBucketCorsRequest.builder().bucket(bucketName)
-            .build());
+        GetBucketCorsResponse bucketCors =
+            s3.getBucketCors(GetBucketCorsRequest.builder().bucket(bucketName)
+                .build());
 
         GetBucketEncryptionResponse encryptionResult = s3.getBucketEncryption(
             GetBucketEncryptionRequest.builder()
@@ -245,17 +257,16 @@ public void requestconstructor() {
             GetBucketInventoryConfigurationRequest.builder().bucket("1").id("2")
                 .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketLifecycleConfiguration(GetBucketLifecycleConfigurationRequest.builder().bucket(bucketName)
-            .build());
+        GetBucketLifecycleConfigurationResponse bucketLifecycleConfiguration =
+            s3.getBucketLifecycleConfiguration(GetBucketLifecycleConfigurationRequest.builder().bucket(bucketName)
+                .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketLocation(GetBucketLocationRequest.builder().bucket(bucketName)
-            .build());
+        String region = s3.getBucketLocation(GetBucketLocationRequest.builder().bucket(bucketName)
+            .build()).locationConstraint().toString();
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketLogging(GetBucketLoggingRequest.builder().bucket(bucketName)
-            .build());
+        GetBucketLoggingResponse bucketLoggingConfiguration =
+            s3.getBucketLogging(GetBucketLoggingRequest.builder().bucket(bucketName)
+                .build());
 
         GetBucketMetricsConfigurationResponse metricsConfig = s3.getBucketMetricsConfiguration(
             GetBucketMetricsConfigurationRequest.builder()
@@ -265,37 +276,36 @@ public void requestconstructor() {
             GetBucketMetricsConfigurationRequest.builder().bucket("1").id("2")
                 .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketNotificationConfiguration(GetBucketNotificationConfigurationRequest.builder().bucket(bucketName)
-            .build());
+        GetBucketNotificationConfigurationResponse bucketNotificationConfiguration =
+            s3.getBucketNotificationConfiguration(GetBucketNotificationConfigurationRequest.builder().bucket(bucketName)
+                .build());
 
         GetBucketOwnershipControlsResponse ownershipControls = s3.getBucketOwnershipControls(
             GetBucketOwnershipControlsRequest.builder()
                 .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketPolicy(GetBucketPolicyRequest.builder().bucket(bucketName)
+        GetBucketPolicyResponse bucketPolicy = s3.getBucketPolicy(GetBucketPolicyRequest.builder().bucket(bucketName)
             .build());
 
         GetBucketPolicyStatusResponse policyStatus = s3.getBucketPolicyStatus(
             GetBucketPolicyStatusRequest.builder()
                 .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketReplication(GetBucketReplicationRequest.builder().bucket(bucketName)
-            .build());
+        GetBucketReplicationResponse bucketReplicationConfiguration =
+            s3.getBucketReplication(GetBucketReplicationRequest.builder().bucket(bucketName)
+                .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketTagging(GetBucketTaggingRequest.builder().bucket(bucketName)
-            .build());
+        GetBucketTaggingResponse bucketTaggingConfiguration =
+            s3.getBucketTagging(GetBucketTaggingRequest.builder().bucket(bucketName)
+                .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketVersioning(GetBucketVersioningRequest.builder().bucket(bucketName)
-            .build());
+        GetBucketVersioningResponse bucketVersioningConfiguration =
+            s3.getBucketVersioning(GetBucketVersioningRequest.builder().bucket(bucketName)
+                .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketWebsite(GetBucketWebsiteRequest.builder().bucket(bucketName)
-            .build());
+        GetBucketWebsiteResponse bucketWebsiteConfiguration =
+            s3.getBucketWebsite(GetBucketWebsiteRequest.builder().bucket(bucketName)
+                .build());
 
         ResponseInputStream<GetObjectResponse> s3Object1 = s3.getObject(
             GetObjectRequest.builder().bucket(bucketName).key(objectKey)
@@ -311,12 +321,10 @@ public void requestconstructor() {
         GetObjectRequest getObjectRequestRequesterPaysFalse = GetObjectRequest.builder().bucket(bucketName).key(objectKey)
             .build();
 
-        //INCOMPATIBLE RESPONSE
-        s3.getObjectAcl(GetObjectAclRequest.builder().bucket(bucketName).key(objectKey)
+        GetObjectAclResponse objectAcl = s3.getObjectAcl(GetObjectAclRequest.builder().bucket(bucketName).key(objectKey)
             .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getObjectAcl(GetObjectAclRequest.builder().bucket(bucketName).key(objectKey).versionId("3")
+        GetObjectAclResponse objectAcl2 = s3.getObjectAcl(GetObjectAclRequest.builder().bucket(bucketName).key(objectKey).versionId("3")
             .build());
 
         GetObjectLegalHoldResponse legalHoldResult = s3.getObjectLegalHold(
@@ -371,9 +379,7 @@ public void requestconstructor() {
             ListBucketMetricsConfigurationsRequest.builder()
                 .build());
 
-        //INCOMPATIBLE RESPONSE
-        s3.listBuckets(ListBucketsRequest.builder()
-            .build());
+        List<Bucket> buckets = s3.listBuckets().buckets();
 
         ListObjectsResponse objectListing = s3.listObjects(
             ListObjectsRequest.builder()
diff --git a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3Streaming.java b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3Streaming.java
index 571d89f6d61f..bccb2eae944b 100644
--- a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3Streaming.java
+++ b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3Streaming.java
@@ -29,7 +29,6 @@
 import software.amazon.awssdk.services.s3.model.GetObjectRequest;
 import software.amazon.awssdk.services.s3.model.GetObjectResponse;
 import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
-import software.amazon.awssdk.services.s3.model.ObjectCannedACL;
 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
 import software.amazon.awssdk.services.s3.model.RequestPayer;
 import software.amazon.awssdk.services.s3.model.Tag;
@@ -44,8 +43,8 @@ void getObject(String bucket, String key, File file) throws Exception {
             .build());
         s3Object.close();
 
-        s3.getObject(GetObjectRequest.builder().bucket(bucket).key(key)
-            .build(), file.toPath());
+        GetObjectResponse objectMetadata = s3.getObject(GetObjectRequest.builder().bucket(bucket).key(key)
+                .build(), file.toPath());
     }
 
     void putObject_bucketKeyContent(String bucket, String key, String content) {
@@ -125,7 +124,6 @@ void putObjectSetters() {
             PutObjectRequest.builder().bucket("bucket").key("key").websiteRedirectLocation("location")
                 .bucket("bucketName")
                 .websiteRedirectLocation("redirectLocation")
-                .acl(ObjectCannedACL.AWS_EXEC_READ)
                 .tagging(objectTagging)
             .build();
     }
diff --git a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/before/src/main/java/foo/bar/S3RequestConstructor.java b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/before/src/main/java/foo/bar/S3RequestConstructor.java
index 4eae60977c07..174594426a36 100644
--- a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/before/src/main/java/foo/bar/S3RequestConstructor.java
+++ b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/before/src/main/java/foo/bar/S3RequestConstructor.java
@@ -18,11 +18,18 @@
 import com.amazonaws.services.s3.AmazonS3;
 import com.amazonaws.services.s3.AmazonS3ClientBuilder;
 import com.amazonaws.services.s3.model.AbortMultipartUploadRequest;
+import com.amazonaws.services.s3.model.AccessControlList;
+import com.amazonaws.services.s3.model.Bucket;
+import com.amazonaws.services.s3.model.BucketAccelerateConfiguration;
+import com.amazonaws.services.s3.model.BucketCrossOriginConfiguration;
 import com.amazonaws.services.s3.model.BucketLifecycleConfiguration;
+import com.amazonaws.services.s3.model.BucketLoggingConfiguration;
 import com.amazonaws.services.s3.model.BucketNotificationConfiguration;
+import com.amazonaws.services.s3.model.BucketPolicy;
 import com.amazonaws.services.s3.model.BucketReplicationConfiguration;
 import com.amazonaws.services.s3.model.BucketTaggingConfiguration;
 import com.amazonaws.services.s3.model.BucketVersioningConfiguration;
+import com.amazonaws.services.s3.model.BucketWebsiteConfiguration;
 import com.amazonaws.services.s3.model.CompleteMultipartUploadRequest;
 import com.amazonaws.services.s3.model.CopyObjectRequest;
 import com.amazonaws.services.s3.model.CopyPartRequest;
@@ -178,11 +185,10 @@ public void requestconstructor() {
 
         s3.deletePublicAccessBlock(new DeletePublicAccessBlockRequest());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketAccelerateConfiguration(new GetBucketAccelerateConfigurationRequest(bucketName));
+        BucketAccelerateConfiguration bucketAccelerateConfiguration =
+            s3.getBucketAccelerateConfiguration(new GetBucketAccelerateConfigurationRequest(bucketName));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketAcl(new GetBucketAclRequest(bucketName));
+        AccessControlList bucketAcl = s3.getBucketAcl(new GetBucketAclRequest(bucketName));
 
         GetBucketAnalyticsConfigurationResult analyticsConfig = s3.getBucketAnalyticsConfiguration(
             new GetBucketAnalyticsConfigurationRequest());
@@ -190,8 +196,8 @@ public void requestconstructor() {
         GetBucketAnalyticsConfigurationResult analyticsConfig2 = s3.getBucketAnalyticsConfiguration(
             new GetBucketAnalyticsConfigurationRequest("1","2"));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketCrossOriginConfiguration(new GetBucketCrossOriginConfigurationRequest(bucketName));
+        BucketCrossOriginConfiguration bucketCors =
+            s3.getBucketCrossOriginConfiguration(new GetBucketCrossOriginConfigurationRequest(bucketName));
 
         GetBucketEncryptionResult encryptionResult = s3.getBucketEncryption(
             new GetBucketEncryptionRequest());
@@ -208,14 +214,13 @@ public void requestconstructor() {
         GetBucketInventoryConfigurationResult inventoryConfig2 = s3.getBucketInventoryConfiguration(
             new GetBucketInventoryConfigurationRequest("1","2"));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketLifecycleConfiguration(new GetBucketLifecycleConfigurationRequest(bucketName));
+        BucketLifecycleConfiguration bucketLifecycleConfiguration =
+            s3.getBucketLifecycleConfiguration(new GetBucketLifecycleConfigurationRequest(bucketName));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketLocation(new GetBucketLocationRequest(bucketName));
+        String region = s3.getBucketLocation(new GetBucketLocationRequest(bucketName));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketLoggingConfiguration(new GetBucketLoggingConfigurationRequest(bucketName));
+        BucketLoggingConfiguration bucketLoggingConfiguration =
+            s3.getBucketLoggingConfiguration(new GetBucketLoggingConfigurationRequest(bucketName));
 
         GetBucketMetricsConfigurationResult metricsConfig = s3.getBucketMetricsConfiguration(
             new GetBucketMetricsConfigurationRequest());
@@ -223,29 +228,28 @@ public void requestconstructor() {
         GetBucketMetricsConfigurationResult metricsConfig2 = s3.getBucketMetricsConfiguration(
             new GetBucketMetricsConfigurationRequest("1","2"));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketNotificationConfiguration(new GetBucketNotificationConfigurationRequest(bucketName));
+        BucketNotificationConfiguration bucketNotificationConfiguration =
+            s3.getBucketNotificationConfiguration(new GetBucketNotificationConfigurationRequest(bucketName));
 
         GetBucketOwnershipControlsResult ownershipControls = s3.getBucketOwnershipControls(
             new GetBucketOwnershipControlsRequest());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketPolicy(new GetBucketPolicyRequest(bucketName));
+        BucketPolicy bucketPolicy = s3.getBucketPolicy(new GetBucketPolicyRequest(bucketName));
 
         GetBucketPolicyStatusResult policyStatus = s3.getBucketPolicyStatus(
             new GetBucketPolicyStatusRequest());
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketReplicationConfiguration(new GetBucketReplicationConfigurationRequest(bucketName));
+        BucketReplicationConfiguration bucketReplicationConfiguration =
+            s3.getBucketReplicationConfiguration(new GetBucketReplicationConfigurationRequest(bucketName));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketTaggingConfiguration(new GetBucketTaggingConfigurationRequest(bucketName));
+        BucketTaggingConfiguration bucketTaggingConfiguration =
+            s3.getBucketTaggingConfiguration(new GetBucketTaggingConfigurationRequest(bucketName));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketVersioningConfiguration(new GetBucketVersioningConfigurationRequest(bucketName));
+        BucketVersioningConfiguration bucketVersioningConfiguration =
+            s3.getBucketVersioningConfiguration(new GetBucketVersioningConfigurationRequest(bucketName));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getBucketWebsiteConfiguration(new GetBucketWebsiteConfigurationRequest(bucketName));
+        BucketWebsiteConfiguration bucketWebsiteConfiguration =
+            s3.getBucketWebsiteConfiguration(new GetBucketWebsiteConfigurationRequest(bucketName));
 
         S3Object s3Object1 = s3.getObject(
             new GetObjectRequest(bucketName, objectKey));
@@ -257,11 +261,9 @@ public void requestconstructor() {
 
         GetObjectRequest getObjectRequestRequesterPaysFalse = new GetObjectRequest(bucketName, objectKey, false);
 
-        //INCOMPATIBLE RESPONSE
-        s3.getObjectAcl(new GetObjectAclRequest(bucketName, objectKey));
+        AccessControlList objectAcl = s3.getObjectAcl(new GetObjectAclRequest(bucketName, objectKey));
 
-        //INCOMPATIBLE RESPONSE
-        s3.getObjectAcl(new GetObjectAclRequest(bucketName, objectKey, "3"));
+        AccessControlList objectAcl2 = s3.getObjectAcl(new GetObjectAclRequest(bucketName, objectKey, "3"));
 
         GetObjectLegalHoldResult legalHoldResult = s3.getObjectLegalHold(
             new GetObjectLegalHoldRequest());
@@ -302,8 +304,7 @@ public void requestconstructor() {
         ListBucketMetricsConfigurationsResult metricsConfigs = s3.listBucketMetricsConfigurations(
             new ListBucketMetricsConfigurationsRequest());
 
-        //INCOMPATIBLE RESPONSE
-        s3.listBuckets(new ListBucketsRequest());
+        List<Bucket> buckets = s3.listBuckets(new ListBucketsRequest());
 
         ObjectListing objectListing = s3.listObjects(
             new ListObjectsRequest());
diff --git a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/before/src/main/java/foo/bar/S3Streaming.java b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/before/src/main/java/foo/bar/S3Streaming.java
index 49b79dc43c98..fe68378df8ec 100644
--- a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/before/src/main/java/foo/bar/S3Streaming.java
+++ b/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/before/src/main/java/foo/bar/S3Streaming.java
@@ -17,7 +17,6 @@
 
 import com.amazonaws.services.s3.AmazonS3;
 import com.amazonaws.services.s3.AmazonS3ClientBuilder;
-import com.amazonaws.services.s3.model.CannedAccessControlList;
 import com.amazonaws.services.s3.model.GetObjectRequest;
 import com.amazonaws.services.s3.model.ObjectMetadata;
 import com.amazonaws.services.s3.model.ObjectTagging;
@@ -41,7 +40,7 @@ void getObject(String bucket, String key, File file) throws Exception {
         S3Object s3Object = s3.getObject(bucket, key);
         s3Object.getObjectContent().close();
 
-        s3.getObject(new GetObjectRequest(bucket, key), file);
+        ObjectMetadata objectMetadata = s3.getObject(new GetObjectRequest(bucket, key), file);
     }
 
     void putObject_bucketKeyContent(String bucket, String key, String content) {
@@ -111,7 +110,6 @@ void putObjectSetters() {
             new PutObjectRequest("bucket", "key", "location")
                 .withBucketName("bucketName")
                 .withRedirectLocation("redirectLocation")
-                .withCannedAcl(CannedAccessControlList.AwsExecRead)
                 .withTagging(objectTagging);
     }
 
diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3NonStreamingRequestToV2Complex.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3NonStreamingRequestToV2Complex.java
index 69fc479b8900..b05f41da02f6 100644
--- a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3NonStreamingRequestToV2Complex.java
+++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3NonStreamingRequestToV2Complex.java
@@ -60,7 +60,8 @@ public class S3NonStreamingRequestToV2Complex extends Recipe {
     private static final MethodMatcher GET_OBJECT_WITH_FILE =
         v2S3MethodMatcher(String.format("getObject(%sGetObjectRequest, java.io.File)", V2_S3_MODEL_PKG));
     private static final MethodMatcher GET_URL = v2S3MethodMatcher("getUrl(String, String)");
-    private static final MethodMatcher LIST_BUCKETS = v2S3MethodMatcher("listBuckets()");
+    private static final MethodMatcher LIST_BUCKETS = v2S3MethodMatcher("listBuckets(..)");
+    private static final MethodMatcher GET_BUCKET_LOCATION = v2S3MethodMatcher("getBucketLocation(..)");
     private static final MethodMatcher RESTORE_OBJECT = v2S3MethodMatcher("restoreObject(String, String, int)");
     private static final MethodMatcher SET_OBJECT_REDIRECT_LOCATION =
         v2S3MethodMatcher("setObjectRedirectLocation(String, String, String)");
@@ -104,6 +105,9 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
             if (isGetS3AccountOwner(method)) {
                 return transformGetS3AccountOwner(method);
             }
+            if (GET_BUCKET_LOCATION.matches(method, false)) {
+                return transformGetBucketLocation(method);
+            }
             if (DISABLE_REQUESTER_PAYS.matches(method, false)) {
                 return transformSetRequesterPays(method, false);
             }
@@ -248,6 +252,13 @@ private J.MethodInvocation transformGetS3AccountOwner(J.MethodInvocation method)
                                .apply(getCursor(), method.getCoordinates().replace(), method.getSelect());
         }
 
+        private J.MethodInvocation transformGetBucketLocation(J.MethodInvocation method) {
+            String v2Method = "#{any()}.getBucketLocation(#{any()}).locationConstraint().toString()";
+            return JavaTemplate.builder(v2Method).build()
+                               .apply(getCursor(), method.getCoordinates().replace(), method.getSelect(),
+                                      method.getArguments().get(0));
+        }
+
         private J.MethodInvocation transformCreateBucket(J.MethodInvocation method) {
             addImport("CreateBucketRequest");
             addImport("CreateBucketConfiguration");
diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/V1GetterToV2.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/V1GetterToV2.java
index 829bcacacd4f..b9b1616f4d2b 100644
--- a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/V1GetterToV2.java
+++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/V1GetterToV2.java
@@ -15,6 +15,7 @@
 
 package software.amazon.awssdk.v2migration;
 
+import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.changeBucketNameToBucket;
 import static software.amazon.awssdk.v2migration.internal.utils.SdkTypeUtils.isV2ModelClass;
 
 import org.openrewrite.ExecutionContext;
@@ -62,6 +63,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
                 return method;
             }
 
+            methodName = changeBucketNameToBucket(methodName);
+
             if (NamingUtils.isGetter(methodName)) {
                 methodName = NamingUtils.removeGet(methodName);
             }
diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/V1SetterToV2.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/V1SetterToV2.java
index 9fe68121ee3e..3106fea3d065 100644
--- a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/V1SetterToV2.java
+++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/V1SetterToV2.java
@@ -15,6 +15,7 @@
 
 package software.amazon.awssdk.v2migration;
 
+import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.changeBucketNameToBucket;
 import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.hasArguments;
 import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isS3PutObjectOrObjectMetadata;
 import static software.amazon.awssdk.v2migration.internal.utils.SdkTypeUtils.isEligibleToConvertToBuilder;
@@ -102,9 +103,7 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation previousMetho
                 return method;
             }
 
-            if (methodName.contains("BucketName")) {
-                methodName = methodName.replace("BucketName", "Bucket");
-            }
+            methodName = changeBucketNameToBucket(methodName);
 
             if (NamingUtils.isWither(methodName)) {
                 methodName = NamingUtils.removeWith(methodName);
diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/NamingConversionUtils.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/NamingConversionUtils.java
index d90a894fd3f3..98e9cdd2b9e9 100644
--- a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/NamingConversionUtils.java
+++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/NamingConversionUtils.java
@@ -164,19 +164,12 @@ public final class NamingConversionUtils {
         S3_POJO_MAPPING.put("SetBucketVersioningConfigurationRequest", "PutBucketVersioningRequest");
 
         S3_POJO_MAPPING.put("CorsRule", "CORSRule");
-        S3_POJO_MAPPING.put("BucketCrossOriginConfiguration", "CORSConfiguration");
-        S3_POJO_MAPPING.put("BucketAccelerateConfiguration", "AccelerateConfiguration");
-        S3_POJO_MAPPING.put("BucketNotificationConfiguration", "NotificationConfiguration");
-        S3_POJO_MAPPING.put("BucketReplicationConfiguration", "ReplicationConfiguration");
-        S3_POJO_MAPPING.put("BucketTaggingConfiguration", "Tagging");
-        S3_POJO_MAPPING.put("BucketWebsiteConfiguration", "WebsiteConfiguration");
         S3_POJO_MAPPING.put("LifecycleFilter", "LifecycleRuleFilter");
         S3_POJO_MAPPING.put("LifecycleAndOperator", "LifecycleRuleAndOperator");
         S3_POJO_MAPPING.put("ReplicationFilter", "ReplicationRuleFilter");
         S3_POJO_MAPPING.put("ReplicationAndOperator", "ReplicationRuleAndOperator");
         S3_POJO_MAPPING.put("PartETag", "CompletedPart");
         S3_POJO_MAPPING.put("ObjectTagging", "Tagging");
-        S3_POJO_MAPPING.put("AccessControlList", "AccessControlPolicy");
         S3_POJO_MAPPING.put("BucketPolicy", "GetBucketPolicyResponse");
         S3_POJO_MAPPING.put("CanonicalGrantee", "Grantee");
         S3_POJO_MAPPING.put("EmailAddressGrantee", "Grantee");
@@ -188,17 +181,24 @@ public final class NamingConversionUtils {
         S3_POJO_MAPPING.put("ReplicationDestinationConfig", "Destination");
         S3_POJO_MAPPING.put("RoutingRuleCondition", "Condition");
         S3_POJO_MAPPING.put("S3ObjectSummary", "S3Object");
+        S3_POJO_MAPPING.put("ObjectListing", "ListObjectsResponse");
+        S3_POJO_MAPPING.put("AmazonS3Exception", "S3Exception");
 
         //Special Enum mapping
         S3_POJO_MAPPING.put("S3Event", "Event");
 
-        // TODO - maps 1 to many
-        // used as input to Request POJOs and returned as Response POJOs
+        // Maps 1 to many, e.g., used as input to Request POJOs and returned as Response POJOs
+        // Transform to one type here, convert others in S3TypesToV2 with ChangeMethodInvocationReturnType
         S3_POJO_MAPPING.put("ObjectMetadata", "HeadObjectResponse");
-        S3_POJO_MAPPING.put("ObjectListing", "ListObjectsResponse");
+        S3_POJO_MAPPING.put("AccessControlList", "AccessControlPolicy");
+        S3_POJO_MAPPING.put("BucketAccelerateConfiguration", "AccelerateConfiguration");
+        S3_POJO_MAPPING.put("BucketCrossOriginConfiguration", "CORSConfiguration");
+        S3_POJO_MAPPING.put("BucketNotificationConfiguration", "NotificationConfiguration");
+        S3_POJO_MAPPING.put("BucketReplicationConfiguration", "ReplicationConfiguration");
+        S3_POJO_MAPPING.put("BucketTaggingConfiguration", "Tagging");
+        S3_POJO_MAPPING.put("BucketWebsiteConfiguration", "WebsiteConfiguration");
         S3_POJO_MAPPING.put("BucketVersioningConfiguration", "VersioningConfiguration");
-        // v2 also has BucketCannedACL
-        S3_POJO_MAPPING.put("CannedAccessControlList", "ObjectCannedACL");
+        S3_POJO_MAPPING.put("BucketLoggingConfiguration", "BucketLoggingStatus");
     }
 
     static {
diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/S3TransformUtils.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/S3TransformUtils.java
index e5445065765d..eda4a98a5a87 100644
--- a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/S3TransformUtils.java
+++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/S3TransformUtils.java
@@ -150,6 +150,13 @@ public static void addMetadataFields(StringBuilder sb, String metadataName,
         }
     }
 
+    public static String changeBucketNameToBucket(String methodName) {
+        if (methodName.contains("BucketName")) {
+            return methodName.replace("BucketName", "Bucket");
+        }
+        return methodName;
+    }
+
     public static String getArgumentName(J.MethodInvocation method) {
         Expression val = method.getArguments().get(0);
         return ((J.Identifier) val).getSimpleName();
diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/SdkTypeUtils.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/SdkTypeUtils.java
index 722d0b526cd2..2aa13502b9ca 100644
--- a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/SdkTypeUtils.java
+++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/SdkTypeUtils.java
@@ -179,8 +179,10 @@ public final class SdkTypeUtils {
         CLASSES_TO_SKIP.add(V1_S3_MODEL_PKG + "GroupGrantee");
         CLASSES_TO_SKIP.add(V1_S3_MODEL_PKG + "Region");
 
-        // No S3-specific exceptions in v2
-        CLASSES_TO_SKIP.add(V1_S3_MODEL_PKG + "AmazonS3Exception");
+        // S3 Enum that maps to two separate enums in v2 : BucketCannedACL and ObjectCannedACL
+        CLASSES_TO_SKIP.add(V1_S3_MODEL_PKG + "CannedAccessControlList");
+
+        // No specific exceptions in v2
         CLASSES_TO_SKIP.add(V1_S3_MODEL_PKG + "IllegalBucketNameException");
         CLASSES_TO_SKIP.add(V1_S3_MODEL_PKG + "MultiObjectDeleteException");
         CLASSES_TO_SKIP.add(V1_S3_MODEL_PKG + "MultiObjectDeleteSlowdownException");
diff --git a/v2-migration/src/main/java/software/amazon/awssdk/v2migration/openrewrite/ChangeMethodInvocationReturnType.java b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/openrewrite/ChangeMethodInvocationReturnType.java
new file mode 100644
index 000000000000..40b3706d96f5
--- /dev/null
+++ b/v2-migration/src/main/java/software/amazon/awssdk/v2migration/openrewrite/ChangeMethodInvocationReturnType.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ *  http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.v2migration.openrewrite;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collections;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Option;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.MethodMatcher;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.TypeUtils;
+import org.openrewrite.marker.Markers;
+import software.amazon.awssdk.annotations.SdkInternalApi;
+
+/**
+ * This class contains source imported from https://github
+ * .com/openrewrite/rewrite/blob/main/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodInvocationReturnType.java,
+ * licensed under the Apache License 2.0, available at the time of the fork (4/11/2025) here:
+ * https://github.com/openrewrite/rewrite/blob/main/LICENSE
+ * <p>
+ * All original source licensed under the Apache License 2.0. All modifications are licensed under the Apache
+ * License 2.0 by Amazon Web Services.
+ */
+@SdkInternalApi
+public class ChangeMethodInvocationReturnType extends Recipe {
+
+    @Option(displayName = "Method pattern",
+        description = "A method pattern is used to find matching method invocations.",
+        example = "org.mockito.Matchers anyVararg()")
+    private final String methodPattern;
+
+    @Option(displayName = "New method invocation return type",
+        description = "The fully qualified new return type of method invocation.",
+        example = "long")
+    private final String newReturnType;
+
+    @JsonCreator
+    public ChangeMethodInvocationReturnType(@JsonProperty("methodPattern") String methodPattern,
+                                            @JsonProperty("newReturnType") String newReturnType) {
+        this.methodPattern = methodPattern;
+        this.newReturnType = newReturnType;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Change method invocation return type";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Changes the return type of a method invocation.";
+    }
+
+    @Override
+    public TreeVisitor<?, ExecutionContext> getVisitor() {
+        return new JavaIsoVisitor<ExecutionContext>() {
+            private final MethodMatcher methodMatcher = new MethodMatcher(methodPattern, false);
+
+            private boolean methodUpdated;
+
+            @Override
+            public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
+                J.MethodInvocation m = super.visitMethodInvocation(method, ctx);
+                JavaType.Method type = m.getMethodType();
+                if (methodMatcher.matches(method) && type != null && !newReturnType.equals(type.getReturnType().toString())) {
+                    type = type.withReturnType(JavaType.buildType(newReturnType));
+                    m = m.withMethodType(type);
+                    if (m.getName().getType() != null) {
+                        m = m.withName(m.getName().withType(type));
+                    }
+                    methodUpdated = true;
+                }
+                return m;
+            }
+
+            @Override
+            public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) {
+                methodUpdated = false;
+                JavaType.FullyQualified originalType = multiVariable.getTypeAsFullyQualified();
+                J.VariableDeclarations mv = super.visitVariableDeclarations(multiVariable, ctx);
+
+                if (methodUpdated) {
+                    JavaType newType = JavaType.buildType(newReturnType);
+                    JavaType.FullyQualified newFieldType = TypeUtils.asFullyQualified(newType);
+
+                    maybeAddImport(newFieldType);
+                    maybeRemoveImport(originalType);
+
+                    mv = mv.withTypeExpression(mv.getTypeExpression() == null ?
+                                               null :
+                                               new J.Identifier(mv.getTypeExpression().getId(),
+                                                                mv.getTypeExpression().getPrefix(),
+                                                                Markers.EMPTY,
+                                                                Collections.emptyList(),
+                                                                newReturnType.substring(newReturnType.lastIndexOf('.') + 1),
+                                                                newType,
+                                                                null
+                                               )
+                    );
+
+                    mv = mv.withVariables(ListUtils.map(mv.getVariables(), var -> {
+                        JavaType.FullyQualified varType = TypeUtils.asFullyQualified(var.getType());
+                        if (varType != null && !varType.equals(newType)) {
+                            return var.withType(newType).withName(var.getName().withType(newType));
+                        }
+                        return var;
+                    }));
+                }
+
+                return mv;
+            }
+        };
+    }
+}
\ No newline at end of file
diff --git a/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2-with-tm.yml b/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2-with-tm.yml
index 9b85b89558ca..99b4b6991845 100644
--- a/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2-with-tm.yml
+++ b/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2-with-tm.yml
@@ -24,6 +24,7 @@ recipeList:
   - software.amazon.awssdk.v2migration.AddTransferManagerDependency
   - software.amazon.awssdk.v2migration.UpgradeSdkDependencies
   - software.amazon.awssdk.v2migration.S3AddImportsAndComments
+  - software.amazon.awssdk.v2migration.S3TypesToV2
   - software.amazon.awssdk.v2migration.S3StreamingResponseToV2
   - software.amazon.awssdk.v2migration.S3StreamingRequestToV2
   - software.amazon.awssdk.v2migration.S3NonStreamingRequestToV2
diff --git a/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2.yml b/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2.yml
index 2652041fc569..f6b624998e48 100644
--- a/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2.yml
+++ b/v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2.yml
@@ -23,6 +23,7 @@ tags:
 recipeList:
   - software.amazon.awssdk.v2migration.UpgradeSdkDependencies
   - software.amazon.awssdk.v2migration.S3AddImportsAndComments
+  - software.amazon.awssdk.v2migration.S3TypesToV2
   - software.amazon.awssdk.v2migration.S3StreamingResponseToV2
   - software.amazon.awssdk.v2migration.S3StreamingRequestToV2
   - software.amazon.awssdk.v2migration.S3NonStreamingRequestToV2
diff --git a/v2-migration/src/main/resources/META-INF/rewrite/change-s3-types.yml b/v2-migration/src/main/resources/META-INF/rewrite/change-s3-types.yml
new file mode 100644
index 000000000000..0c8096334214
--- /dev/null
+++ b/v2-migration/src/main/resources/META-INF/rewrite/change-s3-types.yml
@@ -0,0 +1,98 @@
+#
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License").
+# You may not use this file except in compliance with the License.
+# A copy of the License is located at
+#
+#  http://aws.amazon.com/apache2.0
+#
+# or in the "license" file accompanying this file. This file is distributed
+# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language governing
+# permissions and limitations under the License.
+---
+type: specs.openrewrite.org/v1beta/recipe
+name: software.amazon.awssdk.v2migration.S3TypesToV2
+displayName: Change S3 types to v2.
+description: Change S3 types to v2.
+recipeList:
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getObject(com.amazonaws.services.s3.model.GetObjectRequest, java.io.File)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetObjectResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketAcl(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketAclResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getObjectAcl(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetObjectAclResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketAccelerateConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketAccelerateConfigurationResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketLifecycleConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketLifecycleConfigurationResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketCrossOriginConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketCorsResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketLoggingConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketLoggingResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketNotificationConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketNotificationConfigurationResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketPolicy(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketPolicyResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketReplicationConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketReplicationResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketTaggingConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketTaggingResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketVersioningConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketVersioningResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3 getBucketWebsiteConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketWebsiteResponse
+
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getObject(com.amazonaws.services.s3.model.GetObjectRequest, java.io.File)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetObjectResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketAcl(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketAclResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getObjectAcl(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetObjectAclResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketAccelerateConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketAccelerateConfigurationResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketLifecycleConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketLifecycleConfigurationResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketCrossOriginConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketCorsResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketLoggingConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketLoggingResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketNotificationConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketNotificationConfigurationResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketPolicy(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketPolicyResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketReplicationConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketReplicationResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketTaggingConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketTaggingResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketVersioningConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketVersioningResponse
+  - software.amazon.awssdk.v2migration.openrewrite.ChangeMethodInvocationReturnType:
+      methodPattern: com.amazonaws.services.s3.AmazonS3Client getBucketWebsiteConfiguration(..)
+      newReturnType: software.amazon.awssdk.services.s3.model.GetBucketWebsiteResponse
\ No newline at end of file


Reviews:
user: login: zoewangg
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T23:14:41Z
user: login: davidh44
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T23:26:17Z
user: login: zoewangg
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T22:56:01Z

Review comments:
diff_hunk: @@ -253,7 +253,7 @@ private void singleBucketArgMethods(S3Client s3, String bucket) {
         s3.getBucketPolicy(GetBucketPolicyRequest.builder().bucket(bucket)
             .build());
         s3.getBucketLocation(GetBucketLocationRequest.builder().bucket(bucket)
-            .build());
+            .build()).locationConstraint().toString();
path: test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3.java
user: login: zoewangg
body: Can we update it to return a variable?
created_at: 2025-04-11T23:12:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,128 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ *  http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.v2migration.openrewrite;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collections;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Option;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.MethodMatcher;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.TypeUtils;
+import org.openrewrite.marker.Markers;
+import software.amazon.awssdk.annotations.SdkInternalApi;
+
+/**
+ * This recipe is forked from
path: v2-migration/src/main/java/software/amazon/awssdk/v2migration/openrewrite/ChangeMethodInvocationReturnType.java
user: login: zoewangg
body: Can we follow https://github.com/aws/aws-sdk-java-v2/blob/master/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/nrs/HandlerSubscriber.java#L33 (provide time and link to the exact commit)
created_at: 2025-04-11T23:14:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -253,7 +253,7 @@ private void singleBucketArgMethods(S3Client s3, String bucket) {
         s3.getBucketPolicy(GetBucketPolicyRequest.builder().bucket(bucket)
             .build());
         s3.getBucketLocation(GetBucketLocationRequest.builder().bucket(bucket)
-            .build());
+            .build()).locationConstraint().toString();
path: test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3.java
user: login: davidh44
body: Its covered it in S3RequestConstructor

https://github.com/aws/aws-sdk-java-v2/blob/157dd1091c66c90aa3ec2ff06a55c4f3af89fb6a/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/S3RequestConstructor.java#L264
created_at: 2025-04-11T23:26:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,133 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ *  http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.v2migration.openrewrite;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collections;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Option;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.MethodMatcher;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.TypeUtils;
+import org.openrewrite.marker.Markers;
+import software.amazon.awssdk.annotations.SdkInternalApi;
+
+/**
+ * This class contains source imported from https://github
+ * .com/openrewrite/rewrite/blob/main/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodInvocationReturnType.java,
+ * licensed under the Apache License 2.0, available at the time of the fork (4/11/2025) here:
+ * https://github.com/openrewrite/rewrite/blob/main/LICENSE
+ * <p>
+ * All original source licensed under the Apache License 2.0 by playframework. All modifications are licensed under the Apache
path: v2-migration/src/main/java/software/amazon/awssdk/v2migration/openrewrite/ChangeMethodInvocationReturnType.java
user: login: zoewangg
body: `by playframework` needs to be updated.
created_at: 2025-04-14T22:55:45Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-04-15T21:27:38Z
body: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=aws_aws-sdk-java-v2&pullRequest=6024) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=aws_aws-sdk-java-v2&pullRequest=6024&metric=new_coverage&view=list) (required ≥ 80%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [C Reliability Rating on New Code](https://sonarcloud.io/dashboard?id=aws_aws-sdk-java-v2&pullRequest=6024) (required ≥ A)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aws_aws-sdk-java-v2&pullRequest=6024)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarQube for IDE](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


author_association: NONE