

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 适用于 Java 的 AWS SDK 迁移工具
<a name="migration-tool"></a>

适用于 Java 的 AWS SDK 提供了一个迁移工具，可协助自动将适用于 Java 的 SDK 1.x（V1）代码迁移到 2.x（V2）。该工具使用 [OpenRewrite](https://docs.openrewrite.org/)（一个用于重构源代码的开源工具）来执行迁移。OpenRewrite 使用代码修改规则（称为“配方”）自动将源代码从 V1 更新为 V2 语法和模式。

该工具支持 SDK 服务客户端和 [S3 Transfer Manager](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/transfer/TransferManager.html) 高级库的代码修改规则。不支持其他高级别 API（例如 V1 的 [https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html) 到 V2 的 [DynamoDB 增强型客户端 API](dynamodb-enhanced-client.md)）的代码修改规则。

有关限制的更多详细信息，请参阅[本页末尾](#migration-tool-limitations)。有关使用手动迁移步骤的常见不受支持代码模式的详细示例，请参阅[不支持的代码模式](migration-tool-unsupported-patterns.md)。

## 使用迁移工具
<a name="migration-tool-use"></a>

### 迁移 Maven 项目
<a name="migration-tool-use-maven"></a>

按照以下说明，使用 [OpenRewrite Maven 插件](https://docs.openrewrite.org/reference/rewrite-maven-plugin)工具迁移基于 Maven 的适用于 Java 的 SDK 1.x 项目。

1. 如果需要，导航到 Maven 项目的根目录

   打开终端（命令行）窗口并导航到基于 Maven 的应用程序的根目录。

1. 运行插件的 `rewrite-maven-plugin` 命令

   您可以从两种模式（Maven 目标）中进行选择：`dryRun` 和 `run`。

   **`dryRun`**** 模式**

   在 `dryRun` 模式下，插件会在控制台输出中生成差异日志，并在 `target/rewrite` 文件夹中生成名为 `rewrite.patch` 的补丁文件。借助此模式，您可以预览将要进行的更改，因为这不会对源代码文件进行任何更改。

   以下示例说明如何在 `dryRun` 模式下调用插件。

   ```
   mvn org.openrewrite.maven:rewrite-maven-plugin:<rewrite-plugin-version>*:dryRun \
     -Drewrite.recipeArtifactCoordinates=software.amazon.awssdk:v2-migration:<sdkversion>** \
     -Drewrite.activeRecipes=software.amazon.awssdk.v2migration.AwsSdkJavaV1ToV2
   ```

   \$1将 *<rewrite-plugin-version>* 替换为您在此[测试文件](https://github.com/aws/aws-sdk-java-v2/blob/3a01289246f1f4ac814a354051d00030e53ef968/test/v2-migration-tests/src/test/java/software/amazon/awssdk/v2migrationtests/MavenTestBase.java#L54)中看到的 `rewriteMavenPluginVersion` 值。

   \$1\$1将 *<sdkversion>* 替换为 2.x SDK 版本。访问 [Maven Central](https://central.sonatype.com/artifact/software.amazon.awssdk/v2-migration) 以检查最新版本。
**重要**  
因为其他版本可能无法运行，请务必使用[测试文件](https://github.com/aws/aws-sdk-java-v2/blob/3a01289246f1f4ac814a354051d00030e53ef968/test/v2-migration-tests/src/test/java/software/amazon/awssdk/v2migrationtests/MavenTestBase.java#L54)中显示的 `rewrite-maven-plugin` 版本。

   `dryRun` 模式下的控制台输出应类似于以下输出。

   ```
   [WARNING] These recipes would make changes to project/src/test/resources/maven/before/pom.xml:
   [WARNING]     software.amazon.awssdk.v2migration.AwsSdkJavaV1ToV2
   [WARNING]         software.amazon.awssdk.v2migration.UpgradeSdkDependencies
   [WARNING]             org.openrewrite.java.dependencies.AddDependency: {groupId=software.amazon.awssdk, artifactId=apache-client, version=2.27.0, onlyIfUsing=com.amazonaws.ClientConfiguration}
   [WARNING]             org.openrewrite.java.dependencies.AddDependency: {groupId=software.amazon.awssdk, artifactId=netty-nio-client, version=2.27.0, onlyIfUsing=com.amazonaws.ClientConfiguration}
   [WARNING]             org.openrewrite.java.dependencies.ChangeDependency: {oldGroupId=com.amazonaws, oldArtifactId=aws-java-sdk-bom, newGroupId=software.amazon.awssdk, newArtifactId=bom, newVersion=2.27.0}
   [WARNING]             org.openrewrite.java.dependencies.ChangeDependency: {oldGroupId=com.amazonaws, oldArtifactId=aws-java-sdk-s3, newGroupId=software.amazon.awssdk, newArtifactId=s3, newVersion=2.27.0}
   [WARNING]             org.openrewrite.java.dependencies.ChangeDependency: {oldGroupId=com.amazonaws, oldArtifactId=aws-java-sdk-sqs, newGroupId=software.amazon.awssdk, newArtifactId=sqs, newVersion=2.27.0}
   [WARNING] These recipes would make changes to project/src/test/resources/maven/before/src/main/java/foo/bar/Application.java:
   [WARNING]     software.amazon.awssdk.v2migration.AwsSdkJavaV1ToV2
   [WARNING]         software.amazon.awssdk.v2migration.S3GetObjectConstructorToFluent
   [WARNING]             software.amazon.awssdk.v2migration.ConstructorToFluent
   [WARNING]         software.amazon.awssdk.v2migration.S3StreamingResponseToV2
   [WARNING]         software.amazon.awssdk.v2migration.ChangeSdkType
   [WARNING]         software.amazon.awssdk.v2migration.ChangeSdkCoreTypes
   [WARNING]             software.amazon.awssdk.v2migration.ChangeExceptionTypes
   [WARNING]                 org.openrewrite.java.ChangeType: {oldFullyQualifiedTypeName=com.amazonaws.AmazonClientException, newFullyQualifiedTypeName=software.amazon.awssdk.core.exception.SdkException}
   [WARNING]                 org.openrewrite.java.ChangeMethodName: {methodPattern=com.amazonaws.AmazonServiceException getRequestId(), newMethodName=requestId}
   [WARNING]                 org.openrewrite.java.ChangeMethodName: {methodPattern=com.amazonaws.AmazonServiceException getErrorCode(), newMethodName=awsErrorDetails().errorCode}
   [WARNING]                 org.openrewrite.java.ChangeMethodName: {methodPattern=com.amazonaws.AmazonServiceException getServiceName(), newMethodName=awsErrorDetails().serviceName}
   [WARNING]                 org.openrewrite.java.ChangeMethodName: {methodPattern=com.amazonaws.AmazonServiceException getErrorMessage(), newMethodName=awsErrorDetails().errorMessage}
   [WARNING]                 org.openrewrite.java.ChangeMethodName: {methodPattern=com.amazonaws.AmazonServiceException getRawResponse(), newMethodName=awsErrorDetails().rawResponse().asByteArray}
   [WARNING]                 org.openrewrite.java.ChangeMethodName: {methodPattern=com.amazonaws.AmazonServiceException getRawResponseContent(), newMethodName=awsErrorDetails().rawResponse().asUtf8String}
   [WARNING]                 org.openrewrite.java.ChangeType: {oldFullyQualifiedTypeName=com.amazonaws.AmazonServiceException, newFullyQualifiedTypeName=software.amazon.awssdk.awscore.exception.AwsServiceException}
   [WARNING]         software.amazon.awssdk.v2migration.NewClassToBuilderPattern
   [WARNING]             software.amazon.awssdk.v2migration.NewClassToBuilder
   [WARNING]             software.amazon.awssdk.v2migration.V1SetterToV2
   [WARNING]         software.amazon.awssdk.v2migration.V1GetterToV2
   ...
   [WARNING]         software.amazon.awssdk.v2migration.V1BuilderVariationsToV2Builder
   [WARNING]         software.amazon.awssdk.v2migration.NewClassToBuilderPattern
   [WARNING]             software.amazon.awssdk.v2migration.NewClassToBuilder
   [WARNING]             software.amazon.awssdk.v2migration.V1SetterToV2
   [WARNING]         software.amazon.awssdk.v2migration.HttpSettingsToHttpClient
   [WARNING]         software.amazon.awssdk.v2migration.WrapSdkClientBuilderRegionStr
   [WARNING] Patch file available:
   [WARNING]     project/src/test/resources/maven/before/target/rewrite/rewrite.patch
   [WARNING] Estimate time saved: 20m
   [WARNING] Run 'mvn rewrite:run' to apply the recipes.
   ```

   **`run`**** 模式**

   当您在 `run` 模式下运行插件时，它会修改磁盘上的源代码以应用更改。运行命令之前，确保您有源代码的备份。

   以下示例说明如何在 `run` 模式下调用插件。

   ```
   mvn org.openrewrite.maven:rewrite-maven-plugin:<rewrite-plugin-version>*:run \
     -Drewrite.recipeArtifactCoordinates=software.amazon.awssdk:v2-migration:<sdkversion>** \
     -Drewrite.activeRecipes=software.amazon.awssdk.v2migration.AwsSdkJavaV1ToV2
   ```

   \$1将 *<rewrite-plugin-version>* 替换为您在此[测试文件](https://github.com/aws/aws-sdk-java-v2/blob/3a01289246f1f4ac814a354051d00030e53ef968/test/v2-migration-tests/src/test/java/software/amazon/awssdk/v2migrationtests/MavenTestBase.java#L54)中看到的 `rewriteMavenPluginVersionvalue`。

   \$1\$1将 *<sdkversion>* 替换为 2.x SDK 版本。访问 [Maven Central](https://central.sonatype.com/artifact/software.amazon.awssdk/v2-migration) 以检查最新版本。

   运行命令后，编译应用程序并运行测试以验证更改。

### 迁移 Gradle 项目
<a name="migration-tool-use-gradle"></a>

按照以下说明，使用 [OpenRewrite Gradle 插件](https://docs.openrewrite.org/reference/gradle-plugin-configuration)工具迁移基于 Gradle 的适用于 Java 的 SDK 1.x 项目。

1. 如果需要，导航到 Gradle 项目的根目录

   打开终端（命令行）窗口并导航到基于 Gradle 的应用程序的根目录。

1. 创建 Gradle 初始化脚本

   在目录中创建一个包含以下内容的 `init.gradle` 文件。

   ```
   initscript {
       repositories {
           maven { url "https://plugins.gradle.org/m2" }
       }
       dependencies {
           classpath("org.openrewrite:plugin:<rewrite-plugin-version>*")
       }
   }
   
   rootProject {
       plugins.apply(org.openrewrite.gradle.RewritePlugin)
       dependencies {
           rewrite("software.amazon.awssdk:v2-migration:latest.release")
       }
   
       afterEvaluate {
           if (repositories.isEmpty()) {
               repositories {
                   mavenCentral()
               }
           }
       }
   }
   ```

   \$1将 *<rewrite-plugin-version>* 替换为您在此[测试文件](https://github.com/aws/aws-sdk-java-v2/blob/master/test/v2-migration-tests/src/test/resources/software/amazon/awssdk/v2migrationtests/gradle/before/init.gradle#L6)中看到的版本。

1. 运行 `rewrite` 命令

   与 Maven 插件一样，您可以在 `dryRun` 或 `run` 模式下运行 Gradle 插件。

   **`dryRun` 模式**

   以下示例说明如何在 `dryRun` 模式下调用插件。

   ```
   gradle rewriteDryRun --init-script init.gradle \
     -Drewrite.activeRecipes=software.amazon.awssdk.v2migration.AwsSdkJavaV1ToV2
   ```

   **`run` 模式**

   以下示例说明如何在 `run` 模式下调用插件。

   ```
   gradle rewriteRun --init-script init.gradle \
     -Drewrite.activeRecipes=software.amazon.awssdk.v2migration.AwsSdkJavaV1ToV2
   ```

## 目前的局限性
<a name="migration-tool-limitations"></a>

虽然通过更新到 V2 等效项的代码修改规则可让迁移支持大多数 V1 代码，但有些类和方法并未包括在内。对于这些类和方法，请按照[分步说明](migration-steps.md)手动迁移代码。

对于某些不支持的代码修改规则，迁移工具可能会添加以下内容开头的注释：

```
/*AWS SDK for Java v2 migration: Transform for ...
```

在注释之后，该工具会输出方法或类的 V2 版本的通用存根。例如，在以下输出中，迁移工具尝试迁移 V1 S3 客户端的 `setBucketLifecycleConfiguration` 方法：

```
/*AWS SDK for Java v2 migration: Transform for setBucketLifecycleConfiguration method not supported. 
Please manually migrate your code by using builder pattern, update from BucketLifecycleConfiguration.Rule 
to LifecycleRule, StorageClass to TransitionStorageClass, and adjust imports and names.*/
s3.putBucketLifecycleConfiguration(
        PutBucketLifecycleConfigurationRequest.builder()
            .bucket(bucketName)
            .lifecycleConfiguration(BucketLifecycleConfiguration.builder()
                .build())
            .build());
```

以下列表中的链接可带您前往查看迁移信息，以帮助您手动迁移代码。
+ [版本 1 和版本 2 之间的 S3 客户端区别 适用于 Java 的 AWS SDK](migration-s3-client.md)
+ [S3 Transfer Manager](migration-s3-transfer-manager.md)（TransferManager）
+ [DynamoDB 对象映射](migration-ddb-mapper.md)（DynamoDBMapper）
+ [EC2 元数据实用程序](migration-imds.md)（EC2MetadataUtils）
+ [Waiter](migration-waiters.md)（AmazonDynamoDBWaiters）
+ [IAM 策略生成器](migration-iam-policy-builder.md)（策略）
+ [CloudFront 预签名](migration-cloudfront-presigning.md)（CloudFrontUrlSigner、CloudFrontCookieSigner）
+ [S3 事件通知](migration-s3-event-notification.md)（S3EventNotification）
+ SDK 指标发布（[1.x 文档](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/generating-sdk-metrics.html)、[2.x](metrics.md) 文档）
+ [不支持的代码模式](migration-tool-unsupported-patterns.md) - 需要手动迁移的常见代码模式的详细示例

# 迁移工具不支持的代码模式
<a name="migration-tool-unsupported-patterns"></a>

迁移工具会自动将大多数 v1 代码转换为 v2。但是，某些代码模式需要手动迁移。本主题提供了最常见不受支持模式的详细示例，并向您展示了如何手动转换这些模式。

以下模式列表并非详尽内容。如果运行迁移工具后您的代码无法编译，请按照[step-by-step迁移说明](migration-steps.md)手动迁移剩余的 v1 代码。

## 带参数的请求对象构造函数
<a name="request-pojo-constructors"></a>

对于请求 POJOs （不包括 Amazon S3），迁移工具仅转换设置器方法。该工具不支持带参数的构造函数。

**支持的模式：使用 setter 请求对象（没有构造函数参数）**

之前（原始 v1 代码）：

```
import com.amazonaws.services.sqs.model.SendMessageRequest;

SendMessageRequest request = new SendMessageRequest().withMessageBody("Hello World");
request.setQueueUrl("https://sqs.us-west-2.amazonaws.com/0123456789012/demo-queue");
```

之后（迁移工具结果）：

```
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;

SendMessageRequest request = SendMessageRequest.builder()
    .messageBody("Hello World").build();
request = request.toBuilder()
    .queueUrl("https://sqs.us-west-2.amazonaws.com/0123456789012/demo-queue").build();
```

**不支持的模式：带参数的请求对象构造函数**

迁移工具无法转换带参数的构造函数：

在手动迁移之前，但在使用迁移工具之后：

```
import software.amazon.awssdk.services.sqs.model.SendMessageRequest; // Import updated to v2.

// This pattern requires manual migration.
SendMessageRequest request = new SendMessageRequest(
    "https://sqs.us-west-2.amazonaws.com/0123456789012/demo-queue", 
    "Hello World");
```

迁移工具将导入转换为 v2，但构造函数代码保持不变，需要手动更新才能使用生成器模式。

手动迁移后：

```
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;

SendMessageRequest request = SendMessageRequest.builder()
    .messageBody("Hello World")
    .queueUrl("https://sqs.us-west-2.amazonaws.com/0123456789012/demo-queue")
    .build();
```

## 带有单独参数的服务客户端方法
<a name="service-client-method-overloads"></a>

迁移工具无法转换采用单个参数而非请求对象（不包括 Amazon S3）的服务客户端方法。

之前（v1 代码）：

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClient;

AmazonSQS sqs = new AmazonSQSClient();
// The following v1 method takes individual parameters.
sqs.sendMessage("https://sqs.us-west-2.amazonaws.com/0123456789012/demo-queue", "Hello World");
```

之后（迁移工具结果，不编译）：

```
import software.amazon.awssdk.services.sqs.SqsClient;  // Import updated to v2.
// No import statement for the v2 request POJO.

SqsClient sqs = SqsClient.builder().build();

// Does not compile–v2 methods only accept request POJOs.
sqs.sendMessage("https://sqs.us-west-2.amazonaws.com/0123456789012/demo-queue", "Hello World");
```

您必须手动更新方法参数才能使用请求对象：

```
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.SendMessageRequest; // Add manually.

SqsClient sqs = SqsClient.builder().build();

// Corrected v2 code.
SendMessageRequest request = SendMessageRequest.builder()
    .queueUrl("https://sqs.us-west-2.amazonaws.com/0123456789012/demo-queue")
    .messageBody("Hello World")
    .build();
sqs.sendMessage(request);
```

## 请求超时方法
<a name="request-pojo-timeout-configuration"></a>

迁移工具不会转换对请求对象设置超时的方法。

之前（v1 代码）：

```
import com.amazonaws.services.sqs.model.SendMessageRequest;

SendMessageRequest request = new SendMessageRequest();
request.setSdkRequestTimeout(7);
```

之后（迁移工具结果，不编译）：

```
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;  // Import updated to v2.

SendMessageRequest request = SendMessageRequest.builder().build();

// Does not compile.
request.setSdkRequestTimeout(7);
```

您必须手动迁移才能使用 v2 的 `overrideConfiguration` 方法：

```
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;
import java.time.Duration;

SendMessageRequest request = SendMessageRequest.builder().build();

// Corrected v2 code.
request = request.toBuilder()
    .overrideConfiguration(o -> o.apiCallTimeout(Duration.ofSeconds(7)))
    .build();
```

## 带参数的服务客户端构造函数
<a name="service-client-constructors-with-args"></a>

迁移工具转换空的服务客户端构造函数，但无法转换接受凭证或配置等参数的构造函数。

之前（v1 代码）：

```
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClient;

AWSCredentials awsCredentials = new BasicAWSCredentials("akid", "skid");
AmazonSQS sqs = new AmazonSQSClient(awsCredentials);
```

之后（迁移工具结果，不编译）：

```
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.services.sqs.SqsClient;  // Import updated to v2.

AwsCredentials awsCredentials = AwsBasicCredentials.create("akid", "skid");

// Does not compile.
SqsClient sqs = new SqsClient(awsCredentials);
```

必须手动更新服务客户端构造函数才能使用生成器模式：

```
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;  // Add manually.
import software.amazon.awssdk.services.sqs.SqsClient;

AwsCredentials awsCredentials = AwsBasicCredentials.create("akid", "skid");

// Corrected v2 code.
SqsClient sqs = SqsClient.builder()
    .credentialsProvider(StaticCredentialsProvider.create(awsCredentials))
    .build();
```