Skip to content

Commit

Permalink
Migration Tool Client Config Part 1: map builder variations to the st…
Browse files Browse the repository at this point in the history
…andard builder (#5165)

* WIP

* Add recipe to convert builder varitions to standard builder method
  • Loading branch information
zoewangg committed Apr 30, 2024
1 parent 9831bdf commit 7a638af
Show file tree
Hide file tree
Showing 12 changed files with 494 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static software.amazon.awssdk.migration.internal.utils.SdkTypeUtils.isV2ClientClass;
import static software.amazon.awssdk.migration.internal.utils.SdkTypeUtils.isV2ModelClass;

import java.util.Map;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
Expand All @@ -29,14 +30,23 @@
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.migration.internal.utils.NamingUtils;
import software.amazon.awssdk.migration.recipe.NewClassToBuilderPattern;
import software.amazon.awssdk.utils.ImmutableMap;

/**
* Internal recipe that renames fluent V1 setters (withers), to V2 equivalents.
* Internal recipe that renames fluent V1 setters (withers), to V2 equivalents
* for generated model classes and client classes.
*
* @see NewClassToBuilderPattern
*/
@SdkInternalApi
public class V1SetterToV2 extends Recipe {
private static final Map<String, String> CLIENT_CONFIG_NAMING_MAPPING =
ImmutableMap.<String, String>builder()
.put("credentials", "credentialsProvider")
.put("clientConfiguration", "overrideConfiguration")
.put("endpointConfiguration", "endpointOverride")
.build();

@Override
public String getDisplayName() {
return "V1 Setter to V2";
Expand Down Expand Up @@ -65,42 +75,44 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
selectType = select.getType();
}

if (selectType == null) {
if (selectType == null || !shouldChangeSetter(selectType)) {
return method;
}

if (shouldChangeSetter(method, selectType)) {
String methodName = method.getSimpleName();
String methodName = method.getSimpleName();

if (NamingUtils.isWither(methodName)) {
methodName = NamingUtils.removeWith(methodName);
} else if (NamingUtils.isSetter(methodName)) {
methodName = NamingUtils.removeSet(methodName);
}
if (NamingUtils.isWither(methodName)) {
methodName = NamingUtils.removeWith(methodName);
} else if (NamingUtils.isSetter(methodName)) {
methodName = NamingUtils.removeSet(methodName);
}

JavaType.Method mt = method.getMethodType();
if (isV2ClientClass(selectType)) {
methodName = CLIENT_CONFIG_NAMING_MAPPING.getOrDefault(methodName, methodName);
}

if (mt != null) {
mt = mt.withName(methodName)
.withReturnType(selectType);
JavaType.Method mt = method.getMethodType();

JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(selectType);
if (mt != null) {
mt = mt.withName(methodName)
.withReturnType(selectType);

if (fullyQualified != null) {
mt = mt.withDeclaringType(fullyQualified);
}
JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(selectType);

method = method.withName(method.getName()
.withSimpleName(methodName)
.withType(mt))
.withMethodType(mt);
if (fullyQualified != null) {
mt = mt.withDeclaringType(fullyQualified);
}

method = method.withName(method.getName()
.withSimpleName(methodName)
.withType(mt))
.withMethodType(mt);
}

return method;
}

private static boolean shouldChangeSetter(J.MethodInvocation method, JavaType selectType) {
private static boolean shouldChangeSetter(JavaType selectType) {
return isV2ModelClass(selectType) || isV2ClientClass(selectType);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,19 @@ public final class SdkTypeUtils {

private static final Pattern V1_SERVICE_CLIENT_CLASS_PATTERN =
Pattern.compile("com\\.amazonaws\\.services\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+");
private static final Pattern V1_SERVICE_CLIENT_BUILDER_CLASS_PATTERN =
Pattern.compile("com\\.amazonaws\\.services\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+Builder");

private static final Pattern V2_MODEL_BUILDER_PATTERN =
Pattern.compile("software\\.amazon\\.awssdk\\.services\\.[a-zA-Z0-9]+\\.model\\.[a-zA-Z0-9]+\\.Builder");
private static final Pattern V2_MODEL_CLASS_PATTERN = Pattern.compile(
"software\\.amazon\\.awssdk\\.services\\.[a-zA-Z0-9]+\\.model\\..[a-zA-Z0-9]+");
private static final Pattern V2_CLIENT_CLASS_PATTERN = Pattern.compile(
"software\\.amazon\\.awssdk\\.services\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+");

private static final Pattern V2_ASYNC_CLIENT_CLASS_PATTERN = Pattern.compile(
"software\\.amazon\\.awssdk\\.services\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+AsyncClient");

/**
* V2 core classes with a builder
*/
Expand Down Expand Up @@ -107,6 +113,11 @@ public static boolean isV2ClientClass(JavaType type) {
&& type.isAssignableFrom(V2_CLIENT_CLASS_PATTERN);
}

public static boolean isV2AsyncClientClass(JavaType type) {
return type != null
&& type.isAssignableFrom(V2_ASYNC_CLIENT_CLASS_PATTERN);
}

public static boolean isV2ClientBuilder(JavaType type) {
return type != null
&& type.isAssignableFrom(V2_CLIENT_BUILDER_PATTERN);
Expand Down Expand Up @@ -137,4 +148,13 @@ public static JavaType.FullyQualified v2Builder(JavaType.FullyQualified type) {

return TypeUtils.asFullyQualified(JavaType.buildType(fqcn));
}

public static JavaType.FullyQualified v2ClientFromClientBuilder(JavaType.FullyQualified type) {
if (!isV2ClientBuilder(type)) {
throw new IllegalArgumentException(String.format("%s is not a client builder", type));
}

String builder = type.getFullyQualifiedName().replace("Builder", "");
return TypeUtils.asFullyQualified(JavaType.buildType(builder));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@
import java.util.Set;
import java.util.Stack;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.RemoveImport;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.Flag;
import org.openrewrite.java.tree.J;
Expand Down Expand Up @@ -72,7 +70,7 @@ public String getDescription() {

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(new UsesType<>("com.amazonaws.*", true), new ChangeTypeVisitor());
return new ChangeTypeVisitor();
}

private static class ChangeTypeVisitor extends JavaVisitor<ExecutionContext> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.migration.recipe;

import static software.amazon.awssdk.migration.internal.utils.SdkTypeUtils.isV2AsyncClientClass;
import static software.amazon.awssdk.migration.internal.utils.SdkTypeUtils.isV2ClientBuilder;

import java.util.Collections;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.Tree;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JContainer;
import org.openrewrite.java.tree.JRightPadded;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.Space;
import org.openrewrite.java.tree.TypeUtils;
import org.openrewrite.marker.Markers;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.migration.internal.utils.SdkTypeUtils;

/**
* Internal recipe that renames V1 client builder variations. For example: {@code SqsClientBuilder.standard().build()} to
* {@code SqsClient.builder().build()} and {@code SqsAsyncClient.asyncBuilder().build()} to
* {@code SqsAsyncClient.builder().build()}.
*/
@SdkInternalApi
public class V1BuilderVariationsToV2Builder extends Recipe {

@Override
public String getDisplayName() {
return "V1 client builder variations to builder()";
}

@Override
public String getDescription() {
return "Transforms V1 builder variations to builder()";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new Visitor();
}

private static class Visitor extends JavaIsoVisitor<ExecutionContext> {

@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
method = super.visitMethodInvocation(method, executionContext);

JavaType selectType = null;

Expression select = method.getSelect();
if (select != null) {
selectType = select.getType();
}

if (selectType == null || !shouldChangeMethod(selectType)) {
return method;
}

if (isV2AsyncClientClass(selectType)) {
return renameAsyncBuilderToBuilder(method, selectType);
}

if (isV2ClientBuilder(selectType)) {
return renameStandardToBuilder(method, selectType);
}

return method;
}

private static boolean shouldChangeMethod(JavaType selectType) {
return isV2ClientBuilder(selectType) || isV2AsyncClientClass(selectType);
}

private J.MethodInvocation renameStandardToBuilder(J.MethodInvocation method, JavaType selectType) {
String methodName = method.getSimpleName();
JavaType.Method mt = method.getMethodType();
JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(selectType);

if (mt == null || !"standard".equals(methodName) || fullyQualified == null) {
return method;
}

methodName = "builder";

JavaType.FullyQualified v2Client = SdkTypeUtils.v2ClientFromClientBuilder(fullyQualified);
J.Identifier id = new J.Identifier(
Tree.randomId(),
Space.EMPTY,
Markers.EMPTY,
Collections.emptyList(),
v2Client.getClassName(),
v2Client,
null
);

J.Identifier builderMethod = new J.Identifier(
Tree.randomId(),
Space.EMPTY,
Markers.EMPTY,
Collections.emptyList(),
methodName,
null,
null
);

JavaType.Method methodType = new JavaType.Method(
null,
0L,
v2Client,
methodName,
v2Client,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList()
);

J.MethodInvocation builderInvoke = new J.MethodInvocation(
Tree.randomId(),
Space.EMPTY,
Markers.EMPTY,
JRightPadded.build(id),
null,
builderMethod,
JContainer.empty(),
methodType
);

maybeRemoveImport(fullyQualified);
maybeAddImport(v2Client);
return builderInvoke;
}

private J.MethodInvocation renameAsyncBuilderToBuilder(J.MethodInvocation method, JavaType selectType) {
String methodName = method.getSimpleName();
JavaType.Method mt = method.getMethodType();
JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(selectType);

if (mt == null || fullyQualified == null) {
return method;
}

if ("asyncBuilder".equals(methodName)) {
methodName = "builder";
}

mt = mt.withName(methodName)
.withReturnType(selectType)
.withDeclaringType(fullyQualified);

method = method.withName(method.getName()
.withSimpleName(methodName)
.withType(mt))
.withMethodType(mt);
return method;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ recipeList:
- software.amazon.awssdk.UpgradeSdkDependencies
- software.amazon.awssdk.migration.recipe.ChangeSdkType
- software.amazon.awssdk.ChangeSdkCoreTypes
- software.amazon.awssdk.migration.recipe.V1BuilderVariationsToV2Builder
- software.amazon.awssdk.migration.recipe.NewClassToBuilderPattern
- software.amazon.awssdk.migration.recipe.NewClassToStaticFactory
- software.amazon.awssdk.migration.recipe.NewClassToStaticFactory

0 comments on commit 7a638af

Please sign in to comment.