Skip to content

Commit 6ba2035

Browse files
authored
Migration tool : Setters to toBuilder() setters (#6000)
* Migration tool - setters to toBuilder setters * Add integ tests
1 parent 5c289d7 commit 6ba2035

File tree

11 files changed

+158
-43
lines changed

11 files changed

+158
-43
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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ void objectmetadata_unsupportedSetters(Date dateVal) {
6464
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - ongoingRestore - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.ongoingRestore(false);
6565
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - requesterCharged - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.requesterCharged(false);
6666

67-
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - lastModified - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.lastModified(dateVal);
68-
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - expirationTime - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.expirationTime(dateVal);
69-
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - restoreExpirationTime - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.restoreExpirationTime(dateVal);
67+
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - lastModified - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.lastModified(dateVal.toInstant());
68+
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - expirationTime - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.expirationTime(dateVal.toInstant());
69+
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - restoreExpirationTime - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.restoreExpirationTime(dateVal.toInstant());
7070

7171
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - header - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.header("key", "val");
7272
/*AWS SDK for Java v2 migration: Transform for ObjectMetadata setter - addUserMetadata - is not supported, please manually migrate the code by setting it on the v2 request/response object.*/metadata.addUserMetadata("a", "b");

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import software.amazon.awssdk.services.sqs.model.ListQueuesRequest;
3636
import software.amazon.awssdk.services.sqs.model.ListQueuesResponse;
3737
import software.amazon.awssdk.services.sqs.model.QueueDoesNotExistException;
38+
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;
3839
import software.amazon.awssdk.services.sqs.model.SqsException;
3940

4041
public class Application {
@@ -113,5 +114,17 @@ void dateToInstant(Date start, Date end) {
113114
.startTime(start.toInstant())
114115
.endTime(end.toInstant())
115116
.build();
117+
118+
GetMetricStatisticsRequest getMetricStatisticsRequest2 = GetMetricStatisticsRequest.builder()
119+
.build();
120+
getMetricStatisticsRequest2 = getMetricStatisticsRequest2.toBuilder().startTime(start.toInstant()).build();
121+
getMetricStatisticsRequest2 = getMetricStatisticsRequest2.toBuilder().endTime(end.toInstant()).build();
122+
}
123+
124+
void pojoSettersAfterCreation() {
125+
SendMessageRequest sendMessageRequest = SendMessageRequest.builder()
126+
.build();
127+
sendMessageRequest = sendMessageRequest.toBuilder().messageGroupId("groupId").build();
128+
sendMessageRequest = sendMessageRequest.toBuilder().queueUrl("queueUrl").build();
116129
}
117130
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.amazonaws.services.sqs.model.AmazonSQSException;
2929
import com.amazonaws.services.sqs.model.ListQueuesRequest;
3030
import com.amazonaws.services.sqs.model.ListQueuesResult;
31+
import com.amazonaws.services.sqs.model.SendMessageRequest;
3132

3233
import java.io.IOException;
3334
import java.io.InputStream;
@@ -107,5 +108,15 @@ void dateToInstant(Date start, Date end) {
107108
GetMetricStatisticsRequest getMetricStatisticsRequest = new GetMetricStatisticsRequest()
108109
.withStartTime(start)
109110
.withEndTime(end);
111+
112+
GetMetricStatisticsRequest getMetricStatisticsRequest2 = new GetMetricStatisticsRequest();
113+
getMetricStatisticsRequest2.setStartTime(start);
114+
getMetricStatisticsRequest2.setEndTime(end);
115+
}
116+
117+
void pojoSettersAfterCreation() {
118+
SendMessageRequest sendMessageRequest = new SendMessageRequest();
119+
sendMessageRequest.setMessageGroupId("groupId");
120+
sendMessageRequest.setQueueUrl("queueUrl");
110121
}
111122
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ private static boolean isV2ModelSetterWithDateParam(J.MethodInvocation method) {
8282
}
8383

8484
boolean isDateParam = javaType.isAssignableFrom(DATE_PATTERN);
85-
return SdkTypeUtils.isV2ModelBuilder(declaringType) && isDateParam;
85+
boolean isV2Model = SdkTypeUtils.isV2ModelBuilder(declaringType) || SdkTypeUtils.isV2ModelClass(declaringType);
86+
return isDateParam && isV2Model;
8687
}
8788
}
8889
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public class S3NonStreamingRequestToV2Complex extends Recipe {
5757
private static final MethodMatcher LIST_BUCKETS = v2S3MethodMatcher("listBuckets()");
5858
private static final MethodMatcher RESTORE_OBJECT = v2S3MethodMatcher("restoreObject(String, String, int)");
5959
private static final MethodMatcher SET_OBJECT_REDIRECT_LOCATION =
60-
v2S3MethodMatcher("objectRedirectLocation(String, String, String)");
60+
v2S3MethodMatcher("setObjectRedirectLocation(String, String, String)");
6161
private static final MethodMatcher CHANGE_OBJECT_STORAGE_CLASS = v2S3MethodMatcher(
6262
String.format("changeObjectStorageClass(String, String, %sStorageClass)", V2_S3_MODEL_PKG));
6363
private static final MethodMatcher CREATE_BUCKET = v2S3MethodMatcher("createBucket(String, String)");

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

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.createComments;
2323
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.getArgumentName;
2424
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.getSelectName;
25+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isObjectMetadataSetter;
2526
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isPayloadSetter;
27+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isPutObjectRequestBuilderSetter;
28+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isPutObjectRequestSetter;
2629
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isRequestMetadataSetter;
2730
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isRequestPayerSetter;
2831
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.v2S3MethodMatcher;
@@ -36,7 +39,6 @@
3639
import java.util.List;
3740
import java.util.Map;
3841
import java.util.Queue;
39-
import java.util.regex.Pattern;
4042
import org.openrewrite.ExecutionContext;
4143
import org.openrewrite.Recipe;
4244
import org.openrewrite.TreeVisitor;
@@ -47,7 +49,6 @@
4749
import org.openrewrite.java.tree.Comment;
4850
import org.openrewrite.java.tree.Expression;
4951
import org.openrewrite.java.tree.J;
50-
import org.openrewrite.java.tree.TypeUtils;
5152
import software.amazon.awssdk.annotations.SdkInternalApi;
5253

5354
@SdkInternalApi
@@ -63,8 +64,6 @@ public class S3PutObjectRequestToV2 extends Recipe {
6364
private static final MethodMatcher UPLOAD_WITH_REQUEST =
6465
v2TmMethodMatcher(String.format("upload(%sPutObjectRequest)", V2_S3_MODEL_PKG));
6566

66-
private static final Pattern METADATA_V2 = Pattern.compile(V2_S3_MODEL_PKG + "HeadObjectResponse");
67-
6867
@Override
6968
public String getDisplayName() {
7069
return "V1 S3 PutObjectRequest, AmazonS3.putObject(PutObjectRequest), and TransferManager.upload(PutObjectRequest) to V2";
@@ -412,15 +411,6 @@ private Expression retrieveContentLengthForMetadataIfSet(String metadataName) {
412411
return map.get("contentLength");
413412
}
414413

415-
private boolean isObjectMetadataSetter(J.MethodInvocation method) {
416-
if (method.getSelect() == null || method.getSelect().getType() == null) {
417-
return false;
418-
}
419-
420-
return method.getSelect().getType().isAssignableFrom(METADATA_V2)
421-
&& !method.getArguments().isEmpty();
422-
}
423-
424414
private J.MethodInvocation saveMetadataValueAndRemoveStatement(J.MethodInvocation method) {
425415
J.Identifier metadataPojo = (J.Identifier) method.getSelect();
426416
String variableName = metadataPojo.getSimpleName();
@@ -464,28 +454,6 @@ private J.MethodInvocation transformWithRequesterPays(J.MethodInvocation method)
464454
.apply(getCursor(), method.getCoordinates().replaceArguments());
465455
}
466456

467-
/** Field set during POJO instantiation, e.g.,
468-
* PutObjectRequest request = new PutObjectRequest("bucket" "key", "redirectLocation").withFile(file);
469-
*/
470-
private boolean isPutObjectRequestBuilderSetter(J.MethodInvocation method) {
471-
return isSetterForClassType(method, "software.amazon.awssdk.services.s3.model.PutObjectRequest$Builder");
472-
}
473-
474-
/** Field set after POJO instantiation, e.g.,
475-
* PutObjectRequest request = new PutObjectRequest("bucket" "key", "redirectLocation");
476-
* request.setFile(file);
477-
*/
478-
private boolean isPutObjectRequestSetter(J.MethodInvocation method) {
479-
return isSetterForClassType(method, "software.amazon.awssdk.services.s3.model.PutObjectRequest");
480-
}
481-
482-
private boolean isSetterForClassType(J.MethodInvocation method, String fqcn) {
483-
if (method.getSelect() == null || method.getSelect().getType() == null) {
484-
return false;
485-
}
486-
return TypeUtils.isOfClassType(method.getSelect().getType(), fqcn);
487-
}
488-
489457
private void addRequestBodyImport() {
490458
String fqcn = "software.amazon.awssdk.core.sync.RequestBody";
491459
doAfterVisit(new AddImport<>(fqcn, null, false));
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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.NamingUtils.isSetter;
19+
import static software.amazon.awssdk.v2migration.internal.utils.NamingUtils.removeSet;
20+
import static software.amazon.awssdk.v2migration.internal.utils.SdkTypeUtils.isV2ModelClass;
21+
22+
import org.openrewrite.ExecutionContext;
23+
import org.openrewrite.NlsRewrite;
24+
import org.openrewrite.Recipe;
25+
import org.openrewrite.TreeVisitor;
26+
import org.openrewrite.java.JavaTemplate;
27+
import org.openrewrite.java.JavaVisitor;
28+
import org.openrewrite.java.tree.J;
29+
import software.amazon.awssdk.annotations.SdkInternalApi;
30+
31+
@SdkInternalApi
32+
public class SettersToBuilderV2 extends Recipe {
33+
34+
@Override
35+
public @NlsRewrite.DisplayName String getDisplayName() {
36+
return "Convert V1 setters to V2 toBuilder setters";
37+
}
38+
39+
@Override
40+
public @NlsRewrite.Description String getDescription() {
41+
return "Convert V1 setters to V2 toBuilder setters";
42+
}
43+
44+
@Override
45+
public TreeVisitor<?, ExecutionContext> getVisitor() {
46+
return new Visitor();
47+
}
48+
49+
private static final class Visitor extends JavaVisitor<ExecutionContext> {
50+
51+
52+
@Override
53+
public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
54+
55+
if (isV2ModelClassSetter(method)) {
56+
return convertSetterToBuilder(method);
57+
}
58+
59+
return method;
60+
}
61+
62+
private boolean isV2ModelClassSetter(J.MethodInvocation method) {
63+
return isV2ModelClass(method.getType())
64+
&& method.getArguments().size() == 1
65+
&& isSetter(method.getSimpleName());
66+
}
67+
68+
private J convertSetterToBuilder(J.MethodInvocation method) {
69+
String v2Method = String.format("#{any()} = #{any()}.toBuilder().%s(#{any()}).build()",
70+
removeSet(method.getSimpleName()));
71+
72+
return JavaTemplate.builder(v2Method).build()
73+
.apply(getCursor(), method.getCoordinates().replace(),
74+
method.getSelect(), method.getSelect(), method.getArguments().get(0));
75+
}
76+
}
77+
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
package software.amazon.awssdk.v2migration;
1717

18+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.hasArguments;
19+
import static software.amazon.awssdk.v2migration.internal.utils.S3TransformUtils.isS3PutObjectOrObjectMetadata;
1820
import static software.amazon.awssdk.v2migration.internal.utils.SdkTypeUtils.isEligibleToConvertToBuilder;
1921
import static software.amazon.awssdk.v2migration.internal.utils.SdkTypeUtils.isV2CoreClassBuilder;
2022
import static software.amazon.awssdk.v2migration.internal.utils.SdkTypeUtils.isV2ModelBuilder;
@@ -73,6 +75,10 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation previousMetho
7375
ExecutionContext executionContext) {
7476
J.MethodInvocation method = super.visitMethodInvocation(previousMethodInvocation, executionContext);
7577

78+
if (!hasArguments(method)) {
79+
return method;
80+
}
81+
7682
JavaType selectType = null;
7783

7884
Expression select = method.getSelect();
@@ -98,7 +104,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation previousMetho
98104

99105
if (NamingUtils.isWither(methodName)) {
100106
methodName = NamingUtils.removeWith(methodName);
101-
} else if (NamingUtils.isSetter(methodName)) {
107+
} else if (NamingUtils.isSetter(methodName) && isS3PutObjectOrObjectMetadata(method)) {
108+
// We will change remaining setters to `request = request.toBuilder().setter(val).build()` in SettersToBuilderV2
102109
methodName = NamingUtils.removeSet(methodName);
103110
}
104111

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

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public static void addMetadataFields(StringBuilder sb, String metadataName,
139139
}
140140
Expression expiresDate = map.get("httpExpiresDate");
141141
if (expiresDate != null) {
142-
sb.append(".expires(").append(expiresDate).append(".toInstant())\n");
142+
sb.append(".expires(").append(expiresDate).append(")\n");
143143
}
144144
}
145145

@@ -158,6 +158,42 @@ public static List<Comment> createComments(String comment) {
158158
new TextComment(true, "AWS SDK for Java v2 migration: " + comment, "", Markers.EMPTY));
159159
}
160160

161+
public static boolean isObjectMetadataSetter(J.MethodInvocation method) {
162+
return isSetterForClassType(method, V2_S3_MODEL_PKG + "HeadObjectResponse");
163+
}
164+
165+
/** Field set during POJO instantiation, e.g.,
166+
* PutObjectRequest request = new PutObjectRequest("bucket" "key", "redirectLocation").withFile(file);
167+
*/
168+
public static boolean isPutObjectRequestBuilderSetter(J.MethodInvocation method) {
169+
return isSetterForClassType(method, "software.amazon.awssdk.services.s3.model.PutObjectRequest$Builder");
170+
}
171+
172+
/** Field set after POJO instantiation, e.g.,
173+
* PutObjectRequest request = new PutObjectRequest("bucket" "key", "redirectLocation");
174+
* request.setFile(file);
175+
*/
176+
public static boolean isPutObjectRequestSetter(J.MethodInvocation method) {
177+
return isSetterForClassType(method, "software.amazon.awssdk.services.s3.model.PutObjectRequest");
178+
}
179+
180+
public static boolean isS3PutObjectOrObjectMetadata(J.MethodInvocation method) {
181+
return isObjectMetadataSetter(method)
182+
|| isPutObjectRequestSetter(method)
183+
|| isPutObjectRequestBuilderSetter(method);
184+
}
185+
186+
public static boolean isSetterForClassType(J.MethodInvocation method, String fqcn) {
187+
if (method.getSelect() == null || method.getSelect().getType() == null) {
188+
return false;
189+
}
190+
return hasArguments(method) && TypeUtils.isOfClassType(method.getSelect().getType(), fqcn);
191+
}
192+
193+
public static boolean hasArguments(J.MethodInvocation method) {
194+
return !method.getArguments().isEmpty();
195+
}
196+
161197
public static boolean isPayloadSetter(J.MethodInvocation method) {
162198
return "file".equals(method.getSimpleName()) || "inputStream".equals(method.getSimpleName());
163199
}

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
@@ -46,4 +46,5 @@ recipeList:
4646
- software.amazon.awssdk.v2migration.DateToInstant
4747
- software.amazon.awssdk.v2migration.S3NonStreamingRequestToV2Complex
4848
- software.amazon.awssdk.v2migration.S3PutObjectRequestToV2
49+
- software.amazon.awssdk.v2migration.SettersToBuilderV2
4950
- software.amazon.awssdk.v2migration.TransferManagerMethodsToV2

0 commit comments

Comments
 (0)