Skip to content

Commit 745bf75

Browse files
authored
Migration tool updates (#5495)
* S3 PutObject String overload (#5429) * S3 PutObject String overload * Add comment * S3 CreateBucket DeleteBucket single arg overloads (#5438) * S3 CreateBucket DeleteBucket single arg overload * Address comments
1 parent a8d372b commit 745bf75

File tree

9 files changed

+410
-40
lines changed

9 files changed

+410
-40
lines changed

test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/after/src/main/java/foo/bar/Application.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package foo.bar;
1717

1818
import software.amazon.awssdk.services.s3.S3Client;
19+
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
20+
import software.amazon.awssdk.services.s3.model.DeleteBucketRequest;
1921
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
2022
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
2123
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
@@ -100,4 +102,21 @@ private static PutObjectResponse uploadFile(S3Client s3, String bucket, String k
100102

101103
return result;
102104
}
105+
106+
private static PutObjectResponse uploadString(S3Client s3, String bucket, String key, String content) {
107+
PutObjectResponse result = s3.putObject(PutObjectRequest.builder().bucket(bucket).key(key)
108+
.build(), RequestBody.fromString(content));
109+
110+
return result;
111+
}
112+
113+
private static void createBucket(S3Client s3, String bucket) {
114+
s3.createBucket(CreateBucketRequest.builder().bucket(bucket)
115+
.build());
116+
}
117+
118+
private static void deleteBucket(S3Client s3, String bucket) {
119+
s3.deleteBucket(DeleteBucketRequest.builder().bucket(bucket)
120+
.build());
121+
}
103122
}

test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/maven/before/src/main/java/foo/bar/Application.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
import com.amazonaws.services.s3.model.PutObjectResult;
2424
import com.amazonaws.services.s3.model.S3Object;
2525
import com.amazonaws.services.sqs.AmazonSQS;
26+
import com.amazonaws.services.sqs.model.QueueDoesNotExistException;
2627
import com.amazonaws.services.sqs.model.AmazonSQSException;
2728
import com.amazonaws.services.sqs.model.ListQueuesRequest;
2829
import com.amazonaws.services.sqs.model.ListQueuesResult;
2930

30-
import com.amazonaws.services.sqs.model.QueueDoesNotExistException;
3131
import java.io.IOException;
3232
import java.io.InputStream;
3333
import java.nio.file.Files;
@@ -94,4 +94,18 @@ private static PutObjectResult uploadFile(AmazonS3 s3, String bucket, String key
9494

9595
return result;
9696
}
97+
98+
private static PutObjectResult uploadString(AmazonS3 s3, String bucket, String key, String content) {
99+
PutObjectResult result = s3.putObject(bucket, key, content);
100+
101+
return result;
102+
}
103+
104+
private static void createBucket(AmazonS3 s3, String bucket) {
105+
s3.createBucket(bucket);
106+
}
107+
108+
private static void deleteBucket(AmazonS3 s3, String bucket) {
109+
s3.deleteBucket(bucket);
110+
}
97111
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.v2migration;
17+
18+
import java.util.ArrayList;
19+
import java.util.Collections;
20+
import java.util.List;
21+
import java.util.stream.Collectors;
22+
import org.openrewrite.ExecutionContext;
23+
import org.openrewrite.Recipe;
24+
import org.openrewrite.Tree;
25+
import org.openrewrite.TreeVisitor;
26+
import org.openrewrite.java.JavaIsoVisitor;
27+
import org.openrewrite.java.MethodMatcher;
28+
import org.openrewrite.java.tree.Expression;
29+
import org.openrewrite.java.tree.J;
30+
import org.openrewrite.java.tree.JContainer;
31+
import org.openrewrite.java.tree.JRightPadded;
32+
import org.openrewrite.java.tree.JavaType;
33+
import org.openrewrite.java.tree.Space;
34+
import org.openrewrite.java.tree.TypeUtils;
35+
import org.openrewrite.marker.Markers;
36+
import software.amazon.awssdk.annotations.SdkInternalApi;
37+
import software.amazon.awssdk.v2migration.internal.utils.IdentifierUtils;
38+
39+
@SdkInternalApi
40+
public class S3NonStreamingRequestToV2 extends Recipe {
41+
private static final MethodMatcher CREATE_BUCKET =
42+
new MethodMatcher("com.amazonaws.services.s3.AmazonS3 createBucket(java.lang.String)", true);
43+
private static final MethodMatcher DELETE_BUCKET =
44+
new MethodMatcher("com.amazonaws.services.s3.AmazonS3 deleteBucket(java.lang.String)", true);
45+
private static final JavaType.FullyQualified V1_CREATE_BUCKET_REQUEST =
46+
TypeUtils.asFullyQualified(JavaType.buildType("com.amazonaws.services.s3.model.CreateBucketRequest"));
47+
private static final JavaType.FullyQualified V1_DELETE_BUCKET_REQUEST =
48+
TypeUtils.asFullyQualified(JavaType.buildType("com.amazonaws.services.s3.model.DeleteBucketRequest"));
49+
50+
@Override
51+
public String getDisplayName() {
52+
return "V1 S3 non-streaming requests to V2";
53+
}
54+
55+
@Override
56+
public String getDescription() {
57+
return "Transform usage of V1 S3 non-streaming requests such as CreateBucket and DeleteBucket to V2.";
58+
}
59+
60+
@Override
61+
public TreeVisitor<?, ExecutionContext> getVisitor() {
62+
return new Visitor();
63+
}
64+
65+
private static final class Visitor extends JavaIsoVisitor<ExecutionContext> {
66+
@Override
67+
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
68+
if (CREATE_BUCKET.matches(method, false)) {
69+
method = transformBucketNameArgOverload(method, V1_CREATE_BUCKET_REQUEST);
70+
} else if (DELETE_BUCKET.matches(method, false)) {
71+
method = transformBucketNameArgOverload(method, V1_DELETE_BUCKET_REQUEST);
72+
}
73+
return super.visitMethodInvocation(method, executionContext);
74+
}
75+
76+
private J.MethodInvocation transformBucketNameArgOverload(J.MethodInvocation method, JavaType.FullyQualified fqcn) {
77+
JavaType.Method methodType = method.getMethodType();
78+
if (methodType == null) {
79+
return method;
80+
}
81+
82+
Expression bucketExpr = method.getArguments().get(0);
83+
List<Expression> newArgs = new ArrayList<>();
84+
Expression getObjectExpr = bucketToPojo(bucketExpr, fqcn);
85+
newArgs.add(getObjectExpr);
86+
87+
List<String> paramNames = Collections.singletonList("request");
88+
List<JavaType> paramTypes = newArgs.stream()
89+
.map(Expression::getType)
90+
.collect(Collectors.toList());
91+
92+
methodType = methodType.withParameterTypes(paramTypes)
93+
.withParameterNames(paramNames);
94+
95+
return method.withMethodType(methodType).withArguments(newArgs);
96+
}
97+
98+
private Expression bucketToPojo(Expression bucketExpr, JavaType.FullyQualified fqcn) {
99+
maybeAddImport(fqcn);
100+
101+
J.Identifier putObjRequestId = IdentifierUtils.makeId(fqcn.getClassName(), fqcn);
102+
103+
JavaType.Method ctorType = new JavaType.Method(
104+
null,
105+
0L,
106+
fqcn,
107+
"<init>",
108+
fqcn,
109+
Collections.singletonList("bucket"),
110+
Collections.singletonList(bucketExpr.getType()),
111+
null,
112+
null
113+
);
114+
115+
return new J.NewClass(
116+
Tree.randomId(),
117+
Space.EMPTY,
118+
Markers.EMPTY,
119+
null,
120+
Space.EMPTY,
121+
putObjRequestId.withPrefix(Space.SINGLE_SPACE),
122+
JContainer.build(Collections.singletonList(JRightPadded.build(bucketExpr))),
123+
null,
124+
ctorType
125+
);
126+
}
127+
}
128+
}

v2-migration/src/main/java/software/amazon/awssdk/v2migration/S3StreamingRequestToV2.java

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,26 @@
3939

4040
@SdkInternalApi
4141
public class S3StreamingRequestToV2 extends Recipe {
42-
private static final MethodMatcher PUT_OBJECT =
42+
private static final MethodMatcher PUT_OBJECT_FILE =
4343
new MethodMatcher("com.amazonaws.services.s3.AmazonS3 "
44-
+ "putObject(java.lang.String, java.lang.String, java.io.File)",
45-
true);
44+
+ "putObject(java.lang.String, java.lang.String, java.io.File)", true);
45+
private static final MethodMatcher PUT_OBJECT_STRING =
46+
new MethodMatcher("com.amazonaws.services.s3.AmazonS3 "
47+
+ "putObject(java.lang.String, java.lang.String, java.lang.String)", true);
48+
4649
private static final JavaType.FullyQualified V1_PUT_OBJECT_REQUEST =
4750
TypeUtils.asFullyQualified(JavaType.buildType("com.amazonaws.services.s3.model.PutObjectRequest"));
4851
private static final JavaType.FullyQualified REQUEST_BODY =
4952
TypeUtils.asFullyQualified(JavaType.buildType("software.amazon.awssdk.core.sync.RequestBody"));
5053

5154
@Override
5255
public String getDisplayName() {
53-
return "S3StreamingRequestToV2";
56+
return "V1 S3 streaming requests to V2";
5457
}
5558

5659
@Override
5760
public String getDescription() {
58-
return "S3StreamingRequestToV2.";
61+
return "Transform usage of V1 S3 streaming requests such as PutObject to V2.";
5962
}
6063

6164
@Override
@@ -66,12 +69,78 @@ public TreeVisitor<?, ExecutionContext> getVisitor() {
6669
private static final class Visitor extends JavaIsoVisitor<ExecutionContext> {
6770
@Override
6871
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
69-
if (PUT_OBJECT.matches(method, false)) {
72+
if (PUT_OBJECT_FILE.matches(method, false)) {
7073
method = transformPutFileOverload(method);
74+
} else if (PUT_OBJECT_STRING.matches(method, false)) {
75+
method = transformPutStringOverload(method);
7176
}
7277
return super.visitMethodInvocation(method, executionContext);
7378
}
7479

80+
private J.MethodInvocation transformPutStringOverload(J.MethodInvocation method) {
81+
JavaType.Method methodType = method.getMethodType();
82+
if (methodType == null) {
83+
return method;
84+
}
85+
86+
List<Expression> originalArgs = method.getArguments();
87+
88+
Expression bucketExpr = originalArgs.get(0);
89+
Expression keyExpr = originalArgs.get(1);
90+
Expression stringExpr = originalArgs.get(2);
91+
92+
List<Expression> newArgs = new ArrayList<>();
93+
Expression getObjectExpr = bucketAndKeyToPutObject(bucketExpr, keyExpr);
94+
newArgs.add(getObjectExpr);
95+
96+
// This is to maintain the formatting/spacing of original code, getPrefix() retrieves the leading whitespace
97+
Space stringArgPrefix = stringExpr.getPrefix();
98+
stringExpr = stringToRequestBody(stringExpr.withPrefix(Space.EMPTY)).withPrefix(stringArgPrefix);
99+
newArgs.add(stringExpr);
100+
101+
List<String> paramNames = Arrays.asList("request", "stringContent");
102+
List<JavaType> paramTypes = newArgs.stream()
103+
.map(Expression::getType)
104+
.collect(Collectors.toList());
105+
106+
107+
methodType = methodType.withParameterTypes(paramTypes)
108+
.withParameterNames(paramNames);
109+
110+
return method.withMethodType(methodType).withArguments(newArgs);
111+
}
112+
113+
private J.MethodInvocation stringToRequestBody(Expression fileExpr) {
114+
maybeAddImport(REQUEST_BODY);
115+
116+
J.Identifier requestBodyId = IdentifierUtils.makeId(REQUEST_BODY.getClassName(), REQUEST_BODY);
117+
118+
JavaType.Method fromStringType = new JavaType.Method(
119+
null,
120+
0L,
121+
REQUEST_BODY,
122+
"fromString",
123+
REQUEST_BODY,
124+
Collections.singletonList("stringContent"),
125+
Collections.singletonList(JavaType.buildType("java.lang.String")),
126+
null,
127+
null
128+
);
129+
130+
J.Identifier fromFileId = IdentifierUtils.makeId("fromString", fromStringType);
131+
132+
return new J.MethodInvocation(
133+
Tree.randomId(),
134+
Space.EMPTY,
135+
Markers.EMPTY,
136+
JRightPadded.build(requestBodyId),
137+
null,
138+
fromFileId,
139+
JContainer.build(Collections.singletonList(JRightPadded.build(fileExpr))),
140+
fromStringType
141+
);
142+
}
143+
75144
private J.MethodInvocation transformPutFileOverload(J.MethodInvocation method) {
76145
JavaType.Method methodType = method.getMethodType();
77146
if (methodType == null) {

v2-migration/src/main/resources/META-INF/rewrite/aws-sdk-java-v1-to-v2.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ recipeList:
2424
- software.amazon.awssdk.v2migration.UpgradeSdkDependencies
2525
- software.amazon.awssdk.v2migration.S3StreamingResponseToV2
2626
- software.amazon.awssdk.v2migration.S3StreamingRequestToV2
27-
- software.amazon.awssdk.v2migration.S3GetObjectConstructorToFluent
28-
- software.amazon.awssdk.v2migration.S3PutObjectConstructorToFluent
27+
- software.amazon.awssdk.v2migration.S3NonStreamingRequestToV2
28+
- software.amazon.awssdk.v2migration.S3MethodsConstructorToFluent
2929
- software.amazon.awssdk.v2migration.EnumGettersToV2
3030
- software.amazon.awssdk.v2migration.ChangeSdkType
3131
- software.amazon.awssdk.v2migration.ChangeSdkCoreTypes

v2-migration/src/main/resources/META-INF/rewrite/s3-getobject-constructor-to-fluent.yml renamed to v2-migration/src/main/resources/META-INF/rewrite/s3-methods-constructor-to-fluent.yml

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
#
1515
---
1616
type: specs.openrewrite.org/v1beta/recipe
17-
name: software.amazon.awssdk.v2migration.S3GetObjectConstructorToFluent
18-
displayName: Change GetObject constructors to fluent builder calls
17+
name: software.amazon.awssdk.v2migration.S3MethodsConstructorToFluent
18+
displayName: Change S3 method constructors to fluent builder calls
1919
recipeList:
2020
- software.amazon.awssdk.v2migration.ConstructorToFluent:
2121
clzzFqcn: com.amazonaws.services.s3.model.GetObjectRequest
@@ -24,4 +24,24 @@ recipeList:
2424
- java.lang.String
2525
fluentNames:
2626
- withBucket
27-
- withKey
27+
- withKey
28+
- software.amazon.awssdk.v2migration.ConstructorToFluent:
29+
clzzFqcn: com.amazonaws.services.s3.model.PutObjectRequest
30+
parameterTypes:
31+
- java.lang.String
32+
- java.lang.String
33+
fluentNames:
34+
- withBucket
35+
- withKey
36+
- software.amazon.awssdk.v2migration.ConstructorToFluent:
37+
clzzFqcn: com.amazonaws.services.s3.model.CreateBucketRequest
38+
parameterTypes:
39+
- java.lang.String
40+
fluentNames:
41+
- withBucket
42+
- software.amazon.awssdk.v2migration.ConstructorToFluent:
43+
clzzFqcn: com.amazonaws.services.s3.model.DeleteBucketRequest
44+
parameterTypes:
45+
- java.lang.String
46+
fluentNames:
47+
- withBucket

v2-migration/src/main/resources/META-INF/rewrite/s3-putobject-constructor-to-fluent.yml

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)