

# How to migrate your code from AWS SDK for Java 1.x to 2.x
<a name="migration-howto"></a>

You can migrate your existing SDK for Java 1.x applications in a couple ways.

1. Automated approach by using the [migration tool](migration-tool.md).

1. [Manual approach](migration-steps.md) by incrementally replacing 1.x imports with 2.x imports.

We recommend that you start by using the migration tool. It automates much of the routine, replacement work from 1.x to 2.x code. 

Since the tool [doesn't migrate all features](migration-tool.md#migration-tool-limitations), you'll need to search for remaining v1 code after running the tool. When you find code that the tool didn't migrate, follow the [step-by-step instructions](migration-steps.md) (manual approach) and use the [migration guide articles](migration-whats-different.md) to finish the migration.

**Topics**
+ [Migration tool](migration-tool.md)
+ [Step-by-step instructions](migration-steps.md)

# AWS SDK for Java migration tool
<a name="migration-tool"></a>

The AWS SDK for Java provides a migration tool that helps automate the migration of SDK for Java 1.x (V1) code to 2.x (V2). The tool uses [OpenRewrite](https://docs.openrewrite.org/)—an open source, source code refactoring tool—to perform the migration. OpenRewrite uses code modification rules (called "recipes") to automatically update your source code from V1 to V2 syntax and patterns.

The tool supports code modification rules for SDK service clients and the [S3 Transfer Manager](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/transfer/TransferManager.html) high-level library. Code modification rules for other high-level APIs such as V1's [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) to V2's [DynamoDB Enhanced Client API](dynamodb-enhanced-client.md) are not supported. 

For more details on limitations, see the [end of this page](#migration-tool-limitations). For detailed examples of common unsupported code patterns with manual migration steps, see [Unsupported code patterns](migration-tool-unsupported-patterns.md).

## Use the migration tool
<a name="migration-tool-use"></a>

### Migrate a Maven project
<a name="migration-tool-use-maven"></a>

Follow the instructions below to migrate your SDK for Java 1.x Maven-based project by using the [OpenRewrite Maven plugin](https://docs.openrewrite.org/reference/rewrite-maven-plugin) tool.

1. Navigate to your Maven project's root directory

   Open a terminal (command line) window and navigate to the root directory of your Maven-based application.

1. Run the plugin's `rewrite-maven-plugin` command

   You can choose from two modes (Maven goals): `dryRun` and `run`.

   **`dryRun`**** mode**

   In the `dryRun` mode, the plugin generates diff logs in the console output and a patch file named `rewrite.patch` in the `target/rewrite` folder. This mode allows you to preview the changes that would be made, since no changes are made to source code files. 

   The following example show how to invoke the plugin in `dryRun` mode.

   ```
   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
   ```

   \$1Replace *<rewrite-plugin-version>* with the `rewriteMavenPluginVersion` value that you see in this [test file](https://github.com/aws/aws-sdk-java-v2/blob/3a01289246f1f4ac814a354051d00030e53ef968/test/v2-migration-tests/src/test/java/software/amazon/awssdk/v2migrationtests/MavenTestBase.java#L54).

   \$1\$1Replace *<sdkversion>* with a 2.x SDK version. Visit [Maven Central](https://central.sonatype.com/artifact/software.amazon.awssdk/v2-migration) to check for the latest version. 
**Important**  
Be sure to use the version of the `rewrite-maven-plugin` shown in the [test file](https://github.com/aws/aws-sdk-java-v2/blob/3a01289246f1f4ac814a354051d00030e53ef968/test/v2-migration-tests/src/test/java/software/amazon/awssdk/v2migrationtests/MavenTestBase.java#L54) because other versions may not work.

   Your console output from the `dryRun` mode should resemble the following output.

   ```
   [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`**** mode**

   When you run the plugin in `run` mode, it modifies the source code on disk to apply the changes. Make sure you have a backup of the source code before running the command.

   The following example show how to invoke the plugin in `run` mode.

   ```
   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
   ```

   \$1Replace *<rewrite-plugin-version>* with the `rewriteMavenPluginVersionvalue` that you see in this [test file](https://github.com/aws/aws-sdk-java-v2/blob/3a01289246f1f4ac814a354051d00030e53ef968/test/v2-migration-tests/src/test/java/software/amazon/awssdk/v2migrationtests/MavenTestBase.java#L54).

   \$1\$1Replace *<sdkversion>* with a 2.x SDK version. Visit [Maven Central](https://central.sonatype.com/artifact/software.amazon.awssdk/v2-migration) to check for the latest version. 

   After you run the command, compile your application and run tests to verify the changes. 

### Migrate a Gradle project
<a name="migration-tool-use-gradle"></a>

Follow the instructions below to migrate your SDK for Java 1.x Gradle-based project by using the [OpenRewrite Gradle plugin](https://docs.openrewrite.org/reference/gradle-plugin-configuration) tool.

1. Navigate to your Gradle project's root directory

   Open a terminal (command line) window and navigate to the root directory of your Gradle-based application.

1. Create a Gradle init script

   Create a `init.gradle` file with the following content in the directory.

   ```
   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()
               }
           }
       }
   }
   ```

   \$1Replace *<rewrite-plugin-version>* with the version that you see in this [test file](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. Run the `rewrite` command

   As with the Maven plugin, you can run the Gradle plugin in `dryRun` or `run` mode.

   **`dryRun` mode**

   The following example show how to invoke the plugin in `dryRun` mode.

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

   **`run` mode**

   The following example show how to invoke the plugin in `run` mode.

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

## Current limitations
<a name="migration-tool-limitations"></a>

While the migration upports most V1 code through code modification rules that update to the V2 equivalent, some classes and methods aren't covered. For these classes and methods, follow the [step-by-step instructions](migration-steps.md) to manually migrate your code.

For some unsupported code modification rules, the migration tool may add a comment that begins with:

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

Following the comment, the tool outputs a generic stub of the V2 version of the method or class. For example, in the following output, the migration tool attempted to migrate the V1 S3 client's `setBucketLifecycleConfiguration` method:

```
/*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());
```

The links in the list below, take you to migration information to help you manually migrate the code.
+ [S3 client differences between version 1 and version 2 of the AWS SDK for Java](migration-s3-client.md)
+ [S3 Transfer Manager](migration-s3-transfer-manager.md) (TransferManager)
+ [DynamoDB object mapping](migration-ddb-mapper.md) (DynamoDBMapper)
+ [EC2 metadata utility](migration-imds.md) (EC2MetadataUtils)
+ [Waiters](migration-waiters.md) (AmazonDynamoDBWaiters)
+ [IAM Policy Builder](migration-iam-policy-builder.md) (Policy)
+ [CloudFront presigning](migration-cloudfront-presigning.md) (CloudFrontUrlSigner, CloudFrontCookieSigner)
+ [S3 Event Notifications](migration-s3-event-notification.md) (S3EventNotification)
+ SDK metric publishing ([1.x documentation](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/generating-sdk-metrics.html), [2.x documentation](metrics.md))
+ [Unsupported code patterns](migration-tool-unsupported-patterns.md)–Detailed examples of common code patterns that require manual migration

# Unsupported code patterns of the migration tool
<a name="migration-tool-unsupported-patterns"></a>

The migration tool automatically converts most v1 code to v2. However, some code patterns require manual migration. This topic provides detailed examples of the most common unsupported patterns and shows you how to manually convert them.

The following list of patterns is not exhaustive. If your code doesn't compile after running the migration tool, follow the [step-by-step migration instructions](migration-steps.md) to manually migrate the remaining v1 code.

## Request object constructors with parameters
<a name="request-pojo-constructors"></a>

For request POJOs (excluding Amazon S3), the migration tool transforms only setter methods. The tool does not support constructors with parameters.

**Supported pattern: Request object using setters (no constructor parameters)**

Before (original v1 code):

```
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");
```

After (migration tool result):

```
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();
```

**Unsupported pattern: Request object constructor with parameters**

The migration tool cannot convert constructors with parameters:

Before manual migration, but after migration tool:

```
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");
```

The migration tool transforms the import to v2, but the constructor code remains unchanged and requires manual updates to use the builder pattern.

After manual migration:

```
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();
```

## Service client methods with individual parameters
<a name="service-client-method-overloads"></a>

The migration tool cannot convert service client methods that take individual parameters instead of request objects (excluding Amazon S3).

Before (v1 code):

```
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");
```

After (migration tool result–does not compile):

```
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");
```

You must manually update the method arguments to use a request object:

```
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);
```

## Request timeout methods
<a name="request-pojo-timeout-configuration"></a>

The migration tool does not convert methods that set timeouts on request objects.

Before (v1 code):

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

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

After (migration tool result–does not compile):

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

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

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

You must manually migrate to use v2's `overrideConfiguration` method:

```
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();
```

## Service client constructors with parameters
<a name="service-client-constructors-with-args"></a>

The migration tool converts empty service client constructors but cannot convert constructors that accept parameters like credentials or configuration.

Before (v1 code):

```
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);
```

After (migration tool result–does not compile):

```
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);
```

You must manually update the service client constructor to use the builder pattern:

```
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();
```

# Migration step-by-step instructions with example
<a name="migration-steps"></a>

This section provides a step-by-step guide to migrate your application that currently uses the SDK for Java v1.x to the SDK for Java 2.x. The first part presents an overview of the steps followed by a detailed example of a migration.

The steps that are covered here describe a migration of a normal use case, where the application calls AWS services using model-driven service clients. If you need to migrate code that uses higher level APIs such as [S3 Transfer Manager](migration-s3-transfer-manager.md) or [CloudFront presigning](migration-cloudfront-presigning.md), refer to the section under [What's different between the AWS SDK for Java 1.x and 2.x](migration-whats-different.md) table of contents.



The approach described here is a suggestion. You may use other techniques and leverage your IDE's code editing features to reach the same result. 

## Overview of steps
<a name="migration-steps-overview"></a>

### 1. Begin by adding the SDK for Java 2.x BOM
<a name="migration-steps-overview-step1"></a>

By adding the Maven BOM (Bill of Materials) element for the SDK for Java 2.x to your POM file, you ensure that all of the v2 dependency you need are from the same version. Your POM can contain both v1 and v2 dependencies. This allows you to incrementally migrate your code rather than change it all at once.

#### SDK for Java 2.x BOM
<a name="drt_b5n_q1c"></a>

```
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>bom</artifactId>
      <version>2.27.21</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
```

You can find the [latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom) on the Maven Central Repository.

### 2. Search files for v1 class import statements
<a name="migration-steps-overview-step2"></a>

By scanning the files in your application for SERVICE\$1IDs used in v1 imports, you'll find the unique SERVICE\$1IDs used. A SERVICE\$1ID is a short, unique name for an AWS service. For example `cognitoidentity` is the SERVICE\$1ID for Amazon Cognito Identity.

### 3. Determine the v2 Maven dependencies from the v1 import statements
<a name="migration-steps-overview-step3"></a>

After you find all unique v1 SERVICE\$1IDs, you can determine the corresponding Maven artifact for the v2 dependency by referring to [Package name to Maven artifactId mappings](#migration-serviceid-artifactid-mapping).

### 4. Add v2 dependency elements to the POM file
<a name="migration-steps-overview-step4"></a>

Update the Maven POM file with dependency elements determined in step 3.

### 5. In the Java files, incrementally change over the v1 classes to v2 classes
<a name="migration-steps-overview-step5"></a>

As you replace v1 classes with v2 classes, make the necessary changes to support the v2 API such as using builders instead of constructors and using fluent getters and setters.

### 6. Remove v1 Maven dependencies from the POM and v1 imports from files
<a name="migration-steps-overview-step6"></a>

After you migrate your code to use v2 classes, remove any leftover v1 imports from files and all dependencies from your build file.

### 7. Refactor the code to use v2 API enhancements
<a name="migration-steps-overview-step7"></a>

After the code successfully compiles and passes tests, you can take advantage of v2 enhancements such as using a different HTTP client or paginators to simplify code. This is an optional step.

## Example migration
<a name="migration-steps-example"></a>

In this example, we migrate an application that uses the SDK for Java v1 and accesses several AWS services. We work through the following v1 method in detail in step 5. This is one method in a class that contains eight methods and there are 32 classes in the application.

### v1 method to migrate
<a name="v1-snippet-collapsed"></a>

Only the v1 SDK imports are listed below from the Java file.

```
import com.amazonaws.ClientConfiguration;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.RegionUtils;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.AmazonEC2Exception;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.InstanceStateName;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
...
private static List<Instance> getRunningInstances(AmazonEC2Client ec2, List<String> instanceIds) {
    List<Instance> runningInstances = new ArrayList<>();
    try {
        DescribeInstancesRequest request = new DescribeInstancesRequest()
                .withInstanceIds(instanceIds);
        DescribeInstancesResult result;
        do {
            // DescribeInstancesResponse is a paginated response, so use tokens with multiple requests.
            result = ec2.describeInstances(request);
            request.setNextToken(result.getNextToken());   // Prepare request for next page.
            for (final Reservation r : result.getReservations()) {
                for (final Instance instance : r.getInstances()) {
                    LOGGER.info("Examining instanceId: "+ instance.getInstanceId());
                    // if instance is in a running state, add it to runningInstances list.
                    if (RUNNING_STATES.contains(instance.getState().getName())) {
                        runningInstances.add(instance);
                    }
                }
            }
        } while (result.getNextToken() != null);
    } catch (final AmazonEC2Exception exception) {
        // if instance isn't found, assume its terminated and continue.
        if (exception.getErrorCode().equals(NOT_FOUND_ERROR_CODE)) {
            LOGGER.info("Instance probably terminated; moving on.");
        } else {
            throw exception;
        }
    }
    return runningInstances;
}
```

### 1. Add v2 Maven BOM
<a name="migration-steps-example-step1"></a>

Add the Maven BOM for the SDK for Java 2.x to the POM along side any other dependencies in the `dependencyManagement` section. If your POM file has the BOM for v1 of the SDK, leave it for now. It will be removed at a later step.

#### POM Dependency management at outset
<a name="migration-example-boms"></a>

```
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.example</groupId>             <!--Existing dependency in POM. -->
      <artifactId>bom</artifactId>
      <version>1.3.4</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    ...
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk-bom</artifactId>  <!--Existing v1 BOM dependency. -->
      <version>1.11.1000</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    ...
    <dependency>
      <groupId>software.amazon.awssdk</groupId>  <!--Add v2 BOM dependency. -->
      <artifactId>bom</artifactId>
      <version>2.27.21</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
```

### 2. Search files for v1 class import statements
<a name="migration-steps-example-step2"></a>

Search the application's code for unique occurrences of `import com.amazonaws.services`. This helps us determine the v1 dependencies used by the project. If your application has a Maven POM file with v1 dependencies listed, you can use this information instead. 

For this example we use the [`ripgrep` (rg)](https://github.com/BurntSushi/ripgrep) command to search the code base.

From the root of your code base, execute the following `ripgrep` command. After `ripgrep` finds the import statements, they are piped to the `cut`, `sort`, and `uniq` commands to isolate the SERVICE\$1IDs. 

```
rg --no-filename 'import\s+com\.amazonaws\.services' | cut -d '.' -f 4 | sort | uniq
```

For this application, the following SERVICE\$1IDs are logged to the console.

```
autoscaling
cloudformation
ec2
identitymanagement
```

This indicates that there was at least one occurrence of each of the following package names used in `import` statements. For our purposes, the individual class names don't matter. We just need to find the SERVICE\$1IDs that are used.

```
com.amazonaws.services.autoscaling.*
com.amazonaws.services.cloudformation.*
com.amazonaws.services.ec2.*
com.amazonaws.services.identitymanagement.*
```

### 3. Determine the v2 Maven dependencies from the v1 import statements
<a name="migration-steps-example-step3"></a>

The SERVICE\$1IDs for v1 that we isolated from Step 2—for example `autoscaling` and `cloudformation`—can be mapped to the same v2 SERVICE\$1ID for the most part. Since the v2 Maven artifactId matches the SERVICE\$1ID in most cases, you have the information you need to add dependency blocks to your POM file.

The following table shows how we can determine the v2 dependencies.


| v1 SERVICE\$1ID maps to ...package name | v2 SERVICE\$1ID maps to ...package name | v2 Maven dependency | 
| --- | --- | --- | 
|  **ec2** `com.amazonaws.services.ec2.*`  |  **ec2** `software.amazon.awssdk.services.ec2.*`  |  <pre><dependency><br />  <groupId>software.amazon.awssdk</groupId><br />  <artifactId>ec2</artifactId><br /></dependency></pre>  | 
|  **autoscaling** `com.amazonaws.services.autoscaling.*`  |  **autoscaling** `software.amazon.awssdk.services.autoscaling.*`  |  <pre><dependency><br />  <groupId>software.amazon.awssdk</groupId><br />  <artifactId>autoscaling</artifactId><br /></dependency></pre>  | 
| cloudformation`com.amazonaws.services.cloudformation.*` | cloudformation`software.amazon.awssdk.cloudformation.*` |  <pre><dependency><br />  <groupId>software.amazon.awssdk</groupId><br />  <artifactId>cloudformation</artifactId><br /></dependency></pre>  | 
| identitymanagement\$1`com.amazonaws.services.identitymanagement.*` | iam\$1`software.amazon.awssdk.iam.*` |  <pre><dependency><br />  <groupId>software.amazon.awssdk</groupId><br />  <artifactId>iam</artifactId><br /></dependency></pre>  | 

\$1 The `identitymanagement` to `iam` mapping is an exception where the SERVICE\$1ID differs between versions. Refer to the [Package name to Maven artifactId mappings](#migration-serviceid-artifactid-mapping) for exceptions if Maven or Gradle cannot resolve the v2 dependency.

### 4. Add v2 dependency elements to the POM file
<a name="migration-steps-example-step4"></a>

In step 3, we determined the four dependency blocks that need to be added to the POM file. We don't need to add a version because we have specified the BOM in step 1. After the imports are added, our POM file has the following dependency elements.

```
    ...
  <dependencies>
    ...
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>autoscaling</artifactId>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>iam</artifactId>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>cloudformation</artifactId>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>ec2</artifactId>
    </dependency>
    ...
  </dependencies>
    ...
```

### 5. In the Java files, incrementally change over the v1 classes to v2 classes
<a name="migration-steps-example-step5"></a>

In the method that we are migrating, we see
+ An EC2 service client from `com.amazonaws.services.ec2.AmazonEC2Client`.
+ Several EC2 model classes used. For example `DescribeInstancesRequest` and `DescribeInstancesResult`.

```
import com.amazonaws.ClientConfiguration;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.RegionUtils;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.AmazonEC2Exception;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.InstanceStateName;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
...
private static List<Instance> getRunningInstances(AmazonEC2Client ec2, List<String> instanceIds)
    List<Instance> runningInstances = new ArrayList<>();
    try {
        DescribeInstancesRequest request = new DescribeInstancesRequest()
                .withInstanceIds(instanceIds);
        DescribeInstancesResult result;
        do {
            // DescribeInstancesResponse is a paginated response, so use tokens with multiple re
            result = ec2.describeInstances(request);
            request.setNextToken(result.getNextToken());   // Prepare request for next page.
            for (final Reservation r : result.getReservations()) {
                for (final Instance instance : r.getInstances()) {
                    LOGGER.info("Examining instanceId: "+ instance.getInstanceId());
                    // if instance is in a running state, add it to runningInstances list.
                    if (RUNNING_STATES.contains(instance.getState().getName())) {
                        runningInstances.add(instance);
                    }
                }
            }
        } while (result.getNextToken() != null);
    } catch (final AmazonEC2Exception exception) {
        // if instance isn't found, assume its terminated and continue.
        if (exception.getErrorCode().equals(NOT_FOUND_ERROR_CODE)) {
            LOGGER.info("Instance probably terminated; moving on.");
        } else {
            throw exception;
        }
    }
    return runningInstances;
}
...
```

Our goal is to replace all v1 imports with v2 imports. We proceed one class at a time.

#### a. Replace import statement or class name
<a name="migration-example-step5-substep1"></a>

We see that the first parameter to the `describeRunningInstances` method is a v1 `AmazonEC2Client` instance. Do one of the following:
+ Replace the import for `com.amazonaws.services.ec2.AmazonEC2Client` with `software.amazon.awssdk.services.ec2.Ec2Client` and change `AmazonEC2Client` to `Ec2Client`.
+ Change the parameter type to `Ec2Client` and let the IDE prompt us for the correct import. Our IDE will prompt us to import the v2 class because the client names differ—`AmazonEC2Client` and `Ec2Client`. This approach does not work if the class name is the same in both versions.

#### b. Replace v1 model classes with v2 equivalents
<a name="migration-example-step5-substep2"></a>

After the change to the v2 `Ec2Client`, if we use an IDE, we see compilation errors in the following statement.

```
                    result = ec2.describeInstances(request);
```

The compilation error results from using an instance of v1's `DescribeInstancesRequest` as a parameter to the v2 `Ec2Client` `describeInstances` method. To fix, make the following replacement or import statements.


| replace | with | 
| --- | --- | 
|  <pre>import com.amazonaws.services.ec2.model.DescribeInstancesRequest</pre>  |  <pre>import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest</pre>  | 

#### c. Change v1 constructors to v2 builders.
<a name="migration-example-step5-substep3"></a>

We still see compilation errors because there are [no constructors on v2 classes](migration-whats-different.md#immutable-classes). To fix, make the following change.


| change | to | 
| --- | --- | 
|  <pre>final DescribeInstancesRequest request = new DescribeInstancesRequest()<br />        .withInstanceIds(instanceIdsCopy);</pre>  |  <pre>final DescribeInstancesRequest request = DescribeInstancesRequest.builder()<br />        .instanceIds(instanceIdsCopy)<br />        .build();</pre>  | 

#### d. Replace v1 `*Result` response objects with v2 `*Response` equivalents
<a name="migration-example-step5-substep4"></a>

A consistent difference between v1 and v2 is that all [response objects in v2 end with `*Response` instead of `*Result`](migration-whats-different.md#model-classname-changes). Replace the v1 `DescribeInstancesResult` import to the v2 import, `DescribeInstancesResponse`.

#### d. Make API changes
<a name="migration-example-step5-substep5"></a>

The following statement needs a few changes.

```
request.setNextToken(result.getNextToken());
```

In v2, [setter methods](migration-whats-different.md#setter-getter-methods) do not use the `set` or with `prefix`. Getter methods prefixed with `get` are also gone in the SDK for Java 2.x

Model classes, such as the `request` instance, are immutable in v2, so we need to create a new `DescribeInstancesRequest` with a builder.

In v2, the statement becomes the following.

```
request = DescribeInstancesRequest.builder()
        .nextToken(result.nextToken())
        .build();
```

#### d. Repeat until method compiles with v2 classes
<a name="migration-example-step5-substep6"></a>

Continue with the rest of the code. Replace v1 imports with v2 imports and fix the compilation errors. Refer to the [v2 API Reference](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/ec2/package-summary.html) and [What's different reference](migration-whats-different.md) as needed.

After we migrate this single method, we have the following v2 code.

```
import com.amazonaws.ClientConfiguration;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.RegionUtils;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.AmazonEC2Exception;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.InstanceStateName;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;

import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse;
import software.amazon.awssdk.services.ec2.model.Ec2Exception;
import software.amazon.awssdk.services.ec2.model.Instance;
import software.amazon.awssdk.services.ec2.model.Reservation;
...
private static List<Instance> getRunningInstances(Ec2Client ec2, List<String> instanceIds) {
    List<Instance> runningInstances = new ArrayList<>();
        try {
            DescribeInstancesRequest request = DescribeInstancesRequest.builder()
                    .instanceIds(instanceIds)
                    .build();
            DescribeInstancesResponse result;
            do {
                // DescribeInstancesResponse is a paginated response, so use tokens with multiple re
                result = ec2.describeInstances(request);
                request = DescribeInstancesRequest.builder()   // Prepare request for next page.
                        .nextToken(result.nextToken())
                        .build();
                for (final Reservation r : result.reservations()) {
                    for (final Instance instance : r.instances()) {
                        // if instance is in a running state, add it to runningInstances list.
                        if (RUNNING_STATES.contains(instance.state().nameAsString())) {
                            runningInstances.add(instance);
                        }
                    }
                }
            } while (result.nextToken() != null);
        } catch (final Ec2Exception exception) {
            // if instance isn't found, assume its terminated and continue.
            if (exception.awsErrorDetails().errorCode().equals(NOT_FOUND_ERROR_CODE)) {
                    LOGGER.info("Instance probably terminated; moving on.");
            } else {
                throw exception;
            }
        }
        return runningInstances;
    }
...
```

Because we are migrating a single method in a Java file with eight methods, we have a mix of v1 and v2 imports as we work through the file. We added the last six import statements as we performed the steps. 

After we migrate all the code, there will be no more v1 import statements.

### 6. Remove v1 Maven dependencies from the POM and v1 imports from files
<a name="migration-steps-example-step6"></a>

After we migrate all v1 code in the file, we have the following v2 SDK import statements.

```
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.regions.ServiceMetadata;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.CreateTagsRequest;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse;
import software.amazon.awssdk.services.ec2.model.Ec2Exception;
import software.amazon.awssdk.services.ec2.model.Instance;
import software.amazon.awssdk.services.ec2.model.InstanceStateName;
import software.amazon.awssdk.services.ec2.model.Reservation;
import software.amazon.awssdk.services.ec2.model.Tag;
import software.amazon.awssdk.services.ec2.model.TerminateInstancesRequest;
```

After we migrate *all* files in our application, we no longer need the v1 dependencies in our POM file. Remove the v1 BOM from the `dependencyManagement` section, if using, and all v1 dependency blocks.

### 7. Refactor the code to use v2 API enhancements
<a name="migration-steps-example-step7"></a>

For the snippet we have been migrating, we can optionally use a v2 paginator and let the SDK manage the token-based requests for more data.

We can replace the entire `do` clause with the following.

```
                DescribeInstancesIterable responses = ec2.describeInstancesPaginator(request);

                responses.reservations().stream()
                        .forEach(reservation -> reservation.instances()
                                .forEach(instance -> {
                                    if (RUNNING_STATES.contains(instance.state().nameAsString())) {
                                        runningInstances.put(instance.instanceId(), instance);
                                    }
                                }));
```

## Package name to Maven artifactId mappings
<a name="migration-serviceid-artifactid-mapping"></a>

When you migrate your Maven or Gradle project from v1 of the SDK for Java to v2, you need to figure out which dependencies to add to your build file. The approach described in the [Migration step-by-step instructions with example](#migration-steps) (step 3) uses the package names in import statements as a starting point to determine the dependencies (as artifactIds) to add to your build file. 

You can use the information in this topic to map the v1 package names to v2 artifactIds.

### Common naming convention used in package names and Maven artifactIds
<a name="migration-naming-convention"></a>

The following table shows the common naming convention that the SDKs use for a given SERVICE\$1ID. A SERVICE\$1ID is a unique identifier for an AWS service. For example, the SERVICE\$1ID for the Amazon S3 service is `s3` and `cognitoidentity` is the SERVICE\$1ID for Amazon Cognito Identity.


| v1 package name (import statement) | v1 artifactId | v2 artifactId | v2 package name (import statement) | 
| --- | --- | --- | --- | 
| com.amazonaws.services.SERVICE\$1ID | aws-java-sdk-SERVICE\$1ID | SERVICE\$1ID | software.amazon.awssdk.services.SERVICE\$1ID | 
|   | 
| Example for Amazon Cognito Identity (SERVICE\$1ID: cognitoidentity) | 
| com.amazonaws.services.cognitoidentity | aws-java-sdk-cognitoidentity | cognitoidentity | software.amazon.awssdk.services.cognitoidentity | 

### SERVICE\$1ID differences
<a name="migration-serviceid-diffs"></a>

#### Within v1
<a name="migration-serviceid-diffs-withinv1"></a>

In some cases the SERVICE\$1ID differs between the package name and in the artifactId for the same service. For example, the CloudWatch Metrics row of the following table shows that `metrics` is the SERVICE\$1ID in the package name but `cloudwatchmetrics` is the artifactId's SERVICE\$1ID.

#### Within v2
<a name="migration-serviceid-diffs-withinv2"></a>

There are no differences in the SERVICE\$1ID used in package names and artifactIds.

#### Between v1 and v2
<a name="migration-serviceid-diffs-btwv1v2"></a>

For the majority of services, the SERVICE\$1ID in v2 is the same as v1's SERVICE\$1ID in both package names and artifactIds. An example of this is the `cognitoedentity` SERVICE\$1ID as shown in the previous table. However, some SERVICE\$1IDs differ between the SDKs as shown in the following table.

A **boldface SERVICE\$1ID** in either of the v1 columns indicates that it's different from the SERVICE\$1ID used in v2.


| Service name | v1 package name | v1 artifactId | v2 artifactId | v2 package name | 
| --- | --- | --- | --- | --- | 
|  |  All package names begin with `com.amazonaws.services` as shown in the first row.  |  All artifactIds are enclosed in tags as shown in the first row.  |  All artifactIds are enclosed in tags as shown in the first row.  |  All package names begin with `software.amazon.awssdk` as shown in the first row.  | 
|  | 
| API Gateway | com.amazonaws.services.apigateway | <artifactId>aws-java-sdk-api-gateway</artifactId> | <artifactId>apigateway</artifactId> | software.amazon.awssdk.services.apigateway | 
| App Registry | appregistry | appregistry | servicecatalogappregistry | servicecatalogappregistry | 
| Application Discovery | applicationdiscovery | discovery | applicationdiscovery | applicationdiscovery | 
| Augmented AI Runtime | augmentedairuntime | augmentedairuntime | sagemakera2iruntime | sagemakera2iruntime | 
| Certificate Manager | certificatemanager | acm | acm | acm | 
| CloudControl API | cloudcontrolapi | cloudcontrolapi | cloudcontrol | cloudcontrol | 
| CloudSearch | cloudsearchv2 | cloudsearch | cloudsearch | cloudsearch | 
| CloudSearch Domain | cloudsearchdomain | cloudsearch | cloudsearchdomain | cloudsearchdomain | 
| CloudWatch Events | cloudwatchevents | events | cloudwatchevents | cloudwatchevents | 
| CloudWatch Evidently | cloudwatchevidently | cloudwatchevidently | evidently | evidently | 
| CloudWatch Logs | logs | logs | cloudwatchlogs | cloudwatchlogs | 
| CloudWatch Metrics | metrics | cloudwatchmetrics | cloudwatch | cloudwatch | 
| CloudWatch Rum | cloudwatchrum | cloudwatchrum | rum | rum | 
| Cognito Identity Provider | cognitoidp | cognitoidp | cognitoidentityprovider | cognitoidentityprovider | 
| Connect Campaign | connectcampaign | connectcampaign | connectcampaigns | connectcampaigns | 
| Connect Wisdom | connectwisdom | connectwisdom | wisdom | wisdom | 
| Database Migration Service | databasemigrationservice | dms | databasemigration | databasemigration | 
| DataZone | datazone | datazoneexternal | datazone | datazone | 
| DynamoDB | dynamodbv2 | dynamodb | dynamodb | dynamodb | 
| Elastic File System | elasticfilesystem | efs | efs | efs | 
| Elastic Map Reduce | elasticmapreduce | emr | emr | emr | 
| Glue DataBrew | gluedatabrew | gluedatabrew | databrew | databrew | 
| IAM Roles Anywhere | iamrolesanywhere | iamrolesanywhere | rolesanywhere | rolesanywhere | 
| Identity Management | identitymanagement | iam | iam | iam | 
| IoT Data | iotdata | iot | iotdataplane | iotdataplane | 
| Kinesis Analytics | kinesisanalytics | kinesis | kinesisanalytics | kinesisanalytics | 
| Kinesis Firehose | kinesisfirehose | kinesis | firehose | firehose | 
| Kinesis Video Signaling Channels | kinesisvideosignalingchannels | kinesisvideosignalingchannels | kinesisvideosignaling | kinesisvideosignaling | 
| Lex | lexruntime | lex | lexruntime | lexruntime | 
| Lookout For Vision | lookoutforvision | lookoutforvision | lookoutvision | lookoutvision | 
| Mainframe Modernization | mainframemodernization | mainframemodernization | m2 | m2 | 
| Marketplace Metering | marketplacemetering | marketplacemeteringservice | marketplacemetering | marketplacemetering | 
| Managed Grafana | managedgrafana | managedgrafana | grafana | grafana | 
| Mechanical Turk | mturk | mechanicalturkrequester | mturk | mturk | 
| Migration Hub Strategy Recommendations | migrationhubstrategyrecommendations | migrationhubstrategyrecommendations | migrationhubstrategy | migrationhubstrategy | 
| Nimble Studio | nimblestudio | nimblestudio | nimble | nimble | 
| Private 5G | private5g | private5g | privatenetworks | privatenetworks | 
| Prometheus | prometheus | prometheus | amp | amp | 
| Recycle Bin | recyclebin | recyclebin | rbin | rbin | 
| Redshift Data API | redshiftdataapi | redshiftdataapi | redshiftdata | redshiftdata | 
| Route 53 | route53domains | route53 | route53domains | route53domains | 
| Sage Maker Edge Manager | sagemakeredgemanager | sagemakeredgemanager | sagemakeredge | sagemakeredge | 
| Security Token | securitytoken | sts | sts | sts | 
| Server Migration | servermigration | servermigration | sms | sms | 
| Simple Email | simpleemail | ses | ses | ses | 
| Simple Email V2 | simpleemailv2 | sesv2 | sesv2 | sesv2 | 
| Simple Systems Management | simplesystemsmanagement | ssm | ssm | ssm | 
| Simple Workflow | simpleworkflow | simpleworkflow | swf | swf | 
| Step Functions | stepfunctions | stepfunctions | sfn | sfn | 