Skip to content

Commit 278563e

Browse files
authored
Migration Tool : S3 generatePresignedUrl (#5994)
* Migration Tool : S3 generatePresignedUrl * Add tests for GeneratePresignedUrlRequest * Update formatting and comments * Update comments
1 parent 0b5dc7d commit 278563e

File tree

6 files changed

+231
-34
lines changed

6 files changed

+231
-34
lines changed

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@
1515

1616
package foo.bar;
1717

18+
import com.amazonaws.HttpMethod;
19+
import java.io.ByteArrayInputStream;
20+
import java.io.InputStream;
21+
import java.net.URL;
22+
import java.util.Date;
1823
import software.amazon.awssdk.core.async.AsyncRequestBody;
24+
import software.amazon.awssdk.services.s3.S3Client;
25+
import software.amazon.awssdk.services.s3.model.GeneratePresignedUrlRequest;
1926
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
2027
import software.amazon.awssdk.transfer.s3.S3TransferManager;
2128
import software.amazon.awssdk.transfer.s3.model.UploadRequest;
2229

23-
import java.io.ByteArrayInputStream;
24-
import java.io.InputStream;
25-
2630
public class S3Transforms {
2731

2832
void upload(S3TransferManager tm, String bucket, String key) {
@@ -31,4 +35,19 @@ void upload(S3TransferManager tm, String bucket, String key) {
3135
.build();
3236
/*AWS SDK for Java v2 migration: When using InputStream to upload with TransferManager, you must specify Content-Length and ExecutorService.*/tm.upload(UploadRequest.builder().putObjectRequest(requestWithInputStream).requestBody(AsyncRequestBody.fromInputStream(inputStream, -1L, newExecutorServiceVariableToDefine)).build());
3337
}
38+
39+
private void generatePresignedUrl(S3Client s3, String bucket, String key, Date expiration) {
40+
URL urlHead = /*AWS SDK for Java v2 migration: S3 generatePresignedUrl() with HEAD HTTP method is not supported in v2. Only GET, PUT, and DELETE are supported - https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/presigner/S3Presigner.html*/s3.generatePresignedUrl(bucket, key, expiration, HttpMethod.HEAD);
41+
42+
URL urlPatch = /*AWS SDK for Java v2 migration: S3 generatePresignedUrl() with PATCH HTTP method is not supported in v2. Only GET, PUT, and DELETE are supported - https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/presigner/S3Presigner.html*/s3.generatePresignedUrl(bucket, key, expiration, HttpMethod.PATCH);
43+
44+
URL urlPost = /*AWS SDK for Java v2 migration: S3 generatePresignedUrl() with POST HTTP method is not supported in v2. Only GET, PUT, and DELETE are supported - https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/presigner/S3Presigner.html*/s3.generatePresignedUrl(bucket, key, expiration, HttpMethod.POST);
45+
46+
47+
HttpMethod httpMethod = HttpMethod.PUT;
48+
URL urlWithHttpMethodVariable = /*AWS SDK for Java v2 migration: Transform for S3 generatePresignedUrl() with an assigned variable for HttpMethod is not supported. Please manually migrate your code - https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/presigner/S3Presigner.html*/s3.generatePresignedUrl(bucket, key, expiration, httpMethod);
49+
50+
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, key);
51+
/*AWS SDK for Java v2 migration: Transforms are not supported for GeneratePresignedUrlRequest, please manually migrate your code - https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/presigner/S3Presigner.html*/s3.generatePresignedUrl(request);
52+
}
3453
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,15 @@
1515

1616
package foo.bar;
1717

18+
import com.amazonaws.HttpMethod;
19+
import com.amazonaws.services.s3.AmazonS3;
20+
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
1821
import com.amazonaws.services.s3.model.PutObjectRequest;
1922
import com.amazonaws.services.s3.transfer.TransferManager;
2023
import java.io.ByteArrayInputStream;
2124
import java.io.InputStream;
25+
import java.net.URL;
26+
import java.util.Date;
2227

2328
public class S3Transforms {
2429

@@ -28,4 +33,19 @@ void upload(TransferManager tm, String bucket, String key) {
2833
requestWithInputStream.setInputStream(inputStream);
2934
tm.upload(requestWithInputStream);
3035
}
36+
37+
private void generatePresignedUrl(AmazonS3 s3, String bucket, String key, Date expiration) {
38+
URL urlHead = s3.generatePresignedUrl(bucket, key, expiration, HttpMethod.HEAD);
39+
40+
URL urlPatch = s3.generatePresignedUrl(bucket, key, expiration, HttpMethod.PATCH);
41+
42+
URL urlPost = s3.generatePresignedUrl(bucket, key, expiration, HttpMethod.POST);
43+
44+
45+
HttpMethod httpMethod = HttpMethod.PUT;
46+
URL urlWithHttpMethodVariable = s3.generatePresignedUrl(bucket, key, expiration, httpMethod);
47+
48+
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, key);
49+
s3.generatePresignedUrl(request);
50+
}
3151
}

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

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

1818
import java.net.URI;
19+
import java.net.URL;
20+
import java.time.Duration;
21+
import java.time.Instant;
1922
import java.util.ArrayList;
23+
import java.util.Date;
2024
import java.util.List;
2125
import software.amazon.awssdk.regions.Region;
2226
import software.amazon.awssdk.services.s3.S3Client;
@@ -110,6 +114,7 @@
110114
import software.amazon.awssdk.services.s3.model.UploadPartCopyRequest;
111115
import software.amazon.awssdk.services.s3.model.UploadPartCopyResponse;
112116
import software.amazon.awssdk.services.s3.model.WebsiteConfiguration;
117+
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
113118

114119
public class S3 {
115120

@@ -402,4 +407,26 @@ private void s3Uri(URI uri, String uriAsString) {
402407

403408
S3Uri s3UriFromStringWithUrlEncodeFalse = S3Utilities.builder().build().parseUri(URI.create(uriAsString));
404409
}
410+
411+
private void generatePresignedUrl(S3Client s3, String bucket, String key, Date expiration) {
412+
URL urlGet1 = /*AWS SDK for Java v2 migration: If generating multiple pre-signed URLs, it is recommended to create a single instance of S3Presigner, since creating a presigner can be expensive. If applicable, please manually refactor the transformed code.*/S3Presigner.builder().s3Client(s3).build()
413+
.presignGetObject(p -> p.getObjectRequest(r -> r.bucket(bucket).key(key))
414+
.signatureDuration(Duration.between(Instant.now(), expiration.toInstant())))
415+
.url();
416+
417+
URL urlPut = /*AWS SDK for Java v2 migration: If generating multiple pre-signed URLs, it is recommended to create a single instance of S3Presigner, since creating a presigner can be expensive. If applicable, please manually refactor the transformed code.*/S3Presigner.builder().s3Client(s3).build()
418+
.presignPutObject(p -> p.putObjectRequest(r -> r.bucket(bucket).key(key))
419+
.signatureDuration(Duration.between(Instant.now(), expiration.toInstant())))
420+
.url();
421+
422+
URL urlGet2 = /*AWS SDK for Java v2 migration: If generating multiple pre-signed URLs, it is recommended to create a single instance of S3Presigner, since creating a presigner can be expensive. If applicable, please manually refactor the transformed code.*/S3Presigner.builder().s3Client(s3).build()
423+
.presignGetObject(p -> p.getObjectRequest(r -> r.bucket(bucket).key(key))
424+
.signatureDuration(Duration.between(Instant.now(), expiration.toInstant())))
425+
.url();
426+
427+
URL urlDelete = /*AWS SDK for Java v2 migration: If generating multiple pre-signed URLs, it is recommended to create a single instance of S3Presigner, since creating a presigner can be expensive. If applicable, please manually refactor the transformed code.*/S3Presigner.builder().s3Client(s3).build()
428+
.presignDeleteObject(p -> p.deleteObjectRequest(r -> r.bucket(bucket).key(key))
429+
.signatureDuration(Duration.between(Instant.now(), expiration.toInstant())))
430+
.url();
431+
}
405432
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package foo.bar;
1717

18+
import com.amazonaws.HttpMethod;
1819
import com.amazonaws.services.s3.AmazonS3;
1920
import com.amazonaws.services.s3.AmazonS3URI;
2021
import com.amazonaws.services.s3.model.AbortMultipartUploadRequest;
@@ -59,7 +60,9 @@
5960
import com.amazonaws.services.s3.model.metrics.MetricsConfiguration;
6061
import com.amazonaws.services.s3.model.ownership.OwnershipControls;
6162
import java.net.URI;
63+
import java.net.URL;
6264
import java.util.ArrayList;
65+
import java.util.Date;
6366
import java.util.List;
6467

6568
public class S3 {
@@ -259,4 +262,14 @@ private void s3Uri(URI uri, String uriAsString) {
259262

260263
AmazonS3URI s3UriFromStringWithUrlEncodeFalse = new AmazonS3URI(uriAsString, false);
261264
}
265+
266+
private void generatePresignedUrl(AmazonS3 s3, String bucket, String key, Date expiration) {
267+
URL urlGet1 = s3.generatePresignedUrl(bucket, key, expiration);
268+
269+
URL urlPut = s3.generatePresignedUrl(bucket, key, expiration, HttpMethod.PUT);
270+
271+
URL urlGet2 = s3.generatePresignedUrl(bucket, key, expiration, HttpMethod.GET);
272+
273+
URL urlDelete = s3.generatePresignedUrl(bucket, key, expiration, HttpMethod.DELETE);
274+
}
262275
}

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

Lines changed: 101 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,28 @@
1616
package software.amazon.awssdk.v2migration;
1717

1818
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.V2_S3_MODEL_PKG;
19+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.V2_S3_PKG;
20+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.assignedVariableHttpMethodNotSupportedComment;
21+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.httpMethodNotSupportedComment;
22+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isCompleteMpuRequestMultipartUploadSetter;
23+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isGeneratePresignedUrl;
24+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isUnsupportedHttpMethod;
25+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.presignerSingleInstanceSuggestion;
26+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.requestPojoTransformNotSupportedComment;
1927
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.v2S3MethodMatcher;
20-
import static software.amazon.awssdk.v2migration.internal.utils.SdkTypeUtils.fullyQualified;
2128

29+
import java.util.List;
30+
import java.util.Locale;
2231
import org.openrewrite.ExecutionContext;
2332
import org.openrewrite.Recipe;
2433
import org.openrewrite.TreeVisitor;
2534
import org.openrewrite.java.AddImport;
2635
import org.openrewrite.java.JavaIsoVisitor;
2736
import org.openrewrite.java.JavaTemplate;
2837
import org.openrewrite.java.MethodMatcher;
38+
import org.openrewrite.java.RemoveImport;
39+
import org.openrewrite.java.tree.Expression;
2940
import org.openrewrite.java.tree.J;
30-
import org.openrewrite.java.tree.JavaType;
31-
import org.openrewrite.java.tree.TypeUtils;
3241
import software.amazon.awssdk.annotations.SdkInternalApi;
3342

3443
/**
@@ -74,58 +83,100 @@ private static final class Visitor extends JavaIsoVisitor<ExecutionContext> {
7483
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
7584

7685
if (isCompleteMpuRequestMultipartUploadSetter(method)) {
77-
method = transformCompleteMpuRequestCompletedPartsArg(method);
78-
return super.visitMethodInvocation(method, executionContext);
86+
return transformCompleteMpuRequestCompletedPartsArg(method);
87+
}
88+
if (isGeneratePresignedUrl(method)) {
89+
return maybeAutoFormat(method, transformGeneratePresignedUrl(method), executionContext);
7990
}
80-
8191
if (DISABLE_REQUESTER_PAYS.matches(method, false)) {
82-
method = transformSetRequesterPays(method, false);
83-
return super.visitMethodInvocation(method, executionContext);
92+
return transformSetRequesterPays(method, false);
8493
}
8594
if (ENABLE_REQUESTER_PAYS.matches(method, false)) {
86-
method = transformSetRequesterPays(method, true);
87-
return super.visitMethodInvocation(method, executionContext);
95+
return transformSetRequesterPays(method, true);
8896
}
8997
if (IS_REQUESTER_PAYS_ENABLED.matches(method, false)) {
90-
method = transformIsRequesterPays(method);
91-
return super.visitMethodInvocation(method, executionContext);
98+
return transformIsRequesterPays(method);
9299
}
93100
if (GET_OBJECT_AS_STRING.matches(method, false)) {
94-
method = transformGetObjectAsString(method);
95-
return super.visitMethodInvocation(method, executionContext);
101+
return transformGetObjectAsString(method);
96102
}
97103
if (GET_URL.matches(method, false)) {
98-
method = transformGetUrl(method);
99-
return super.visitMethodInvocation(method, executionContext);
104+
return transformGetUrl(method);
100105
}
101106
if (LIST_BUCKETS.matches(method, false)) {
102-
method = transformListBuckets(method);
103-
return super.visitMethodInvocation(method, executionContext);
107+
return transformListBuckets(method);
104108
}
105109
if (RESTORE_OBJECT.matches(method, false)) {
106-
method = transformRestoreObject(method);
107-
return super.visitMethodInvocation(method, executionContext);
110+
return transformRestoreObject(method);
108111
}
109112
if (SET_OBJECT_REDIRECT_LOCATION.matches(method, false)) {
110-
method = transformSetObjectRedirectLocation(method);
111-
return super.visitMethodInvocation(method, executionContext);
113+
return transformSetObjectRedirectLocation(method);
112114
}
113115
if (CHANGE_OBJECT_STORAGE_CLASS.matches(method, false)) {
114-
method = transformChangeObjectStorageClass(method);
115-
return super.visitMethodInvocation(method, executionContext);
116+
return transformChangeObjectStorageClass(method);
116117
}
117118
if (CREATE_BUCKET.matches(method, false)) {
118-
method = transformCreateBucket(method);
119-
return super.visitMethodInvocation(method, executionContext);
119+
return transformCreateBucket(method);
120120
}
121121
return super.visitMethodInvocation(method, executionContext);
122122
}
123123

124-
private boolean isCompleteMpuRequestMultipartUploadSetter(J.MethodInvocation method) {
125-
JavaType.FullyQualified completeMpuRequest =
126-
fullyQualified("software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest.Builder");
127-
return "multipartUpload".equals(method.getSimpleName()) &&
128-
TypeUtils.isAssignableTo(completeMpuRequest, method.getSelect().getType());
124+
private J.MethodInvocation transformGeneratePresignedUrl(J.MethodInvocation method) {
125+
List<Expression> args = method.getArguments();
126+
if (args.size() == 1) {
127+
return method.withComments(requestPojoTransformNotSupportedComment());
128+
}
129+
130+
String httpMethod = determineHttpMethod(args);
131+
132+
if (isUnsupportedHttpMethod(httpMethod)) {
133+
return method.withComments(httpMethodNotSupportedComment(httpMethod));
134+
}
135+
if (httpMethod == null) {
136+
return method.withComments(assignedVariableHttpMethodNotSupportedComment());
137+
}
138+
139+
String v2Method = String.format("S3Presigner.builder().s3Client(#{any()}).build()%n"
140+
+ ".presign%sObject(p -> p.%sObjectRequest(r -> r.bucket(#{any()}).key(#{any()}))%n"
141+
+ ".signatureDuration(Duration.between(Instant.now(), #{any()}.toInstant())))%n"
142+
+ ".url()",
143+
httpMethod, httpMethod.toLowerCase(Locale.ROOT));
144+
145+
removeV1HttpMethodImport();
146+
addInstantImport();
147+
addDurationImport();
148+
addS3PresignerImport();
149+
150+
return JavaTemplate.builder(v2Method).build()
151+
.apply(getCursor(), method.getCoordinates().replace(), method.getSelect(),
152+
args.get(0), args.get(1), args.get(2))
153+
.withComments(presignerSingleInstanceSuggestion());
154+
}
155+
156+
private String determineHttpMethod(List<Expression> args) {
157+
if (args.size() == 3) {
158+
return "Get";
159+
}
160+
Expression argVal = args.get(3);
161+
String httpMethod = argVal.printTrimmed(getCursor());
162+
163+
switch (httpMethod) {
164+
case "HttpMethod.GET":
165+
return "Get";
166+
case "HttpMethod.PUT":
167+
return "Put";
168+
case "HttpMethod.DELETE":
169+
return "Delete";
170+
case "HttpMethod.HEAD":
171+
return "Head";
172+
case "HttpMethod.POST":
173+
return "Post";
174+
case "HttpMethod.PATCH":
175+
return "Patch";
176+
default:
177+
// enum value assigned to variable
178+
return null;
179+
}
129180
}
130181

131182
private J.MethodInvocation transformCompleteMpuRequestCompletedPartsArg(J.MethodInvocation method) {
@@ -251,6 +302,25 @@ private J.MethodInvocation transformSetRequesterPays(J.MethodInvocation method,
251302
return method;
252303
}
253304

305+
private void removeV1HttpMethodImport() {
306+
doAfterVisit(new RemoveImport<>("com.amazonaws.HttpMethod", true));
307+
}
308+
309+
private void addInstantImport() {
310+
String fqcn = "java.time.Instant";
311+
doAfterVisit(new AddImport<>(fqcn, null, false));
312+
}
313+
314+
private void addDurationImport() {
315+
String fqcn = "java.time.Duration";
316+
doAfterVisit(new AddImport<>(fqcn, null, false));
317+
}
318+
319+
private void addS3PresignerImport() {
320+
String fqcn = V2_S3_PKG + "presigner.S3Presigner";
321+
doAfterVisit(new AddImport<>(fqcn, null, false));
322+
}
323+
254324
private void addImport(String pojoName) {
255325
String fqcn = V2_S3_MODEL_PKG + pojoName;
256326
doAfterVisit(new AddImport<>(fqcn, null, false));

0 commit comments

Comments
 (0)