Skip to content

Commit 4089dca

Browse files
authored
Migration Tool AmazonS3URI transform (#5990)
1 parent 36eb1c8 commit 4089dca

File tree

7 files changed

+269
-0
lines changed

7 files changed

+269
-0
lines changed

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

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

1616
package foo.bar;
1717

18+
import java.net.URI;
1819
import java.util.ArrayList;
1920
import java.util.List;
21+
import software.amazon.awssdk.regions.Region;
2022
import software.amazon.awssdk.services.s3.S3Client;
23+
import software.amazon.awssdk.services.s3.S3Uri;
24+
import software.amazon.awssdk.services.s3.S3Utilities;
2125
import software.amazon.awssdk.services.s3.model.AbortMultipartUploadRequest;
2226
import software.amazon.awssdk.services.s3.model.AccelerateConfiguration;
2327
import software.amazon.awssdk.services.s3.model.AnalyticsConfiguration;
@@ -384,4 +388,18 @@ private void setBucketNameTest(S3Client s3, String bucket) {
384388
GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(bucket).key("key").bucket(bucket)
385389
.build();
386390
}
391+
392+
private void s3Uri(URI uri, String uriAsString) {
393+
S3Uri s3Uri = S3Utilities.builder().build().parseUri(uri);
394+
395+
String versionId = s3Uri.firstMatchingRawQueryParameter("versionId").orElse(null);
396+
String bucket = s3Uri.bucket().orElse(null);
397+
String key = s3Uri.key().orElse(null);
398+
String region = s3Uri.region().map(Region::id).orElse(null);
399+
boolean isPathStyle = s3Uri.isPathStyle();
400+
401+
S3Uri s3UriFromString = /*AWS SDK for Java v2 migration: v2 S3Uri does not URL-encode a String URI. If you relied on this functionality in v1 you must update your code to manually encode the String.*/S3Utilities.builder().build().parseUri(URI.create(uriAsString));
402+
403+
S3Uri s3UriFromStringWithUrlEncodeFalse = S3Utilities.builder().build().parseUri(URI.create(uriAsString));
404+
}
387405
}

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

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

1818
import com.amazonaws.services.s3.AmazonS3;
19+
import com.amazonaws.services.s3.AmazonS3URI;
1920
import com.amazonaws.services.s3.model.AbortMultipartUploadRequest;
2021
import com.amazonaws.services.s3.model.Bucket;
2122
import com.amazonaws.services.s3.model.BucketAccelerateConfiguration;
@@ -57,6 +58,7 @@
5758
import com.amazonaws.services.s3.model.inventory.InventoryConfiguration;
5859
import com.amazonaws.services.s3.model.metrics.MetricsConfiguration;
5960
import com.amazonaws.services.s3.model.ownership.OwnershipControls;
61+
import java.net.URI;
6062
import java.util.ArrayList;
6163
import java.util.List;
6264

@@ -243,4 +245,18 @@ private void setBucketConfigs(AmazonS3 s3, String bucket) {
243245
private void setBucketNameTest(AmazonS3 s3, String bucket) {
244246
GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, "key").withBucketName(bucket);
245247
}
248+
249+
private void s3Uri(URI uri, String uriAsString) {
250+
AmazonS3URI s3Uri = new AmazonS3URI(uri);
251+
252+
String versionId = s3Uri.getVersionId();
253+
String bucket = s3Uri.getBucket();
254+
String key = s3Uri.getKey();
255+
String region = s3Uri.getRegion();
256+
boolean isPathStyle = s3Uri.isPathStyle();
257+
258+
AmazonS3URI s3UriFromString = new AmazonS3URI(uriAsString);
259+
260+
AmazonS3URI s3UriFromStringWithUrlEncodeFalse = new AmazonS3URI(uriAsString, false);
261+
}
246262
}
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
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 static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.V1_S3_PKG;
19+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.V2_S3_PKG;
20+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.createComments;
21+
import static software.amazon.awssdk.v2migration.internal.utils.SdkTypeUtils.isStringType;
22+
import static software.amazon.awssdk.v2migration.internal.utils.SdkTypeUtils.isUriType;
23+
24+
import java.util.List;
25+
import java.util.regex.Pattern;
26+
import org.openrewrite.ExecutionContext;
27+
import org.openrewrite.NlsRewrite;
28+
import org.openrewrite.Recipe;
29+
import org.openrewrite.TreeVisitor;
30+
import org.openrewrite.java.AddImport;
31+
import org.openrewrite.java.JavaTemplate;
32+
import org.openrewrite.java.JavaVisitor;
33+
import org.openrewrite.java.RemoveImport;
34+
import org.openrewrite.java.tree.Comment;
35+
import org.openrewrite.java.tree.Expression;
36+
import org.openrewrite.java.tree.J;
37+
import org.openrewrite.java.tree.JavaType;
38+
import org.openrewrite.java.tree.TypeTree;
39+
import software.amazon.awssdk.annotations.SdkInternalApi;
40+
41+
@SdkInternalApi
42+
public class S3UriToV2 extends Recipe {
43+
44+
private static final Pattern V1_AMAZON_S3_URI = Pattern.compile(V1_S3_PKG + "AmazonS3URI");
45+
private static final String V2_S3_URI = V2_S3_PKG + "S3Uri";
46+
47+
@Override
48+
public @NlsRewrite.DisplayName String getDisplayName() {
49+
return "Convert v1 AmazonS3URI to v2 S3Uri";
50+
}
51+
52+
@Override
53+
public @NlsRewrite.Description String getDescription() {
54+
return "Convert v1 AmazonS3URI to v2 S3Uri";
55+
}
56+
57+
@Override
58+
public TreeVisitor<?, ExecutionContext> getVisitor() {
59+
return new Visitor();
60+
}
61+
62+
private static final class Visitor extends JavaVisitor<ExecutionContext> {
63+
64+
@Override
65+
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations variableDecls, ExecutionContext ctx) {
66+
J.VariableDeclarations varDec = (J.VariableDeclarations) super.visitVariableDeclarations(variableDecls, ctx);
67+
68+
JavaType type = varDec.getType();
69+
if (type == null) {
70+
return varDec;
71+
}
72+
73+
if (!type.isAssignableFrom(V1_AMAZON_S3_URI)) {
74+
return varDec;
75+
}
76+
77+
addV2S3UriImport();
78+
removeV1S3UriImport();
79+
JavaType v2Type = JavaType.buildType(V2_S3_URI);
80+
TypeTree v2TypeTree = TypeTree.build("S3Uri");
81+
return varDec.withType(v2Type).withTypeExpression(v2TypeTree);
82+
}
83+
84+
@Override
85+
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
86+
method = (J.MethodInvocation) super.visitMethodInvocation(method, ctx);
87+
JavaType.Method methodType = method.getMethodType();
88+
89+
if (methodType == null) {
90+
return method;
91+
}
92+
93+
Expression select = method.getSelect();
94+
if (select == null) {
95+
return method;
96+
}
97+
JavaType selectType = select.getType();
98+
if (selectType == null || !selectType.isAssignableFrom(V1_AMAZON_S3_URI)) {
99+
return method;
100+
}
101+
102+
String methodName = method.getSimpleName();
103+
String v2Method;
104+
105+
switch (methodName) {
106+
case "getVersionId":
107+
v2Method = "#{any()}.firstMatchingRawQueryParameter(\"versionId\").orElse(null)";
108+
break;
109+
case "getBucket":
110+
v2Method = "#{any()}.bucket().orElse(null)";
111+
break;
112+
case "getKey":
113+
v2Method = "#{any()}.key().orElse(null)";
114+
break;
115+
case "getRegion":
116+
v2Method = "#{any()}.region().map(Region::id).orElse(null)";
117+
addV2RegionImport();
118+
break;
119+
default:
120+
return method;
121+
}
122+
123+
124+
return JavaTemplate.builder(v2Method).build().apply(getCursor(), method.getCoordinates().replace(),
125+
method.getSelect());
126+
}
127+
128+
@Override
129+
public J visitNewClass(J.NewClass previousNewClass, ExecutionContext ctx) {
130+
J.NewClass newClass = super.visitNewClass(previousNewClass, ctx).cast();
131+
132+
JavaType type = newClass.getType();
133+
if (!(type instanceof JavaType.FullyQualified) || !type.isAssignableFrom(V1_AMAZON_S3_URI)) {
134+
return newClass;
135+
}
136+
137+
List<Expression> args = newClass.getArguments();
138+
Expression uriArg = args.get(0);
139+
JavaType uriType = uriArg.getType();
140+
if (uriType == null) {
141+
return newClass;
142+
}
143+
144+
StringBuilder sb = new StringBuilder("S3Utilities.builder().build().parseUri(");
145+
146+
if (isUriType(uriType)) {
147+
sb.append("#{any()})");
148+
} else if (isStringType(uriType)) {
149+
sb.append("URI.create(#{any()})");
150+
addJavaUriImport();
151+
}
152+
153+
J.MethodInvocation newMethod = JavaTemplate.builder(sb.toString()).build()
154+
.apply(getCursor(), newClass.getCoordinates().replace(), uriArg);
155+
156+
if (shouldAddWarning(uriType, args)) {
157+
newMethod = newMethod.withComments(v2DoesNotEncodeWarning());
158+
}
159+
160+
removeV1S3UriImport();
161+
addS3UtilitiesImport();
162+
return newMethod;
163+
}
164+
165+
private boolean shouldAddWarning(JavaType uriType, List<Expression> args) {
166+
if (isUriType(uriType)) {
167+
return false;
168+
}
169+
if (args.size() == 1) {
170+
return true;
171+
}
172+
return !urlEncodeArgIsLiteralFalse(args.get(1));
173+
}
174+
175+
private boolean urlEncodeArgIsLiteralFalse(Expression arg) {
176+
if (arg instanceof J.Literal) {
177+
J.Literal literal = (J.Literal) arg;
178+
return literal.getValue().equals(Boolean.FALSE);
179+
}
180+
return false;
181+
}
182+
183+
184+
private List<Comment> v2DoesNotEncodeWarning() {
185+
String warning = "v2 S3Uri does not URL-encode a String URI. If you relied on this functionality in v1 you must "
186+
+ "update your code to manually encode the String.";
187+
return createComments(warning);
188+
}
189+
190+
private void removeV1S3UriImport() {
191+
doAfterVisit(new RemoveImport<>(V1_AMAZON_S3_URI.toString(), true));
192+
}
193+
194+
private void addV2S3UriImport() {
195+
doAfterVisit(new AddImport<>(V2_S3_URI, null, false));
196+
}
197+
198+
private void addS3UtilitiesImport() {
199+
String fqcn = V2_S3_PKG + "S3Utilities";
200+
doAfterVisit(new AddImport<>(fqcn, null, false));
201+
}
202+
203+
private void addV2RegionImport() {
204+
String fqcn = "software.amazon.awssdk.regions.Region";
205+
doAfterVisit(new AddImport<>(fqcn, null, false));
206+
}
207+
208+
private void addJavaUriImport() {
209+
String fqcn = "java.net.URI";
210+
doAfterVisit(new AddImport<>(fqcn, null, false));
211+
}
212+
}
213+
}

v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/S3TransformUtils.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,24 @@
1515

1616
package software.amazon.awssdk.v2migration.internal.utils;
1717

18+
import java.util.Collections;
19+
import java.util.List;
1820
import org.openrewrite.java.MethodMatcher;
21+
import org.openrewrite.java.tree.Comment;
22+
import org.openrewrite.java.tree.TextComment;
23+
import org.openrewrite.marker.Markers;
1924
import software.amazon.awssdk.annotations.SdkInternalApi;
2025

2126
@SdkInternalApi
2227
public final class S3TransformUtils {
2328

2429
public static final String V1_S3_CLIENT = "com.amazonaws.services.s3.AmazonS3";
2530
public static final String V1_S3_MODEL_PKG = "com.amazonaws.services.s3.model.";
31+
public static final String V1_S3_PKG = "com.amazonaws.services.s3.";
2632

2733
public static final String V2_S3_CLIENT = "software.amazon.awssdk.services.s3.S3Client";
2834
public static final String V2_S3_MODEL_PKG = "software.amazon.awssdk.services.s3.model.";
35+
public static final String V2_S3_PKG = "software.amazon.awssdk.services.s3.";
2936

3037
public static final String V2_TM_CLIENT = "software.amazon.awssdk.transfer.s3.S3TransferManager";
3138
public static final String V2_TM_MODEL_PKG = "software.amazon.awssdk.transfer.s3.model.";
@@ -45,4 +52,9 @@ public static MethodMatcher v2S3MethodMatcher(String methodSignature) {
4552
public static MethodMatcher v2TmMethodMatcher(String methodSignature) {
4653
return new MethodMatcher(V2_TM_CLIENT + " " + methodSignature, true);
4754
}
55+
56+
public static List<Comment> createComments(String comment) {
57+
return Collections.singletonList(
58+
new TextComment(true, "AWS SDK for Java v2 migration: " + comment, "", Markers.EMPTY));
59+
}
4860
}

v2-migration/src/main/java/software/amazon/awssdk/v2migration/internal/utils/SdkTypeUtils.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,4 +671,12 @@ public static boolean isInputStreamType(JavaType type) {
671671
public static boolean isFileType(JavaType type) {
672672
return TypeUtils.isAssignableTo("java.io.File", type);
673673
}
674+
675+
public static boolean isStringType(JavaType type) {
676+
return TypeUtils.isAssignableTo("java.lang.String", type);
677+
}
678+
679+
public static boolean isUriType(JavaType type) {
680+
return TypeUtils.isAssignableTo("java.net.URI", type);
681+
}
674682
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ recipeList:
2828
- software.amazon.awssdk.v2migration.S3NonStreamingRequestToV2
2929
- software.amazon.awssdk.v2migration.S3MethodsToV2
3030
- software.amazon.awssdk.v2migration.S3MethodsConstructorToFluent
31+
- software.amazon.awssdk.v2migration.S3UriToV2
3132
- software.amazon.awssdk.v2migration.EnumGettersToV2
3233
- software.amazon.awssdk.v2migration.ChangeTransferManagerTypes
3334
- software.amazon.awssdk.v2migration.ChangeSdkType

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ recipeList:
2727
- software.amazon.awssdk.v2migration.S3NonStreamingRequestToV2
2828
- software.amazon.awssdk.v2migration.S3MethodsToV2
2929
- software.amazon.awssdk.v2migration.S3MethodsConstructorToFluent
30+
- software.amazon.awssdk.v2migration.S3UriToV2
3031
- software.amazon.awssdk.v2migration.EnumGettersToV2
3132
- software.amazon.awssdk.v2migration.ChangeSdkType
3233
- software.amazon.awssdk.v2migration.ChangeSdkCoreTypes

0 commit comments

Comments
 (0)