Skip to content

Commit fe69254

Browse files
committed
Support code transformation for credentials related classes.
Add NewClassToStaticFactory reciipe to convert objects creating using constructor to static factory method Refactor NewClassToBuilderPattern to support client classes
1 parent 5e99856 commit fe69254

File tree

19 files changed

+885
-120
lines changed

19 files changed

+885
-120
lines changed
Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
package software.amazon.awssdk.migration.internal.recipe;
1717

18+
import static software.amazon.awssdk.migration.internal.utils.SdkTypeUtils.isEligibleToConvertToBuilder;
19+
1820
import java.util.Collections;
1921
import org.openrewrite.ExecutionContext;
2022
import org.openrewrite.Recipe;
@@ -31,23 +33,24 @@
3133
import software.amazon.awssdk.annotations.SdkInternalApi;
3234
import software.amazon.awssdk.migration.internal.utils.NamingUtils;
3335
import software.amazon.awssdk.migration.internal.utils.SdkTypeUtils;
34-
import software.amazon.awssdk.migration.recipe.NewV1ModelClassToV2;
36+
import software.amazon.awssdk.migration.recipe.NewClassToBuilderPattern;
3537

3638
/**
37-
* Internal recipe that converts V1 model creation to the builder pattern.
39+
* Internal recipe that converts new class creation to the builder pattern.
3840
*
39-
* @see NewV1ModelClassToV2
41+
* @see NewClassToBuilderPattern
4042
*/
4143
@SdkInternalApi
42-
public class NewV1ClassToBuilder extends Recipe {
44+
public class NewClassToBuilder extends Recipe {
4345
@Override
4446
public String getDisplayName() {
4547
return "Transform 'new' expressions to builders";
4648
}
4749

4850
@Override
4951
public String getDescription() {
50-
return "Transforms 'new' expression for V1 model objects to the equivalent builder()..build() expression in V2.";
52+
return "Transforms 'new' expression for generated model, client objects and client config related objects to the "
53+
+ "equivalent builder()..build() expression in V2.";
5154
}
5255

5356
@Override
@@ -96,21 +99,25 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext execu
9699
public J visitNewClass(J.NewClass newClass, ExecutionContext executionContext) {
97100
newClass = super.visitNewClass(newClass, executionContext).cast();
98101

99-
JavaType classType = newClass.getType();
100-
if (!SdkTypeUtils.isV1ModelClass(classType)) {
102+
if (!(newClass.getType() instanceof JavaType.FullyQualified)) {
103+
return newClass;
104+
}
105+
106+
JavaType.FullyQualified classType = (JavaType.FullyQualified) newClass.getType();
107+
108+
if (!isEligibleToConvertToBuilder(classType)) {
101109
return newClass;
102110
}
103111

104-
JavaType.FullyQualified v2Type = SdkTypeUtils.asV2Type((JavaType.FullyQualified) classType);
105-
JavaType.FullyQualified v2TypeBuilder = SdkTypeUtils.v2ModelBuilder(v2Type);
112+
JavaType.FullyQualified builderType = SdkTypeUtils.v2Builder(classType);
106113

107114
J.Identifier modelId = new J.Identifier(
108115
Tree.randomId(),
109116
Space.EMPTY,
110117
Markers.EMPTY,
111118
Collections.emptyList(),
112-
v2Type.getClassName(),
113-
v2Type,
119+
classType.getClassName(),
120+
classType,
114121
null
115122
);
116123

@@ -127,9 +134,9 @@ public J visitNewClass(J.NewClass newClass, ExecutionContext executionContext) {
127134
JavaType.Method methodType = new JavaType.Method(
128135
null,
129136
0L,
130-
v2Type,
137+
classType,
131138
"builder",
132-
v2TypeBuilder,
139+
builderType,
133140
Collections.emptyList(),
134141
Collections.emptyList(),
135142
Collections.emptyList(),
@@ -145,7 +152,28 @@ public J visitNewClass(J.NewClass newClass, ExecutionContext executionContext) {
145152
builderMethod,
146153
JContainer.empty(),
147154
methodType
155+
);
156+
157+
J.Identifier buildName = new J.Identifier(
158+
Tree.randomId(),
159+
Space.EMPTY,
160+
Markers.EMPTY,
161+
Collections.emptyList(),
162+
"build",
163+
null,
164+
null
165+
);
148166

167+
JavaType.Method buildMethodType = new JavaType.Method(
168+
null,
169+
0L,
170+
builderType,
171+
"build",
172+
classType,
173+
Collections.emptyList(),
174+
Collections.emptyList(),
175+
Collections.emptyList(),
176+
Collections.emptyList()
149177
);
150178

151179
J.MethodInvocation buildInvoke = new J.MethodInvocation(
@@ -154,27 +182,9 @@ public J visitNewClass(J.NewClass newClass, ExecutionContext executionContext) {
154182
Markers.EMPTY,
155183
JRightPadded.build(builderInvoke),
156184
null,
157-
new J.Identifier(
158-
Tree.randomId(),
159-
Space.EMPTY,
160-
Markers.EMPTY,
161-
Collections.emptyList(),
162-
"build",
163-
v2Type,
164-
null
165-
),
185+
buildName,
166186
JContainer.empty(),
167-
new JavaType.Method(
168-
null,
169-
0L,
170-
v2TypeBuilder,
171-
"build",
172-
v2Type,
173-
Collections.emptyList(),
174-
Collections.emptyList(),
175-
Collections.emptyList(),
176-
Collections.emptyList()
177-
)
187+
buildMethodType
178188
);
179189

180190
return buildInvoke;

migration-tool/src/main/java/software/amazon/awssdk/migration/internal/recipe/V1SetterToV2.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
package software.amazon.awssdk.migration.internal.recipe;
1717

18+
import static software.amazon.awssdk.migration.internal.utils.SdkTypeUtils.isV2ClientClass;
19+
import static software.amazon.awssdk.migration.internal.utils.SdkTypeUtils.isV2ModelClass;
20+
1821
import org.openrewrite.ExecutionContext;
1922
import org.openrewrite.Recipe;
2023
import org.openrewrite.TreeVisitor;
@@ -25,13 +28,12 @@
2528
import org.openrewrite.java.tree.TypeUtils;
2629
import software.amazon.awssdk.annotations.SdkInternalApi;
2730
import software.amazon.awssdk.migration.internal.utils.NamingUtils;
28-
import software.amazon.awssdk.migration.internal.utils.SdkTypeUtils;
29-
import software.amazon.awssdk.migration.recipe.NewV1ModelClassToV2;
31+
import software.amazon.awssdk.migration.recipe.NewClassToBuilderPattern;
3032

3133
/**
3234
* Internal recipe that renames fluent V1 setters (withers), to V2 equivalents.
3335
*
34-
* @see NewV1ModelClassToV2
36+
* @see NewClassToBuilderPattern
3537
*/
3638
@SdkInternalApi
3739
public class V1SetterToV2 extends Recipe {
@@ -42,7 +44,7 @@ public String getDisplayName() {
4244

4345
@Override
4446
public String getDescription() {
45-
return "Transforms a setter on a V1 model object to the equivalent in V2.";
47+
return "Transforms V1 setter to fluent setter in V2.";
4648
}
4749

4850
@Override
@@ -67,7 +69,7 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
6769
return method;
6870
}
6971

70-
if (SdkTypeUtils.isV2ModelBuilder(selectType) && !SdkTypeUtils.isV2ModelBuilder(method.getType())) {
72+
if (shouldChangeSetter(method, selectType)) {
7173
String methodName = method.getSimpleName();
7274

7375
if (NamingUtils.isWither(methodName)) {
@@ -97,5 +99,9 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
9799

98100
return method;
99101
}
102+
103+
private static boolean shouldChangeSetter(J.MethodInvocation method, JavaType selectType) {
104+
return isV2ModelClass(selectType) || isV2ClientClass(selectType);
105+
}
100106
}
101107
}

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

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,64 @@
1515

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

18+
import java.util.Arrays;
19+
import java.util.HashSet;
20+
import java.util.Map;
21+
import java.util.Set;
1822
import java.util.regex.Pattern;
1923
import org.openrewrite.java.tree.JavaType;
2024
import org.openrewrite.java.tree.TypeUtils;
2125
import software.amazon.awssdk.annotations.SdkInternalApi;
22-
import software.amazon.awssdk.utils.StringUtils;
26+
import software.amazon.awssdk.utils.ImmutableMap;
2327

2428
/**
2529
* Type creation and checking utilities.
2630
*/
2731
@SdkInternalApi
2832
public final class SdkTypeUtils {
33+
/**
34+
* V2 core classes with a static factory method
35+
*/
36+
public static final Map<String, Integer> V2_CORE_CLASSES_WITH_STATIC_FACTORY =
37+
ImmutableMap.<String, Integer>builder()
38+
.put("software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider", 0)
39+
.put("software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider", 0)
40+
.put("software.amazon.awssdk.auth.credentials.AwsBasicCredentials", 2)
41+
.put("software.amazon.awssdk.auth.credentials.AwsSessionCredentials", 3)
42+
.put("software.amazon.awssdk.auth.credentials.StaticCredentialsProvider", 1)
43+
.build();
44+
2945
private static final Pattern V1_SERVICE_CLASS_PATTERN =
3046
Pattern.compile("com\\.amazonaws\\.services\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+");
3147
private static final Pattern V1_SERVICE_MODEL_CLASS_PATTERN =
3248
Pattern.compile("com\\.amazonaws\\.services\\.[a-zA-Z0-9]+\\.model\\.[a-zA-Z0-9]+");
49+
50+
private static final Pattern V1_SERVICE_CLIENT_CLASS_PATTERN =
51+
Pattern.compile("com\\.amazonaws\\.services\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+");
3352
private static final Pattern V2_MODEL_BUILDER_PATTERN =
3453
Pattern.compile("software\\.amazon\\.awssdk\\.services\\.[a-zA-Z0-9]+\\.model\\.[a-zA-Z0-9]+\\.Builder");
3554
private static final Pattern V2_MODEL_CLASS_PATTERN = Pattern.compile(
3655
"software\\.amazon\\.awssdk\\.services\\.[a-zA-Z0-9]+\\.model\\..[a-zA-Z0-9]+");
56+
private static final Pattern V2_CLIENT_CLASS_PATTERN = Pattern.compile(
57+
"software\\.amazon\\.awssdk\\.services\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+");
58+
59+
/**
60+
* V2 core classes with a builder
61+
*/
62+
private static final Set<String> V2_CORE_CLASSES_WITH_BUILDER =
63+
new HashSet<>(Arrays.asList("software.amazon.awssdk.core.client.ClientOverrideConfiguration",
64+
"software.amazon.awssdk.auth.credentials.AwsSessionCredentials",
65+
"software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider",
66+
"software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider",
67+
"software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider",
68+
"software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider",
69+
"software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider",
70+
"software.amazon.awssdk.services.sts.auth.StsGetSessionTokenCredentialsProvider",
71+
"software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithWebIdentityCredentialsProvider",
72+
"software.amazon.awssdk.auth.credentials.ProcessCredentialsProvider"));
73+
74+
private static final Pattern V2_CLIENT_BUILDER_PATTERN = Pattern.compile(
75+
"software\\.amazon\\.awssdk\\.services\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+Builder");
3776

3877
private SdkTypeUtils() {
3978
}
@@ -48,6 +87,12 @@ public static boolean isV1ModelClass(JavaType type) {
4887
&& type.isAssignableFrom(V1_SERVICE_MODEL_CLASS_PATTERN);
4988
}
5089

90+
public static boolean isV1ClientClass(JavaType type) {
91+
return type != null
92+
&& type instanceof JavaType.FullyQualified
93+
&& type.isAssignableFrom(V1_SERVICE_CLIENT_CLASS_PATTERN);
94+
}
95+
5196
public static boolean isV2ModelBuilder(JavaType type) {
5297
return type != null
5398
&& type.isAssignableFrom(V2_MODEL_BUILDER_PATTERN);
@@ -58,26 +103,39 @@ public static boolean isV2ModelClass(JavaType type) {
58103
&& type.isAssignableFrom(V2_MODEL_CLASS_PATTERN);
59104
}
60105

61-
public static JavaType.FullyQualified asV2Type(JavaType.FullyQualified type) {
62-
if (!isV1ModelClass(type)) {
63-
throw new IllegalArgumentException(String.format("%s is not a V1 SDK model type", type));
64-
}
65-
66-
String className = type.getClassName();
67-
String packageName = type.getPackageName();
106+
public static boolean isV2ClientClass(JavaType type) {
107+
return type != null
108+
&& type.isAssignableFrom(V2_CLIENT_CLASS_PATTERN);
109+
}
68110

69-
packageName = StringUtils.replaceOnce(packageName, "com.amazonaws", "software.amazon.awssdk");
111+
public static boolean isV2ClientBuilder(JavaType type) {
112+
return type != null
113+
&& type.isAssignableFrom(V2_CLIENT_BUILDER_PATTERN);
114+
}
70115

71-
return TypeUtils.asFullyQualified(JavaType.buildType(String.format("%s.%s", packageName, className)));
116+
public static boolean isEligibleToConvertToBuilder(JavaType.FullyQualified type) {
117+
return isV2ModelClass(type) || isV2ClientClass(type) || isV2CoreClassesWithBuilder(type.getFullyQualifiedName());
72118
}
73119

74-
public static JavaType.FullyQualified v2ModelBuilder(JavaType.FullyQualified type) {
75-
if (!isV2ModelClass(type)) {
76-
throw new IllegalArgumentException(String.format("%s is not a V2 model class", type));
77-
}
120+
public static boolean isEligibleToConvertToStaticFactory(JavaType.FullyQualified type) {
121+
return type != null && V2_CORE_CLASSES_WITH_STATIC_FACTORY.containsKey(type.getFullyQualifiedName());
122+
}
78123

79-
String fqcn = String.format("%s.%s", type.getFullyQualifiedName(), "Builder");
124+
private static boolean isV2CoreClassesWithBuilder(String fqcn) {
125+
return V2_CORE_CLASSES_WITH_BUILDER.contains(fqcn);
126+
}
80127

128+
public static JavaType.FullyQualified v2Builder(JavaType.FullyQualified type) {
129+
if (!isEligibleToConvertToBuilder(type)) {
130+
throw new IllegalArgumentException(String.format("%s cannot be converted to builder", type));
131+
}
132+
String fqcn;
133+
if (isV2ModelClass(type)) {
134+
fqcn = String.format("%s.%s", type.getFullyQualifiedName(), "Builder");
135+
} else {
136+
fqcn = String.format("%s%s", type.getFullyQualifiedName(), "Builder");
137+
}
138+
81139
return TypeUtils.asFullyQualified(JavaType.buildType(fqcn));
82140
}
83141
}

migration-tool/src/main/java/software/amazon/awssdk/migration/recipe/ChangeSdkType.java

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package software.amazon.awssdk.migration.recipe;
1717

1818
import static software.amazon.awssdk.migration.internal.utils.NamingConversionUtils.getV2Equivalent;
19+
import static software.amazon.awssdk.migration.internal.utils.SdkTypeUtils.isV1ClientClass;
20+
import static software.amazon.awssdk.migration.internal.utils.SdkTypeUtils.isV1ModelClass;
1921

2022
import java.util.HashMap;
2123
import java.util.HashSet;
@@ -93,8 +95,19 @@ public J visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ct
9395

9496
@Override
9597
public J visitImport(J.Import anImport, ExecutionContext ctx) {
96-
String currentFqcn = currentFqcn(anImport);
97-
if (isV1Import(currentFqcn)) {
98+
JavaType.FullyQualified fullyQualified =
99+
Optional.ofNullable(anImport.getQualid())
100+
.map(J.FieldAccess::getType)
101+
.map(TypeUtils::asFullyQualified)
102+
.orElse(null);
103+
104+
if (fullyQualified == null) {
105+
return anImport;
106+
}
107+
108+
String currentFqcn = fullyQualified.getFullyQualifiedName();
109+
110+
if (isV1ModelClass(fullyQualified) || isV1ClientClass(fullyQualified)) {
98111
JavaType.ShallowClass originalType = JavaType.ShallowClass.build(currentFqcn);
99112
String v2Equivalent = getV2Equivalent(currentFqcn);
100113

@@ -464,19 +477,4 @@ private static JavaType.FullyQualified getTopLevelClassName(JavaType.FullyQualif
464477
classType = classType.getOwningClass();
465478
}
466479
}
467-
468-
private static boolean isV1Import(String currentFqcn) {
469-
if (currentFqcn != null) {
470-
return currentFqcn.startsWith(V1_PATTERN);
471-
}
472-
473-
return false;
474-
}
475-
476-
private static String currentFqcn(J.Import anImport) {
477-
JavaType.FullyQualified currentFqcn =
478-
TypeUtils.asFullyQualified(Optional.ofNullable(anImport.getQualid()).map(J.FieldAccess::getType).orElse(null));
479-
String curFqn = currentFqcn != null ? currentFqcn.getFullyQualifiedName() : null;
480-
return curFqn;
481-
}
482480
}

0 commit comments

Comments
 (0)