From 1f589d609188c8ffe09f773bb94e16d76041fbc5 Mon Sep 17 00:00:00 2001 From: Dongie Agnir Date: Tue, 7 May 2024 15:16:11 -0700 Subject: [PATCH 1/3] Transforming S3 PUT override This transforms the AmazonS3#putObject(String,String,File) override. --- .../recipe/S3StreamingRequestToV2.java | 173 ++++++++++++++++++ .../META-INF/rewrite/java-sdk-v1-to-v2.yml | 4 +- .../s3-putbject-constructor-to-fluent.yml | 27 +++ .../recipe/S3StreamingRequestToV2Test.java | 81 ++++++++ 4 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 migration-tool/src/main/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2.java create mode 100644 migration-tool/src/main/resources/META-INF/rewrite/s3-putbject-constructor-to-fluent.yml create mode 100644 migration-tool/src/test/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2Test.java diff --git a/migration-tool/src/main/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2.java b/migration-tool/src/main/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2.java new file mode 100644 index 000000000000..a243c29cef07 --- /dev/null +++ b/migration-tool/src/main/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2.java @@ -0,0 +1,173 @@ +/* + * 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.migration.internal.recipe; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.Tree; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JContainer; +import org.openrewrite.java.tree.JRightPadded; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Space; +import org.openrewrite.java.tree.TypeUtils; +import org.openrewrite.marker.Markers; +import software.amazon.awssdk.annotations.SdkInternalApi; +import software.amazon.awssdk.migration.internal.utils.IdentifierUtils; + +@SdkInternalApi +public class S3StreamingRequestToV2 extends Recipe { + private static final MethodMatcher PUT_OBJECT = + new MethodMatcher("com.amazonaws.services.s3.AmazonS3 " + + "putObject(java.lang.String, java.lang.String, java.io.File)", + true); + private static final JavaType.FullyQualified V1_PUT_OBJECT_REQUEST = + TypeUtils.asFullyQualified(JavaType.buildType("com.amazonaws.services.s3.model.PutObjectRequest")); + private static final JavaType.FullyQualified REQUEST_BODY = + TypeUtils.asFullyQualified(JavaType.buildType("software.amazon.awssdk.core.sync.RequestBody")); + + @Override + public String getDisplayName() { + return "S3StreamingRequestToV2"; + } + + @Override + public String getDescription() { + return "S3StreamingRequestToV2."; + } + + @Override + public TreeVisitor getVisitor() { + return new Visitor(); + } + + private static final class Visitor extends JavaIsoVisitor { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) { + if (PUT_OBJECT.matches(method, false)) { + method = transformPutFileOverload(method); + } + return super.visitMethodInvocation(method, executionContext); + } + + private J.MethodInvocation transformPutFileOverload(J.MethodInvocation method) { + JavaType.Method methodType = method.getMethodType(); + if (methodType == null) { + return method; + } + + List originalArgs = method.getArguments(); + + Expression bucketExpr = originalArgs.get(0); + Expression keyExpr = originalArgs.get(1); + Expression fileExpr = originalArgs.get(2); + + List newArgs = new ArrayList<>(); + Expression getObjectExpr = bucketAndKeyToPutObject(bucketExpr, keyExpr); + newArgs.add(getObjectExpr); + + Space fileArgPrefix = fileExpr.getPrefix(); + fileExpr = fileToRequestBody(fileExpr.withPrefix(Space.EMPTY)).withPrefix(fileArgPrefix); + newArgs.add(fileExpr); + + List paramNames = Arrays.asList("request", "file"); + List paramTypes = newArgs.stream() + .map(Expression::getType) + .collect(Collectors.toList()); + + + methodType = methodType.withParameterTypes(paramTypes) + .withParameterNames(paramNames); + + return method.withMethodType(methodType).withArguments(newArgs); + } + + private J.MethodInvocation fileToRequestBody(Expression fileExpr) { + maybeAddImport(REQUEST_BODY); + + J.Identifier requestBodyId = IdentifierUtils.makeId(REQUEST_BODY.getClassName(), REQUEST_BODY); + + JavaType.Method fromFileType = new JavaType.Method( + null, + 0L, + REQUEST_BODY, + "fromFile", + REQUEST_BODY, + Collections.singletonList("file"), + Collections.singletonList(JavaType.buildType("java.io.File")), + null, + null + ); + + J.Identifier fromFileId = IdentifierUtils.makeId("fromFile", fromFileType); + + return new J.MethodInvocation( + Tree.randomId(), + Space.EMPTY, + Markers.EMPTY, + JRightPadded.build(requestBodyId), + null, + fromFileId, + JContainer.build(Collections.singletonList(JRightPadded.build(fileExpr))), + fromFileType + ); + } + + private Expression bucketAndKeyToPutObject(Expression bucketExpr, Expression keyExpr) { + maybeAddImport(V1_PUT_OBJECT_REQUEST); + + J.Identifier putObjRequestId = IdentifierUtils.makeId(V1_PUT_OBJECT_REQUEST.getClassName(), V1_PUT_OBJECT_REQUEST); + + JavaType.Method ctorType = new JavaType.Method( + null, + 0L, + V1_PUT_OBJECT_REQUEST, + "", + V1_PUT_OBJECT_REQUEST, + Arrays.asList("bucket", "key"), + Arrays.asList(bucketExpr.getType(), keyExpr.getType()), + null, + null + ); + + return new J.NewClass( + Tree.randomId(), + Space.EMPTY, + Markers.EMPTY, + null, + Space.EMPTY, + putObjRequestId.withPrefix(Space.SINGLE_SPACE), + JContainer.build( + Arrays.asList( + JRightPadded.build(bucketExpr), + JRightPadded.build(keyExpr) + ) + ), + null, + ctorType + ); + } + } +} diff --git a/migration-tool/src/main/resources/META-INF/rewrite/java-sdk-v1-to-v2.yml b/migration-tool/src/main/resources/META-INF/rewrite/java-sdk-v1-to-v2.yml index 1788fb7334f0..bedeb9d56073 100644 --- a/migration-tool/src/main/resources/META-INF/rewrite/java-sdk-v1-to-v2.yml +++ b/migration-tool/src/main/resources/META-INF/rewrite/java-sdk-v1-to-v2.yml @@ -23,8 +23,10 @@ tags: recipeList: # TODO: update recipe naming to be consistent - software.amazon.awssdk.UpgradeSdkDependencies - - software.amazon.awssdk.S3GetObjectConstructorToFluent - software.amazon.awssdk.migration.internal.recipe.S3StreamingResponseToV2 + - software.amazon.awssdk.migration.internal.recipe.S3StreamingRequestToV2 + - software.amazon.awssdk.S3GetObjectConstructorToFluent + - software.amazon.awssdk.S3PutObjectConstructorToFluent - software.amazon.awssdk.migration.recipe.ChangeSdkType - software.amazon.awssdk.ChangeSdkCoreTypes # At this point, all classes should be changed to v2 equivalents diff --git a/migration-tool/src/main/resources/META-INF/rewrite/s3-putbject-constructor-to-fluent.yml b/migration-tool/src/main/resources/META-INF/rewrite/s3-putbject-constructor-to-fluent.yml new file mode 100644 index 000000000000..92044c8a44fa --- /dev/null +++ b/migration-tool/src/main/resources/META-INF/rewrite/s3-putbject-constructor-to-fluent.yml @@ -0,0 +1,27 @@ +# +# 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.S3PutObjectConstructorToFluent +displayName: Change auth related classes +recipeList: + - software.amazon.awssdk.migration.internal.recipe.ConstructorToFluent: + clzzFqcn: com.amazonaws.services.s3.model.PutObjectRequest + parameterTypes: + - java.lang.String + - java.lang.String + fluentNames: + - withBucket + - withKey \ No newline at end of file diff --git a/migration-tool/src/test/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2Test.java b/migration-tool/src/test/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2Test.java new file mode 100644 index 000000000000..4382e0ef0e4b --- /dev/null +++ b/migration-tool/src/test/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2Test.java @@ -0,0 +1,81 @@ +/* + * 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.migration.internal.recipe; + +import static org.openrewrite.java.Assertions.java; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnJre; +import org.junit.jupiter.api.condition.JRE; +import org.openrewrite.java.Java8Parser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +public class S3StreamingRequestToV2Test implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new S3StreamingRequestToV2()); + spec.parser(Java8Parser.builder().classpath( + "aws-java-sdk-s3", + "aws-java-sdk-core", + "s3", + "sdk-core", + "aws-core")); + } + + @Test + @EnabledOnJre({JRE.JAVA_8}) + public void foo() { + rewriteRun( + java( + "import com.amazonaws.services.s3.AmazonS3Client;\n" + + "\n" + + "import java.io.File;\n" + + "\n" + + "public class S3PutObjectExample {\n" + + " private static final String BUCKET = \"my-bucket\";\n" + + " private static final String KEY = \"key\";\n" + + "\n" + + " public static void main(String[] args) {\n" + + " AmazonS3Client s3 = null;\n" + + "\n" + + " File myFile = new File(\"test.txt\");\n" + + "\n" + + " s3.putObject(BUCKET, KEY, myFile);\n" + + " }\n" + + "}\n", + "import com.amazonaws.services.s3.AmazonS3Client;\n" + + "import com.amazonaws.services.s3.model.PutObjectRequest;\n" + + "import software.amazon.awssdk.core.sync.RequestBody;\n" + + "\n" + + "import java.io.File;\n" + + "\n" + + "public class S3PutObjectExample {\n" + + " private static final String BUCKET = \"my-bucket\";\n" + + " private static final String KEY = \"key\";\n" + + "\n" + + " public static void main(String[] args) {\n" + + " AmazonS3Client s3 = null;\n" + + "\n" + + " File myFile = new File(\"test.txt\");\n" + + "\n" + + " s3.putObject(new PutObjectRequest(BUCKET, KEY), RequestBody.fromFile(myFile));\n" + + " }\n" + + "}" + ) + ); + } +} From e9227349578ae8719470be4167aa29d37ae8f3d7 Mon Sep 17 00:00:00 2001 From: Dongie Agnir Date: Mon, 13 May 2024 09:42:16 -0700 Subject: [PATCH 2/3] Update test name --- .../migration/internal/recipe/S3StreamingRequestToV2Test.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration-tool/src/test/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2Test.java b/migration-tool/src/test/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2Test.java index 4382e0ef0e4b..52b8c510770b 100644 --- a/migration-tool/src/test/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2Test.java +++ b/migration-tool/src/test/java/software/amazon/awssdk/migration/internal/recipe/S3StreamingRequestToV2Test.java @@ -38,7 +38,7 @@ public void defaults(RecipeSpec spec) { @Test @EnabledOnJre({JRE.JAVA_8}) - public void foo() { + public void testS3PutObjectOverrideRewrite() { rewriteRun( java( "import com.amazonaws.services.s3.AmazonS3Client;\n" From bbe539698d7f18deb3d13b7cbbde5571bccaeba6 Mon Sep 17 00:00:00 2001 From: Dongie Agnir Date: Thu, 27 Jun 2024 12:03:17 -0700 Subject: [PATCH 3/3] Review comments --- .../META-INF/rewrite/s3-putbject-constructor-to-fluent.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration-tool/src/main/resources/META-INF/rewrite/s3-putbject-constructor-to-fluent.yml b/migration-tool/src/main/resources/META-INF/rewrite/s3-putbject-constructor-to-fluent.yml index 92044c8a44fa..b46ae1708f2c 100644 --- a/migration-tool/src/main/resources/META-INF/rewrite/s3-putbject-constructor-to-fluent.yml +++ b/migration-tool/src/main/resources/META-INF/rewrite/s3-putbject-constructor-to-fluent.yml @@ -15,7 +15,7 @@ --- type: specs.openrewrite.org/v1beta/recipe name: software.amazon.awssdk.S3PutObjectConstructorToFluent -displayName: Change auth related classes +displayName: Change PutObject constructors to fluent builder calls recipeList: - software.amazon.awssdk.migration.internal.recipe.ConstructorToFluent: clzzFqcn: com.amazonaws.services.s3.model.PutObjectRequest @@ -24,4 +24,4 @@ recipeList: - java.lang.String fluentNames: - withBucket - - withKey \ No newline at end of file + - withKey