

# Migrate from version 1.x to 2.x of the AWS SDK for Java
<a name="migration"></a>

The AWS SDK for Java 2.x is a major rewrite of the 1.x code base built on top of Java 8\$1. It includes many updates, such as improved consistency, ease of use, and strongly enforced immutability. This section describes the major features that are new in version 2.x, and provides guidance on how to migrate your code to version 2.x from 1.x.

**Topics**
+ [What’s new in version 2](#migration-whats-new)
+ [Find applications using 1.x clients](migration-find-apps-using-v1.md)
+ [How to migrate](migration-howto.md)
+ [What's different between 1.x and 2.x](migration-whats-different.md)
+ [Use the SDK for Java 1.x and 2.x side-by-side](migration-side-by-side.md)

## What’s new in version 2
<a name="migration-whats-new"></a>
+ You can configure your own HTTP clients. See [HTTP transport configuration](http-configuration.md).
+ Async clients feature non-blocking I/O support and return `CompletableFuture` objects. See [Asynchronous programming](asynchronous.md).
+ Operations that return multiple pages have autopaginated responses. This way, you can focus your code on what to do with the response, without the need to check for and get subsequent pages. See [Pagination](pagination.md). 
+ SDK start time performance for AWS Lambda functions is improved. See [SDK start time performance improvements](lambda-optimize-starttime.md). 
+ Version 2.x supports a new shorthand method for creating requests.  
**Example**  

  ```
  dynamoDbClient.putItem(request -> request.tableName(TABLE))
  ```

For more details about the new features and to see specific code examples, refer to the other sections of this guide.
+  [Quick Start](get-started.md) 
+  [Setting up](setup.md) 
+  [Code examples for the AWS SDK for Java 2.x ](java_code_examples.md)
+  [Use the SDK](using.md) 
+  [Security for the AWS SDK for Java](security.md) 

# Find applications using AWS SDK for Java 1.x clients
<a name="migration-find-apps-using-v1"></a>

Before migrating to the AWS SDK for Java 2.x, you need to identify which applications in your environment use SDK for Java 1.x clients. You can use CloudTrail logs to trace SDK usage, search application logs for deprecation warnings, inspect your source code and build configurations, or examine your deployable Java artifacts. Use whichever methods are available in your environment.

## Use CloudTrail Lake to find applications with 1.x clients
<a name="migration-find-v1-apps-with-cloudtrail"></a>

AWS CloudTrail Lake lets you query events recorded by CloudTrail. Follow these steps to create a data lake that identifies SDK versions used by your applications:

1. Create a CloudTrail data lake. Refer to the [User guide](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/query-event-data-store.html) to create an event data store.

1. After you create the data store, examine the record contents. The record body contains fields that determine the requested action, timing, and location. For details, refer to the [User guide for CloudTrail record contents](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-record-contents.html).

1. Run queries against your data. Follow the [User Guide to query and save query results](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/query-run-query.html).

The *userAgent* field in each record contains the SDK version that made the request. Use this field to identify applications using SDK for Java 1.x.

The following sample query finds all requests from user applications and third-party tools made with SDK for Java 1.x starting from June 17, 2025, for an EventDatastoreID `sample-Data-Store-Id`:

```
select userIdentity, eventSource, awsRegion,
    eventName, eventType, eventTime, userAgent,
    requestParameters, sourceIPAddress
 from sample-Data-Store-Id
where eventTime > '2025-06-17 00:00:00'
and userAgent like '%aws-sdk-java/1.%'
and userAgent not like '%aws-internal/%'
order by eventTime desc
```

An example of event content in the query result looks like this:

```
{
    "userIdentity": "{
         "type": "IAMUser",
         "principalId": "AIDAJ45Q7YFFAREXAMPLE",
         "arn": "arn:aws:iam::123456789012:user/Alice",
         "accountId": "123456789012",
         "accessKeyId": "",
         "userName": "Alice"
    }",
    "eventSource": "dynamodb.amazonaws.com",
    "awsRegion": "us-west-2",
    "eventName": "ListTables",
    "eventType": "AwsApiCall",
    "eventTime": "2025-07-01 02:23:52.000",
    "userAgent": "aws-sdk-java/1.12.746 Linux/5.10.240 OpenJDK/11.0.25+9-LTS ...",
    "requestParameters": "",
    "sourceIPAddress": "12.345.6.78"
}
```

You can use this information to help determine when and where the request was made.

In the example, a DynamoDB `ListTables` request was made at `2025-07-01 02:23:52 (UTC)` from the IP Address `12.345.6.78` with the credentials of the IAM user named Alice. The *userAgent* field's value shows that the request was made using the AWS SDK for Java version `1.12.746` from a Linux system with JDK 11.

For a description of the fields in the AWS CloudTrail event record, see [CloudTrail record contents for management, data, and network activity events ](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-record-contents.html).

If CloudTrail is not enabled in your account, contact your organization's AWS account administrator to enable it, or use one of the alternative methods described in the following sections.

CloudTrail Lake charges for data ingested and data scanned per query. To minimize costs, filter queries to specific time ranges and regions. For current pricing, see [AWS CloudTrail Pricing](https://aws.amazon.com/cloudtrail/pricing/).

## Search application warning-level logs for SDK deprecation
<a name="migration-find-v1-apps-log-warning"></a>

Starting with version 1.12.767 (released on July 30, 2024), the AWS SDK for Java 1.x emits a deprecation warning at application startup. You can search your application logs for this warning to identify which applications and hosts are using SDK for Java 1.x.

The exact wording of the warning depends on the SDK version:
+ Versions 1.12.767 through 1.12.796:

  `WARNING: The AWS SDK for Java 1.x entered maintenance mode starting July 31, 2024 and will reach end of support on December 31, 2025...`
+ Versions 1.12.797 and higher:

  `WARNING: The AWS SDK for Java 1.x reached end of support on December 31, 2025...`

The trailing `...` indicates that the warning message continues with additional text. You can search for the common prefix `The AWS SDK for Java 1.x` to find either version of the warning.

The following example demonstrates searching for this warning using `grep`:

```
grep -r "The AWS SDK for Java 1.x" /path/to/your/application/logs/
```

If the warning is found, the `grep` command prints the matching log lines. If no warning is found, either your application is not using SDK for Java 1.x, or it uses a version earlier than 1.12.767. In that case, use one of the other methods described in this document.

## Search source code and dependencies
<a name="migration-find-v1-apps-source-code"></a>

You can search your codebase and build configuration files for references to the AWS SDK for Java 1.x. The key identifier is the `com.amazonaws` group ID, which is used by all SDK for Java 1.x artifacts.

The following examples demonstrate using `grep` to search for `com.amazonaws` references across common Java project files.

**Example: Search Java source files for SDK for Java 1.x imports (run from project root directory)**

```
grep -r "import com.amazonaws" --include="*.java" .
```

Example output:

```
src/main/java/com/example/App.java:import com.amazonaws.services.s3.AmazonS3;
```

**Note**  
The `com.amazonaws` package is also used by libraries that are not part of the SDK for Java 1.x, such as `aws-lambda-java-core`. To confirm an import is from SDK for Java 1.x, check that the corresponding artifact ID in your `pom.xml`, `build.gradle`, or dependency management configuration starts with `aws-java-sdk-`.

**Example: Search Maven `pom.xml` files for SDK for Java 1.x dependencies (run from project root directory)**

```
grep -r "com.amazonaws" --include="pom.xml" .
```

Example output:

```
pom.xml:    <groupId>com.amazonaws</groupId>
```

**Example: Search Gradle build files for SDK for Java 1.x dependencies (run from project root directory)**

```
grep -r "com.amazonaws:aws-java-sdk" --include="*.gradle" .
```

Example output:

```
build.gradle:    implementation 'com.amazonaws:aws-java-sdk-s3:1.12.xxx'
```

The preceding `grep` commands identify SDK for Java 1.x references declared directly in your source and build files. However, your application might also depend on SDK for Java 1.x transitively — through a third-party library that itself depends on the SDK. Use your build tool's dependency tree to find both direct and transitive SDK for Java 1.x dependencies. Choose the example that matches your build system.

**Example: Use Maven to find all transitive SDK for Java 1.x dependencies (run from project root directory)**

```
mvn dependency:tree -Dincludes=com.amazonaws
```

Example output:

```
[INFO] com.example:my-application:jar:1.0-SNAPSHOT
[INFO] +- com.amazonaws:aws-java-sdk-s3:jar:1.12.746:compile
[INFO] |  \- com.amazonaws:aws-java-sdk-core:jar:1.12.746:compile
[INFO] \- some.thirdparty:library:jar:2.3.1:compile
[INFO]    \- com.amazonaws:aws-java-sdk-dynamodb:jar:1.12.600:compile
```

The `-Dincludes=com.amazonaws` flag filters the tree to show only SDK for Java 1.x artifacts. In this example, `aws-java-sdk-s3` is a direct dependency, but `aws-java-sdk-dynamodb` is a transitive dependency brought in by `some.thirdparty:library`.

**Example: Use Gradle to find all transitive SDK for Java 1.x dependencies (run from project root directory)**

```
gradle dependencies --configuration runtimeClasspath | grep "com.amazonaws"
```

Example output:

```
+--- com.amazonaws:aws-java-sdk-s3:1.12.746
|    \--- com.amazonaws:aws-java-sdk-core:1.12.746
\--- com.amazonaws:aws-java-sdk-dynamodb:1.12.600
```

Gradle does not have a built-in dependency filter equivalent to Maven's `-Dincludes`, so piping through `grep` is the simplest approach.

## Inspect deployable Java artifacts
<a name="migration-find-v1-apps-inspect-artifacts"></a>

You can inspect your deployable Java artifacts (JARs, WARs, or EARs) to confirm whether the AWS SDK for Java 1.x is packaged with your application. Java archive files are ZIP-format files. To determine if SDK for Java 1.x is present, look for the file `com/amazonaws/sdk/versionInfo.properties` inside the archive. This file is included in the `aws-java-sdk-core` module and contains the SDK version number.

### Quick check with the `jar` command
<a name="migration-find-v1-apps-jar-command"></a>

For uber-jars where all dependency classes are merged at the top level, list the archive contents and search for the version file:

In the following examples, replace `myapp.jar` with the path to your application's JAR file.

```
jar -tf myapp.jar | grep 'versionInfo.properties'
```

If the SDK is present, the output is:

```
com/amazonaws/sdk/versionInfo.properties
```

If the `jar` command is not available in your environment (for example, JRE-only or minimal container images), you can use `unzip -l` instead:

```
unzip -l myapp.jar | grep 'versionInfo.properties'
```

To print the version:

```
unzip -p myapp.jar com/amazonaws/sdk/versionInfo.properties
```

Example output:

```
platform=java
version=1.12.xxx
```

**Note**  
The preceding commands only search top-level entries in uber-jars. They will not find SDK classes in thin JARs (where dependencies are external) or inside nested JARs (such as those in WARs, EARs, or Lambda packages under `lib/` or `WEB-INF/lib/`). For thin JARs, check your build configuration (`pom.xml`, `build.gradle`) or dependency tree instead. For nested JARs, search the bundled JARs using a tool that can read ZIP archives recursively without extracting to disk.

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

# What's different between the AWS SDK for Java 1.x and 2.x
<a name="migration-whats-different"></a>

This section describes the main changes to be aware of when converting an application from using the AWS SDK for Java version 1.x to version 2.x.

## Package name change
<a name="mig-diff-package-name-change"></a>

A noticeable change from the SDK for Java 1.x to the SDK for Java 2.x is the package name change. Package names begin with `software.amazon.awssdk` in SDK 2.x, whereas the SDK 1.x uses `com.amazonaws`.

These same names differentiate Maven artifacts from SDK 1.x to SDK 2.x. Maven artifacts for the SDK 2.x use the `software.amazon.awssdk` groupId, whereas the SDK 1.x uses the `com.amazonaws` groupId.

There are a few times when your code requires a `com.amazonaws` dependency for a project that otherwise uses only SDK 2.x artifacts. One example of this is when you work with server-side AWS Lambda. This was shown in the [Set up an Apache Maven project](setup-project-maven.md#modules-dependencies) section earlier in this guide.

**Note**  
Several package names in the SDK 1.x contain `v2`. The use of `v2` in this case usually means that code in the package is targeted to work with version 2 of the service.   
Since the full package name begins with `com.amazonaws`, these are SDK 1.x components. Examples of these package names in the SDK 1.x are:   
`com.amazonaws.services.dynamodbv2`
`com.amazonaws.retry.v2`
`com.amazonaws.services.apigatewayv2`
`com.amazonaws.services.simpleemailv2`

## Adding version 2.x to your project
<a name="adding-v2"></a>

Maven is the recommended way to manage dependencies when using the AWS SDK for Java 2.x. To add version 2.x components to your project, update your `pom.xml` file with a dependency on the SDK. 

**Example**  

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

<dependencies>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>dynamodb</artifactId>
    </dependency>
</dependencies>
```

You can also [use version 1.x and 2.x side-by-side](migration-side-by-side.md) as you migrate your project to version 2.x.

## Immutable POJOs
<a name="immutable-classes"></a>

Clients and operation request and response objects are now immutable and cannot be changed after creation. To reuse a request or response variable, you must build a new object to assign to it.

**Example of updating a request object in 1.x**  

```
DescribeAlarmsRequest request = new DescribeAlarmsRequest();
DescribeAlarmsResult response = cw.describeAlarms(request);

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

**Example of updating a request object in 2.x**  

```
DescribeAlarmsRequest request = DescribeAlarmsRequest.builder().build();
DescribeAlarmsResponse response = cw.describeAlarms(request);

request = DescribeAlarmsRequest.builder()
        .nextToken(response.nextToken())
        .build();
```

## Setter and getter methods
<a name="setter-getter-methods"></a>

In the AWS SDK for Java 2.x, setter method names don’t include the `set` or `with` prefix. For example, `*.withEndpoint()` is now `*.endpoint()`.

Getter method names do not use the `get` prefix.

**Example of using setter methods in 1.x**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
        		.withRegion("us-east-1")
        		.build();
```

**Example of using setter methods in 2.x**  

```
DynamoDbClient client = DynamoDbClient.builder()
        		.region(Region.US_EAST_1)
        		.build();
```

**Example of using getter methods in 1.x**  

```
String token = request.getNextToken();
```

**Example of using getter methods in 2.x**  

```
String token = request.nextToken();
```

## Model class names
<a name="model-classname-changes"></a>

Model class names that represent service responses end with `Response` in v2 instead of `Result` that v1 uses.

**Example of class names that represent a response in v1**  

```
CreateApiKeyResult
AllocateAddressResult
```

**Example of class names that represent a response in v2**  

```
CreateApiKeyResponse
AllocateAddressResponse
```

## Migration status of libraries and utilities
<a name="migration-libraries-utilities"></a>

### SDK for Java libraries and utilities
<a name="migration-java-sdk-libs-utils"></a>

The following table lists the migration status of libraries and utilities for the SDK for Java. 


| Version 1.12.x name | Version 2.x name | Since version in 2.x | 
| --- | --- | --- | 
| DynamoDBMapper | [DynamoDbEnhancedClient](dynamodb-enhanced-client.md) | 2.12.0 | 
| Waiters | [Waiters](waiters.md) | 2.15.0 | 
| CloudFrontUrlSigner, CloudFrontCookieSigner | [CloudFrontUtilities](https://aws.amazon.com/blogs/developer/amazon-cloudfront-signed-urls-and-cookies-are-now-supported-in-aws-sdk-for-java-2-x/) | 2.18.33 | 
| TransferManager | [S3TransferManager](transfer-manager.md) | 2.19.0 | 
| EC2 Metadata client |  [EC2 Metadata client](examples-ec2-IMDS.md)  | 2.19.29 | 
| S3 URI parser |  [S3 URI parser](https://aws.amazon.com/blogs/devops/s3-uri-parsing-is-now-available-in-aws-sdk-for-java-2-x/)  | 2.20.41 | 
| IAM Policy Builder | [IAM Policy Builder](feature-iam-policy-builder.md) | 2.20.126 | 
| S3 Event Notifications | [S3 Event Notifications](examples-s3-event-notifications.md#s3-event-notification-read) | 2.25.11  | 
| Amazon SQS Client-side Buffering | [Automatic Request Batching API for Amazon SQS](sqs-auto-batch.md) | 2.28.0 | 
| Progress Listeners | Progress Listeners | [not yet released](https://github.com/aws/aws-sdk-java-v2/issues/25) | 

### Related libraries
<a name="migration-other-sdks"></a>

The following table lists libraries that are released separately but work with the SDK for Java 2.x.


| Name used with version 2.x of the SDK for Java | Since version | 
| --- | --- | 
|  [Amazon S3 Encryption Client](https://docs.aws.amazon.com/amazon-s3-encryption-client/latest/developerguide/what-is-s3-encryption-client.html)  |  3.0.01  | 
| [AWS Database Encryption SDK for DynamoDB](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/ddb-java.html) | 3.0.02 | 

#### 1Amazon S3 Encryption Client
<a name="migration-s3-encryption-sdk"></a>

The encryption client for Amazon S3 is available by using the following Maven dependency.

```
<dependency>
    <groupId>software.amazon.encryption.s3</groupId>
    <artifactId>amazon-s3-encryption-client-java</artifactId>
    <version>3.x</version>
</dependency>
```

#### 2AWS Database Encryption SDK for DynamoDB
<a name="migration-ddb-encryption-sdk"></a>

The AWS Database Encryption SDK for DynamoDB is available for V2 by using the following Maven dependency.

```
<dependency> 
    <groupId>software.amazon.cryptography</groupId>
    <artifactId>aws-database-encryption-sdk-dynamodb</artifactId>
    <version>3.x</version>
</dependency>
```

Information on the encryption library for DynamoDB that works with v1 of the Java SDK is available in the [AWS Database Encryption SDK Developer Guide](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/java.html) (named *Amazon DynamoDB Encryption Client for Java*) and in [GitHub](https://github.com/aws/aws-dynamodb-encryption-java).

For more information on the DynamoDB encryption library that is compatible with V2 of the Java SDK, see the [AWS Database Encryption SDK Developer Guide](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/ddb-java.html) and the [GitHub source](https://github.com/aws/aws-database-encryption-sdk-dynamodb).

Migration information about the encryption library is available in the [AWS Database Encryption SDK Developer Guide](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/ddb-java-migrate.html).

### Migration details for libraries and utilities
<a name="migrate-libs-utils-details"></a>
+ [Transfer Manager](migration-s3-transfer-manager.md)
+ [EC2 metadata utility](migration-imds.md)
+ [CloudFront presigning](migration-cloudfront-presigning.md)
+ [S3 URI parsing](migration-s3-uri-parser.md)
+ [DynamoDB mapping/document APIs](migration-ddb-mapper.md) 
+ [IAM Policy Builder](migration-iam-policy-builder.md)
+ [S3 Event Notifications](migration-s3-event-notification.md)
+ 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))

# Client changes
<a name="migration-clients"></a>

## Client builders
<a name="client-builder"></a>

You must create all clients using the client builder method. Constructors are no longer available.

**Example of creating a client in version 1.x**  

```
AmazonDynamoDB ddbClient = AmazonDynamoDBClientBuilder.defaultClient();
AmazonDynamoDBClient ddbClient = new AmazonDynamoDBClient();
```

**Example of creating a client in version 2.x**  

```
DynamoDbClient ddbClient = DynamoDbClient.create();
DynamoDbClient ddbClient = DynamoDbClient.builder().build();
```

## Client class names
<a name="class-names"></a>

All client class names are now fully camel cased and no longer prefixed by `Amazon`. These changes are aligned with names used in the AWS CLI.

**Example of class names in 1.x**  

```
AmazonDynamoDB
AWSACMPCAAsyncClient
```

**Example of class names in 2.x**  

```
DynamoDbClient
AcmAsyncClient
```


**Client class name changes**  

| 1.x Client | 2.x Client | 
| --- | --- | 
| com.amazonaws.services.acmpca.AWSACMPCAAsyncClient | software.amazon.awssdk.services.acm.AcmAsyncClient | 
| com.amazonaws.services.acmpca.AWSACMPCAClient | software.amazon.awssdk.services.acm.AcmClient | 
| com.amazonaws.services.alexaforbusiness.AmazonAlexaForBusinessAsyncClient | software.amazon.awssdk.services.alexaforbusiness.AlexaForBusinessAsyncClient | 
| com.amazonaws.services.alexaforbusiness.AmazonAlexaForBusinessClient | software.amazon.awssdk.services.alexaforbusiness.AlexaForBusinessClient | 
| com.amazonaws.services.apigateway.AmazonApiGatewayAsyncClient | software.amazon.awssdk.services.apigateway.ApiGatewayAsyncClient | 
| com.amazonaws.services.apigateway.AmazonApiGatewayClient | software.amazon.awssdk.services.apigateway.ApiGatewayClient | 
| com.amazonaws.services.applicationautoscaling.AWSApplicationAutoScalingAsyncClient | software.amazon.awssdk.services.applicationautoscaling.ApplicationAutoScalingAsyncClient | 
| com.amazonaws.services.applicationautoscaling.AWSApplicationAutoScalingClient | software.amazon.awssdk.services.applicationautoscaling.ApplicationAutoScalingClient | 
| com.amazonaws.services.applicationdiscovery.AWSApplicationDiscoveryAsyncClient | software.amazon.awssdk.services.applicationdiscovery.ApplicationDiscoveryAsyncClient | 
| com.amazonaws.services.applicationdiscovery.AWSApplicationDiscoveryClient | software.amazon.awssdk.services.applicationdiscovery.ApplicationDiscoveryClient | 
| com.amazonaws.services.appstream.AmazonAppStreamAsyncClient | software.amazon.awssdk.services.appstream.AppStreamAsyncClient | 
| com.amazonaws.services.appstream.AmazonAppStreamClient | software.amazon.awssdk.services.appstream.AppStreamClient | 
| com.amazonaws.services.appsync.AWSAppSyncAsyncClient | software.amazon.awssdk.services.appsync.AppSyncAsyncClient | 
| com.amazonaws.services.appsync.AWSAppSyncClient | software.amazon.awssdk.services.appsync.AppSyncClient | 
| com.amazonaws.services.athena.AmazonAthenaAsyncClient | software.amazon.awssdk.services.athena.AthenaAsyncClient | 
| com.amazonaws.services.athena.AmazonAthenaClient | software.amazon.awssdk.services.athena.AthenaClient | 
| com.amazonaws.services.autoscaling.AmazonAutoScalingAsyncClient | software.amazon.awssdk.services.autoscaling.AutoScalingAsyncClient | 
| com.amazonaws.services.autoscaling.AmazonAutoScalingClient | software.amazon.awssdk.services.autoscaling.AutoScalingClient | 
| com.amazonaws.services.autoscalingplans.AWSAutoScalingPlansAsyncClient | software.amazon.awssdk.services.autoscalingplans.AutoScalingPlansAsyncClient | 
| com.amazonaws.services.autoscalingplans.AWSAutoScalingPlansClient | software.amazon.awssdk.services.autoscalingplans.AutoScalingPlansClient | 
| com.amazonaws.services.batch.AWSBatchAsyncClient | software.amazon.awssdk.services.batch.BatchAsyncClient | 
| com.amazonaws.services.batch.AWSBatchClient | software.amazon.awssdk.services.batch.BatchClient | 
| com.amazonaws.services.budgets.AWSBudgetsAsyncClient | software.amazon.awssdk.services.budgets.BudgetsAsyncClient | 
| com.amazonaws.services.budgets.AWSBudgetsClient | software.amazon.awssdk.services.budgets.BudgetsClient | 
| com.amazonaws.services.certificatemanager.AWSCertificateManagerAsyncClient | software.amazon.awssdk.services.acm.AcmAsyncClient | 
| com.amazonaws.services.certificatemanager.AWSCertificateManagerClient | software.amazon.awssdk.services.acm.AcmClient | 
| com.amazonaws.services.cloud9.AWSCloud9AsyncClient | software.amazon.awssdk.services.cloud9.Cloud9AsyncClient | 
| com.amazonaws.services.cloud9.AWSCloud9Client | software.amazon.awssdk.services.cloud9.Cloud9Client | 
| com.amazonaws.services.clouddirectory.AmazonCloudDirectoryAsyncClient | software.amazon.awssdk.services.clouddirectory.CloudDirectoryAsyncClient | 
| com.amazonaws.services.clouddirectory.AmazonCloudDirectoryClient | software.amazon.awssdk.services.clouddirectory.CloudDirectoryClient | 
| com.amazonaws.services.cloudformation.AmazonCloudFormationAsyncClient | software.amazon.awssdk.services.cloudformation.CloudFormationAsyncClient | 
| com.amazonaws.services.cloudformation.AmazonCloudFormationClient | software.amazon.awssdk.services.cloudformation.CloudFormationClient | 
| com.amazonaws.services.cloudfront.AmazonCloudFrontAsyncClient | software.amazon.awssdk.services.cloudfront.CloudFrontAsyncClient | 
| com.amazonaws.services.cloudfront.AmazonCloudFrontClient | software.amazon.awssdk.services.cloudfront.CloudFrontClient | 
| com.amazonaws.services.cloudhsm.AWSCloudHSMAsyncClient | software.amazon.awssdk.services.cloudhsm.CloudHsmAsyncClient | 
| com.amazonaws.services.cloudhsm.AWSCloudHSMClient | software.amazon.awssdk.services.cloudhsm.CloudHsmClient | 
| com.amazonaws.services.cloudhsmv2.AWSCloudHSMV2AsyncClient | software.amazon.awssdk.services.cloudhsmv2.CloudHsmV2AsyncClient | 
| com.amazonaws.services.cloudhsmv2.AWSCloudHSMV2Client | software.amazon.awssdk.services.cloudhsmv2.CloudHsmV2Client | 
| com.amazonaws.services.cloudsearchdomain.AmazonCloudSearchDomainAsyncClient | software.amazon.awssdk.services.cloudsearchdomain.CloudSearchDomainAsyncClient | 
| com.amazonaws.services.cloudsearchdomain.AmazonCloudSearchDomainClient | software.amazon.awssdk.services.cloudsearchdomain.CloudSearchDomainClient | 
| com.amazonaws.services.cloudsearchv2.AmazonCloudSearchAsyncClient | software.amazon.awssdk.services.cloudsearch.CloudSearchAsyncClient | 
| com.amazonaws.services.cloudsearchv2.AmazonCloudSearchClient | software.amazon.awssdk.services.cloudsearch.CloudSearchClient | 
| com.amazonaws.services.cloudtrail.AWSCloudTrailAsyncClient | software.amazon.awssdk.services.cloudtrail.CloudTrailAsyncClient | 
| com.amazonaws.services.cloudtrail.AWSCloudTrailClient | software.amazon.awssdk.services.cloudtrail.CloudTrailClient | 
| com.amazonaws.services.cloudwatch.AmazonCloudWatchAsyncClient | software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient | 
| com.amazonaws.services.cloudwatch.AmazonCloudWatchClient | software.amazon.awssdk.services.cloudwatch.CloudWatchClient | 
| com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEventsAsyncClient | software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsAsyncClient | 
| com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEventsClient | software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsClient | 
| com.amazonaws.services.codebuild.AWSCodeBuildAsyncClient | software.amazon.awssdk.services.codebuild.CodeBuildAsyncClient | 
| com.amazonaws.services.codebuild.AWSCodeBuildClient | software.amazon.awssdk.services.codebuild.CodeBuildClient | 
| com.amazonaws.services.codecommit.AWSCodeCommitAsyncClient | software.amazon.awssdk.services.codecommit.CodeCommitAsyncClient | 
| com.amazonaws.services.codecommit.AWSCodeCommitClient | software.amazon.awssdk.services.codecommit.CodeCommitClient | 
| com.amazonaws.services.codedeploy.AmazonCodeDeployAsyncClient | software.amazon.awssdk.services.codedeploy.CodeDeployAsyncClient | 
| com.amazonaws.services.codedeploy.AmazonCodeDeployClient | software.amazon.awssdk.services.codedeploy.CodeDeployClient | 
| com.amazonaws.services.codepipeline.AWSCodePipelineAsyncClient | software.amazon.awssdk.services.codepipeline.CodePipelineAsyncClient | 
| com.amazonaws.services.codepipeline.AWSCodePipelineClient | software.amazon.awssdk.services.codepipeline.CodePipelineClient | 
| com.amazonaws.services.codestar.AWSCodeStarAsyncClient | software.amazon.awssdk.services.codestar.CodeStarAsyncClient | 
| com.amazonaws.services.codestar.AWSCodeStarClient | software.amazon.awssdk.services.codestar.CodeStarClient | 
| com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityAsyncClient | software.amazon.awssdk.services.cognitoidentity.CognitoIdentityAsyncClient | 
| com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityClient | software.amazon.awssdk.services.cognitoidentity.CognitoIdentityClient | 
| com.amazonaws.services.cognitoidp.AWSCognitoIdentityProviderAsyncClient | software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderAsyncClient | 
| com.amazonaws.services.cognitoidp.AWSCognitoIdentityProviderClient | software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient | 
| com.amazonaws.services.cognitosync.AmazonCognitoSyncAsyncClient | software.amazon.awssdk.services.cognitosync.CognitoSyncAsyncClient | 
| com.amazonaws.services.cognitosync.AmazonCognitoSyncClient | software.amazon.awssdk.services.cognitosync.CognitoSyncClient | 
| com.amazonaws.services.comprehend.AmazonComprehendAsyncClient | software.amazon.awssdk.services.comprehend.ComprehendAsyncClient | 
| com.amazonaws.services.comprehend.AmazonComprehendClient | software.amazon.awssdk.services.comprehend.ComprehendClient | 
| com.amazonaws.services.config.AmazonConfigAsyncClient | software.amazon.awssdk.services.config.ConfigAsyncClient | 
| com.amazonaws.services.config.AmazonConfigClient | software.amazon.awssdk.services.config.ConfigClient | 
| com.amazonaws.services.connect.AmazonConnectAsyncClient | software.amazon.awssdk.services.connect.ConnectAsyncClient | 
| com.amazonaws.services.connect.AmazonConnectClient | software.amazon.awssdk.services.connect.ConnectClient | 
| com.amazonaws.services.costandusagereport.AWSCostAndUsageReportAsyncClient | software.amazon.awssdk.services.costandusagereport.CostAndUsageReportAsyncClient | 
| com.amazonaws.services.costandusagereport.AWSCostAndUsageReportClient | software.amazon.awssdk.services.costandusagereport.CostAndUsageReportClient | 
| com.amazonaws.services.costexplorer.AWSCostExplorerAsyncClient | software.amazon.awssdk.services.costexplorer.CostExplorerAsyncClient | 
| com.amazonaws.services.costexplorer.AWSCostExplorerClient | software.amazon.awssdk.services.costexplorer.CostExplorerClient | 
| com.amazonaws.services.databasemigrationservice.AWSDatabaseMigrationServiceAsyncClient | software.amazon.awssdk.services.databasemigration.DatabaseMigrationAsyncClient | 
| com.amazonaws.services.databasemigrationservice.AWSDatabaseMigrationServiceClient | software.amazon.awssdk.services.databasemigration.DatabaseMigrationClient | 
| com.amazonaws.services.datapipeline.DataPipelineAsyncClient | software.amazon.awssdk.services.datapipeline.DataPipelineAsyncClient | 
| com.amazonaws.services.datapipeline.DataPipelineClient | software.amazon.awssdk.services.datapipeline.DataPipelineAsyncClient | 
| com.amazonaws.services.dax.AmazonDaxAsyncClient | software.amazon.awssdk.services.dax.DaxAsyncClient | 
| com.amazonaws.services.dax.AmazonDaxClient | software.amazon.awssdk.services.dax.DaxClient | 
| com.amazonaws.services.devicefarm.AWSDeviceFarmAsyncClient | software.amazon.awssdk.services.devicefarm.DeviceFarmAsyncClient | 
| com.amazonaws.services.devicefarm.AWSDeviceFarmClient | software.amazon.awssdk.services.devicefarm.DeviceFarmClient | 
| com.amazonaws.services.directconnect.AmazonDirectConnectAsyncClient | software.amazon.awssdk.services.directconnect.DirectConnectAsyncClient | 
| com.amazonaws.services.directconnect.AmazonDirectConnectClient | software.amazon.awssdk.services.directconnect.DirectConnectClient | 
| com.amazonaws.services.directory.AWSDirectoryServiceAsyncClient | software.amazon.awssdk.services.directory.DirectoryAsyncClient | 
| com.amazonaws.services.directory.AWSDirectoryServiceClient | software.amazon.awssdk.services.directory.DirectoryClient | 
| com.amazonaws.services.dlm.AmazonDLMAsyncClient | software.amazon.awssdk.services.dlm.DlmAsyncClient | 
| com.amazonaws.services.dlm.AmazonDLMClient | software.amazon.awssdk.services.dlm.DlmClient | 
| com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsyncClient | software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient | 
| com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient | software.amazon.awssdk.services.dynamodb.DynamoDbClient | 
| com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsAsyncClient | software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsAsyncClient | 
| com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsClient | software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsClient | 
| com.amazonaws.services.ec2.AmazonEC2AsyncClient | software.amazon.awssdk.services.ec2.Ec2AsyncClient | 
| com.amazonaws.services.ec2.AmazonEC2Client | software.amazon.awssdk.services.ec2.Ec2Client | 
| com.amazonaws.services.ecr.AmazonECRAsyncClient | software.amazon.awssdk.services.ecr.EcrAsyncClient | 
| com.amazonaws.services.ecr.AmazonECRClient | software.amazon.awssdk.services.ecr.EcrClient | 
| com.amazonaws.services.ecs.AmazonECSAsyncClient | software.amazon.awssdk.services.ecs.EcsAsyncClient | 
| com.amazonaws.services.ecs.AmazonECSClient | software.amazon.awssdk.services.ecs.EcsClient | 
| com.amazonaws.services.eks.AmazonEKSAsyncClient | software.amazon.awssdk.services.eks.EksAsyncClient | 
| com.amazonaws.services.eks.AmazonEKSClient | software.amazon.awssdk.services.eks.EksClient | 
| com.amazonaws.services.elasticache.AmazonElastiCacheAsyncClient | software.amazon.awssdk.services.elasticache.ElastiCacheAsyncClient | 
| com.amazonaws.services.elasticache.AmazonElastiCacheClient | software.amazon.awssdk.services.elasticache.ElastiCacheClient | 
| com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalkAsyncClient | software.amazon.awssdk.services.elasticbeanstalk.ElasticBeanstalkAsyncClient | 
| com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalkClient | software.amazon.awssdk.services.elasticbeanstalk.ElasticBeanstalkClient | 
| com.amazonaws.services.elasticfilesystem.AmazonElasticFileSystemAsyncClient | software.amazon.awssdk.services.efs.EfsAsyncClient | 
| com.amazonaws.services.elasticfilesystem.AmazonElasticFileSystemClient | software.amazon.awssdk.services.efs.EfsClient | 
| com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingAsyncClient | software.amazon.awssdk.services.elasticloadbalancing.ElasticLoadBalancingAsyncClient | 
| com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClient | software.amazon.awssdk.services.elasticloadbalancing.ElasticLoadBalancingClient | 
| com.amazonaws.services.elasticloadbalancingv2.AmazonElasticLoadBalancingAsyncClient | software.amazon.awssdk.services.elasticloadbalancingv2.ElasticLoadBalancingV2AsyncClient | 
| com.amazonaws.services.elasticloadbalancingv2.AmazonElasticLoadBalancingClient | software.amazon.awssdk.services.elasticloadbalancingv2.ElasticLoadBalancingV2Client | 
| com.amazonaws.services.elasticmapreduce.AmazonElasticMapReduceAsyncClient | software.amazon.awssdk.services.emr.EmrAsyncClient | 
| com.amazonaws.services.elasticmapreduce.AmazonElasticMapReduceClient | software.amazon.awssdk.services.emr.EmrClient | 
| com.amazonaws.services.elasticsearch.AWSElasticsearchAsyncClient | software.amazon.awssdk.services.elasticsearch.ElasticsearchAsyncClient | 
| com.amazonaws.services.elasticsearch.AWSElasticsearchClient | software.amazon.awssdk.services.elasticsearch.ElasticsearchClient | 
| com.amazonaws.services.elastictranscoder.AmazonElasticTranscoderAsyncClient | software.amazon.awssdk.services.elastictranscoder.ElasticTranscoderAsyncClient | 
| com.amazonaws.services.elastictranscoder.AmazonElasticTranscoderClient | software.amazon.awssdk.services.elastictranscoder.ElasticTranscoderClient | 
| com.amazonaws.services.fms.AWSFMSAsyncClient | software.amazon.awssdk.services.fms.FmsAsyncClient | 
| com.amazonaws.services.fms.AWSFMSClient | software.amazon.awssdk.services.fms.FmsClient | 
| com.amazonaws.services.gamelift.AmazonGameLiftAsyncClient | software.amazon.awssdk.services.gamelift.GameLiftAsyncClient | 
| com.amazonaws.services.gamelift.AmazonGameLiftClient | software.amazon.awssdk.services.gamelift.GameLiftClient | 
| com.amazonaws.services.glacier.AmazonGlacierAsyncClient | software.amazon.awssdk.services.glacier.GlacierAsyncClient | 
| com.amazonaws.services.glacier.AmazonGlacierClient | software.amazon.awssdk.services.glacier.GlacierClient | 
| com.amazonaws.services.glue.AWSGlueAsyncClient | software.amazon.awssdk.services.glue.GlueAsyncClient | 
| com.amazonaws.services.glue.AWSGlueClient | software.amazon.awssdk.services.glue.GlueClient | 
| com.amazonaws.services.greengrass.AWSGreengrassAsyncClient | software.amazon.awssdk.services.greengrass.GreengrassAsyncClient | 
| com.amazonaws.services.greengrass.AWSGreengrassClient | software.amazon.awssdk.services.greengrass.GreengrassClient | 
| com.amazonaws.services.guardduty.AmazonGuardDutyAsyncClient | software.amazon.awssdk.services.guardduty.GuardDutyAsyncClient | 
| com.amazonaws.services.guardduty.AmazonGuardDutyClient | software.amazon.awssdk.services.guardduty.GuardDutyClient | 
| com.amazonaws.services.health.AWSHealthAsyncClient | software.amazon.awssdk.services.health.HealthAsyncClient | 
| com.amazonaws.services.health.AWSHealthClient | software.amazon.awssdk.services.health.HealthClient | 
| com.amazonaws.services.identitymanagement.AmazonIdentityManagementAsyncClient | software.amazon.awssdk.services.iam.IamAsyncClient | 
| com.amazonaws.services.identitymanagement.AmazonIdentityManagementClient | software.amazon.awssdk.services.iam.IamClient | 
| com.amazonaws.services.importexport.AmazonImportExportAsyncClient | Deprecated | 
| com.amazonaws.services.importexport.AmazonImportExportClient | Deprecated | 
| com.amazonaws.services.inspector.AmazonInspectorAsyncClient | software.amazon.awssdk.services.inspector.InspectorAsyncClient | 
| com.amazonaws.services.inspector.AmazonInspectorClient | software.amazon.awssdk.services.inspector.InspectorClient | 
| com.amazonaws.services.iot.AWSIotAsyncClient | software.amazon.awssdk.services.iot.IotAsyncClient | 
| com.amazonaws.services.iot.AWSIotClient | software.amazon.awssdk.services.iot.IotClient | 
| com.amazonaws.services.iot1clickdevices.AWSIoT1ClickDevicesAsyncClient | software.amazon.awssdk.services.iot1clickdevices.Iot1ClickDevicesAsyncClient | 
| com.amazonaws.services.iot1clickdevices.AWSIoT1ClickDevicesClient | software.amazon.awssdk.services.iot1clickdevices.Iot1ClickDevicesClient | 
| com.amazonaws.services.iot1clickprojects.AWSIoT1ClickProjectsAsyncClient | software.amazon.awssdk.services.iot1clickprojects.Iot1ClickProjectsAsyncClient | 
| com.amazonaws.services.iot1clickprojects.AWSIoT1ClickProjectsClient | software.amazon.awssdk.services.iot1clickprojects.Iot1ClickProjectsClient | 
| com.amazonaws.services.iotanalytics.AWSIoTAnalyticsAsyncClient | software.amazon.awssdk.services.iotanalytics.IotAnalyticsAsyncClient | 
| com.amazonaws.services.iotanalytics.AWSIoTAnalyticsClient | software.amazon.awssdk.services.iotanalytics.IotAnalyticsClient | 
| com.amazonaws.services.iotdata.AWSIotDataAsyncClient | software.amazon.awssdk.services.iotdata.IotDataAsyncClient | 
| com.amazonaws.services.iotdata.AWSIotDataClient | software.amazon.awssdk.services.iotdata.IotDataClient | 
| com.amazonaws.services.iotjobsdataplane.AWSIoTJobsDataPlaneAsyncClient | software.amazon.awssdk.services.iotdataplane.IotDataPlaneAsyncClient | 
| com.amazonaws.services.iotjobsdataplane.AWSIoTJobsDataPlaneClient | software.amazon.awssdk.services.iotdataplane.IotDataPlaneClient | 
| com.amazonaws.services.kinesis.AmazonKinesisAsyncClient | software.amazon.awssdk.services.kinesis.KinesisAsyncClient | 
| com.amazonaws.services.kinesis.AmazonKinesisClient | software.amazon.awssdk.services.kinesis.KinesisClient | 
| com.amazonaws.services.kinesisanalytics.AmazonKinesisAnalyticsAsyncClient | software.amazon.awssdk.services.kinesisanalytics.KinesisAnalyticsAsyncClient | 
| com.amazonaws.services.kinesisanalytics.AmazonKinesisAnalyticsClient | software.amazon.awssdk.services.kinesisanalytics.KinesisAnalyticsClient | 
| com.amazonaws.services.kinesisfirehose.AmazonKinesisFirehoseAsyncClient | software.amazon.awssdk.services.firehose.FirehoseAsyncClient | 
| com.amazonaws.services.kinesisfirehose.AmazonKinesisFirehoseClient | software.amazon.awssdk.services.firehose.FirehoseClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoArchivedMediaAsyncClient | software.amazon.awssdk.services.kinesisvideoarchivedmedia.KinesisVideoArchivedMediaAsyncClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoArchivedMediaClient | software.amazon.awssdk.services.kinesisvideoarchivedmedia.KinesisVideoArchivedMediaClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoAsyncClient | software.amazon.awssdk.services.kinesisvideo.KinesisVideoAsyncClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoClient | software.amazon.awssdk.services.kinesisvideo.KinesisVideoClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoMediaAsyncClient | software.amazon.awssdk.services.kinesisvideomedia.KinesisVideoMediaAsyncClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoMediaClient | software.amazon.awssdk.services.kinesisvideomedia.KinesisVideoMediaClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoPutMediaClient | Not Supported  | 
| com.amazonaws.services.kms.AWSKMSAsyncClient | software.amazon.awssdk.services.kms.KmsAsyncClient | 
| com.amazonaws.services.kms.AWSKMSClient | software.amazon.awssdk.services.kms.KmsClient | 
| com.amazonaws.services.lambda.AWSLambdaAsyncClient | software.amazon.awssdk.services.lambda.LambdaAsyncClient | 
| com.amazonaws.services.lambda.AWSLambdaClient | software.amazon.awssdk.services.lambda.LambdaClient | 
| com.amazonaws.services.lexmodelbuilding.AmazonLexModelBuildingAsyncClient | software.amazon.awssdk.services.lexmodelbuilding.LexModelBuildingAsyncClient | 
| com.amazonaws.services.lexmodelbuilding.AmazonLexModelBuildingClient | software.amazon.awssdk.services.lexmodelbuilding.LexModelBuildingClient | 
| com.amazonaws.services.lexruntime.AmazonLexRuntimeAsyncClient | software.amazon.awssdk.services.lexruntime.LexRuntimeAsyncClient | 
| com.amazonaws.services.lexruntime.AmazonLexRuntimeClient | software.amazon.awssdk.services.lexruntime.LexRuntimeClient | 
| com.amazonaws.services.lightsail.AmazonLightsailAsyncClient | software.amazon.awssdk.services.lightsail.LightsailAsyncClient | 
| com.amazonaws.services.lightsail.AmazonLightsailClient | software.amazon.awssdk.services.lightsail.LightsailClient | 
| com.amazonaws.services.logs.AWSLogsAsyncClient | software.amazon.awssdk.services.logs.LogsAsyncClient | 
| com.amazonaws.services.logs.AWSLogsClient | software.amazon.awssdk.services.logs.LogsClient | 
| com.amazonaws.services.machinelearning.AmazonMachineLearningAsyncClient | software.amazon.awssdk.services.machinelearning.MachineLearningAsyncClient | 
| com.amazonaws.services.machinelearning.AmazonMachineLearningClient | software.amazon.awssdk.services.machinelearning.MachineLearningClient | 
| com.amazonaws.services.macie.AmazonMacieAsyncClient | software.amazon.awssdk.services.macie.MacieAsyncClient | 
| com.amazonaws.services.macie.AmazonMacieClient | software.amazon.awssdk.services.macie.MacieClient | 
| com.amazonaws.services.marketplacecommerceanalytics.AWSMarketplaceCommerceAnalyticsAsyncClient | software.amazon.awssdk.services.marketplacecommerceanalytics.MarketplaceCommerceAnalyticsAsyncClient | 
| com.amazonaws.services.marketplacecommerceanalytics.AWSMarketplaceCommerceAnalyticsClient | software.amazon.awssdk.services.marketplacecommerceanalytics.MarketplaceCommerceAnalyticsClient | 
| com.amazonaws.services.marketplaceentitlement.AWSMarketplaceEntitlementAsyncClient | software.amazon.awssdk.services.marketplaceentitlement.MarketplaceEntitlementAsyncClient | 
| com.amazonaws.services.marketplaceentitlement.AWSMarketplaceEntitlementClient | software.amazon.awssdk.services.marketplaceentitlement.MarketplaceEntitlementClient | 
| com.amazonaws.services.marketplacemetering.AWSMarketplaceMeteringAsyncClient | software.amazon.awssdk.services.marketplacemetering.MarketplaceMeteringAsyncClient | 
| com.amazonaws.services.marketplacemetering.AWSMarketplaceMeteringClient | software.amazon.awssdk.services.marketplacemetering.MarketplaceMeteringClient | 
| com.amazonaws.services.mediaconvert.AWSMediaConvertAsyncClient | software.amazon.awssdk.services.mediaconvert.MediaConvertAsyncClient | 
| com.amazonaws.services.mediaconvert.AWSMediaConvertClient | software.amazon.awssdk.services.mediaconvert.MediaConvertClient | 
| com.amazonaws.services.medialive.AWSMediaLiveAsyncClient | software.amazon.awssdk.services.medialive.MediaLiveAsyncClient | 
| com.amazonaws.services.medialive.AWSMediaLiveClient | software.amazon.awssdk.services.medialive.MediaLiveClient | 
| com.amazonaws.services.mediapackage.AWSMediaPackageAsyncClient | software.amazon.awssdk.services.mediapackage.MediaPackageAsyncClient | 
| com.amazonaws.services.mediapackage.AWSMediaPackageClient | software.amazon.awssdk.services.mediapackage.MediaPackageClient | 
| com.amazonaws.services.mediastore.AWSMediaStoreAsyncClient | software.amazon.awssdk.services.mediastore.MediaStoreAsyncClient | 
| com.amazonaws.services.mediastore.AWSMediaStoreClient | software.amazon.awssdk.services.mediastore.MediaStoreClient | 
| com.amazonaws.services.mediastoredata.AWSMediaStoreDataAsyncClient | software.amazon.awssdk.services.mediastoredata.MediaStoreDataAsyncClient | 
| com.amazonaws.services.mediastoredata.AWSMediaStoreDataClient | software.amazon.awssdk.services.mediastoredata.MediaStoreDataClient | 
| com.amazonaws.services.mediatailor.AWSMediaTailorAsyncClient | software.amazon.awssdk.services.mediatailor.MediaTailorAsyncClient | 
| com.amazonaws.services.mediatailor.AWSMediaTailorClient | software.amazon.awssdk.services.mediatailor.MediaTailorClient | 
| com.amazonaws.services.migrationhub.AWSMigrationHubAsyncClient | software.amazon.awssdk.services.migrationhub.MigrationHubAsyncClient | 
| com.amazonaws.services.migrationhub.AWSMigrationHubClient | software.amazon.awssdk.services.migrationhub.MigrationHubClient | 
| com.amazonaws.services.mobile.AWSMobileAsyncClient | software.amazon.awssdk.services.mobile.MobileAsyncClient | 
| com.amazonaws.services.mobile.AWSMobileClient | software.amazon.awssdk.services.mobile.MobileClient | 
| com.amazonaws.services.mq.AmazonMQAsyncClient | software.amazon.awssdk.services.mq.MqAsyncClient | 
| com.amazonaws.services.mq.AmazonMQClient | software.amazon.awssdk.services.mq.MqClient | 
| com.amazonaws.services.mturk.AmazonMTurkAsyncClient | software.amazon.awssdk.services.mturk.MTurkAsyncClient | 
| com.amazonaws.services.mturk.AmazonMTurkClient | software.amazon.awssdk.services.mturk.MTurkClient | 
| com.amazonaws.services.neptune.AmazonNeptuneAsyncClient | software.amazon.awssdk.services.neptune.NeptuneAsyncClient | 
| com.amazonaws.services.neptune.AmazonNeptuneClient | software.amazon.awssdk.services.neptune.NeptuneClient | 
| com.amazonaws.services.opsworks.AWSOpsWorksAsyncClient | software.amazon.awssdk.services.opsworks.OpsWorksAsyncClient | 
| com.amazonaws.services.opsworks.AWSOpsWorksClient | software.amazon.awssdk.services.opsworks.OpsWorksClient | 
| com.amazonaws.services.opsworkscm.AWSOpsWorksCMAsyncClient | software.amazon.awssdk.services.opsworkscm.OpsWorksCmAsyncClient | 
| com.amazonaws.services.opsworkscm.AWSOpsWorksCMClient | software.amazon.awssdk.services.opsworkscm.OpsWorksCmClient | 
| com.amazonaws.services.organizations.AWSOrganizationsAsyncClient | software.amazon.awssdk.services.organizations.OrganizationsAsyncClient | 
| com.amazonaws.services.organizations.AWSOrganizationsClient | software.amazon.awssdk.services.organizations.OrganizationsClient | 
| com.amazonaws.services.pi.AWSPIAsyncClient | software.amazon.awssdk.services.pi.PiAsyncClient | 
| com.amazonaws.services.pi.AWSPIClient | software.amazon.awssdk.services.pi.PiClient | 
| com.amazonaws.services.pinpoint.AmazonPinpointAsyncClient | software.amazon.awssdk.services.pinpoint.PinpointAsyncClient | 
| com.amazonaws.services.pinpoint.AmazonPinpointClient | software.amazon.awssdk.services.pinpoint.PinpointClient | 
| com.amazonaws.services.polly.AmazonPollyAsyncClient | software.amazon.awssdk.services.polly.PollyAsyncClient | 
| com.amazonaws.services.polly.AmazonPollyClient | software.amazon.awssdk.services.polly.PollyClient | 
| com.amazonaws.services.pricing.AWSPricingAsyncClient | software.amazon.awssdk.services.pricing.PricingAsyncClient | 
| com.amazonaws.services.pricing.AWSPricingClient | software.amazon.awssdk.services.pricing.PricingClient | 
| com.amazonaws.services.rds.AmazonRDSAsyncClient | software.amazon.awssdk.services.rds.RdsAsyncClient | 
| com.amazonaws.services.rds.AmazonRDSClient | software.amazon.awssdk.services.rds.RdsClient | 
| com.amazonaws.services.redshift.AmazonRedshiftAsyncClient | software.amazon.awssdk.services.redshift.RedshiftAsyncClient | 
| com.amazonaws.services.redshift.AmazonRedshiftClient | software.amazon.awssdk.services.redshift.RedshiftClient | 
| com.amazonaws.services.rekognition.AmazonRekognitionAsyncClient | software.amazon.awssdk.services.rekognition.RekognitionAsyncClient | 
| com.amazonaws.services.rekognition.AmazonRekognitionClient | software.amazon.awssdk.services.rekognition.RekognitionClient | 
| com.amazonaws.services.resourcegroups.AWSResourceGroupsAsyncClient | software.amazon.awssdk.services.resourcegroups.ResourceGroupsAsyncClient | 
| com.amazonaws.services.resourcegroups.AWSResourceGroupsClient | software.amazon.awssdk.services.resourcegroups.ResourceGroupsClient | 
| com.amazonaws.services.resourcegroupstaggingapi.AWSResourceGroupsTaggingAPIAsyncClient | software.amazon.awssdk.services.resourcegroupstaggingapi.ResourceGroupsTaggingApiAsyncClient | 
| com.amazonaws.services.resourcegroupstaggingapi.AWSResourceGroupsTaggingAPIClient | software.amazon.awssdk.services.resourcegroupstaggingapi.ResourceGroupsTaggingApiClient | 
| com.amazonaws.services.route53.AmazonRoute53AsyncClient | software.amazon.awssdk.services.route53.Route53AsyncClient | 
| com.amazonaws.services.route53.AmazonRoute53Client | software.amazon.awssdk.services.route53.Route53Client | 
| com.amazonaws.services.route53domains.AmazonRoute53DomainsAsyncClient | software.amazon.awssdk.services.route53domains.Route53DomainsAsyncClient | 
| com.amazonaws.services.route53domains.AmazonRoute53DomainsClient | software.amazon.awssdk.services.route53domains.Route53DomainsClient | 
| com.amazonaws.services.s3.AmazonS3Client | software.amazon.awssdk.services.s3.S3Client | 
| com.amazonaws.services.sagemaker.AmazonSageMakerAsyncClient | software.amazon.awssdk.services.sagemaker.SageMakerAsyncClient | 
| com.amazonaws.services.sagemaker.AmazonSageMakerClient | software.amazon.awssdk.services.sagemaker.SageMakerClient | 
| com.amazonaws.services.sagemakerruntime.AmazonSageMakerRuntimeAsyncClient | software.amazon.awssdk.services.sagemakerruntime.SageMakerRuntimeAsyncClient | 
| com.amazonaws.services.sagemakerruntime.AmazonSageMakerRuntimeClient | software.amazon.awssdk.services.sagemakerruntime.SageMakerRuntimeClient | 
| com.amazonaws.services.secretsmanager.AWSSecretsManagerAsyncClient | software.amazon.awssdk.services.secretsmanager.SecretsManagerAsyncClient | 
| com.amazonaws.services.secretsmanager.AWSSecretsManagerClient | software.amazon.awssdk.services.secretsmanager.SecretsManagerClient | 
| com.amazonaws.services.securitytoken.AWSSecurityTokenServiceAsyncClient | software.amazon.awssdk.services.sts.StsAsyncClient | 
| com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient | software.amazon.awssdk.services.sts.StsClient | 
| com.amazonaws.services.serverlessapplicationrepository.AWSServerlessApplicationRepositoryAsyncClient | software.amazon.awssdk.services.serverlessapplicationrepository.ServerlessApplicationRepositoryAsyncClient | 
| com.amazonaws.services.serverlessapplicationrepository.AWSServerlessApplicationRepositoryClient | software.amazon.awssdk.services.serverlessapplicationrepository.ServerlessApplicationRepositoryClient | 
| com.amazonaws.services.servermigration.AWSServerMigrationAsyncClient | software.amazon.awssdk.services.sms.SmsAsyncClient | 
| com.amazonaws.services.servermigration.AWSServerMigrationClient | software.amazon.awssdk.services.sms.SmsClient | 
| com.amazonaws.services.servicecatalog.AWSServiceCatalogAsyncClient | software.amazon.awssdk.services.servicecatalog.ServiceCatalogAsyncClient | 
| com.amazonaws.services.servicecatalog.AWSServiceCatalogClient | software.amazon.awssdk.services.servicecatalog.ServiceCatalogClient | 
| com.amazonaws.services.servicediscovery.AWSServiceDiscoveryAsyncClient | software.amazon.awssdk.services.servicediscovery.ServiceDiscoveryAsyncClient | 
| com.amazonaws.services.servicediscovery.AWSServiceDiscoveryClient | software.amazon.awssdk.services.servicediscovery.ServiceDiscoveryClient | 
| com.amazonaws.services.shield.AWSShieldAsyncClient | software.amazon.awssdk.services.shield.ShieldAsyncClient | 
| com.amazonaws.services.shield.AWSShieldClient | software.amazon.awssdk.services.shield.ShieldClient | 
| com.amazonaws.services.simpledb.AmazonSimpleDBAsyncClient | software.amazon.awssdk.services.simpledb.SimpleDbAsyncClient | 
| com.amazonaws.services.simpledb.AmazonSimpleDBClient | software.amazon.awssdk.services.simpledb.SimpleDbClient | 
| com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceAsyncClient | software.amazon.awssdk.services.ses.SesAsyncClient | 
| com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient | software.amazon.awssdk.services.ses.SesClient | 
| com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementAsyncClient | software.amazon.awssdk.services.ssm.SsmAsyncClient | 
| com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClient | software.amazon.awssdk.services.ssm.SsmClient | 
| com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowAsyncClient | software.amazon.awssdk.services.swf.SwfAsyncClient | 
| com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient | software.amazon.awssdk.services.swf.SwfClient | 
| com.amazonaws.services.snowball.AmazonSnowballAsyncClient | software.amazon.awssdk.services.snowball.SnowballAsyncClient | 
| com.amazonaws.services.snowball.AmazonSnowballClient | software.amazon.awssdk.services.snowball.SnowballClient | 
| com.amazonaws.services.sns.AmazonSNSAsyncClient | software.amazon.awssdk.services.sns.SnsAsyncClient | 
| com.amazonaws.services.sns.AmazonSNSClient | software.amazon.awssdk.services.sns.SnsClient | 
| com.amazonaws.services.sqs.AmazonSQSAsyncClient | software.amazon.awssdk.services.sqs.SqsAsyncClient | 
| com.amazonaws.services.sqs.AmazonSQSClient | software.amazon.awssdk.services.sqs.SqsClient | 
| com.amazonaws.services.stepfunctions.AWSStepFunctionsAsyncClient | software.amazon.awssdk.services.sfn.SfnAsyncClient | 
| com.amazonaws.services.stepfunctions.AWSStepFunctionsClient | software.amazon.awssdk.services.sfn.SfnClient | 
| com.amazonaws.services.storagegateway.AWSStorageGatewayAsyncClient | software.amazon.awssdk.services.storagegateway.StorageGatewayAsyncClient | 
| com.amazonaws.services.storagegateway.AWSStorageGatewayClient | software.amazon.awssdk.services.storagegateway.StorageGatewayClient | 
| com.amazonaws.services.support.AWSSupportAsyncClient | software.amazon.awssdk.services.support.SupportAsyncClient | 
| com.amazonaws.services.support.AWSSupportClient | software.amazon.awssdk.services.support.SupportClient | 
| com.amazonaws.services.transcribe.AmazonTranscribeAsyncClient | software.amazon.awssdk.services.transcribe.TranscribeAsyncClient | 
| com.amazonaws.services.transcribe.AmazonTranscribeClient | software.amazon.awssdk.services.transcribe.TranscribeClient | 
| com.amazonaws.services.translate.AmazonTranslateAsyncClient | software.amazon.awssdk.services.translate.TranslateAsyncClient | 
| com.amazonaws.services.translate.AmazonTranslateClient | software.amazon.awssdk.services.translate.TranslateClient | 
| com.amazonaws.services.waf.AWSWAFAsyncClient | software.amazon.awssdk.services.waf.WafAsyncClient | 
| com.amazonaws.services.waf.AWSWAFClient | software.amazon.awssdk.services.waf.WafClient | 
| com.amazonaws.services.waf.AWSWAFRegionalAsyncClient | software.amazon.awssdk.services.waf.regional.WafRegionalAsyncClient | 
| com.amazonaws.services.waf.AWSWAFRegionalClient | software.amazon.awssdk.services.waf.regional.WafRegionalClient | 
| com.amazonaws.services.workdocs.AmazonWorkDocsAsyncClient | software.amazon.awssdk.services.workdocs.WorkDocsAsyncClient | 
| com.amazonaws.services.workdocs.AmazonWorkDocsClient | software.amazon.awssdk.services.workdocs.WorkDocsClient | 
| com.amazonaws.services.workmail.AmazonWorkMailAsyncClient | software.amazon.awssdk.services.workmail.WorkMailAsyncClient | 
| com.amazonaws.services.workmail.AmazonWorkMailClient | software.amazon.awssdk.services.workmail.WorkMailClient | 
| com.amazonaws.services.workspaces.AmazonWorkspacesAsyncClient | software.amazon.awssdk.services.workspaces.WorkSpacesAsyncClient | 
| com.amazonaws.services.workspaces.AmazonWorkspacesClient | software.amazon.awssdk.services.workspaces.WorkSpacesClient | 
| com.amazonaws.services.xray.AWSXRayAsyncClient | software.amazon.awssdk.services.xray.XRayAsyncClient | 
| com.amazonaws.services.xray.AWSXRayClient | software.amazon.awssdk.services.xray.XRayClient | 

# Client creation defaults
<a name="client-creation-defaults"></a>

In version 2.x, the following changes have been made to the default client creation logic.
+ The default credential provider chain for S3 no longer includes anonymous credentials. You must manually specify anonymous access to S3 by using the `AnonymousCredentialsProvider`.
+ The following environment variables related to default client creation are different.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/client-creation-defaults.html)
+ The following system properties related to default client creation are different.     
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/client-creation-defaults.html)
+ Version 2.x does not support the following system properties.
+     
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/client-creation-defaults.html)
+ Loading Region configuration from a custom `endpoints.json` file is no longer supported.

# Client configuration
<a name="client-configuration"></a>

In 1.x, SDK client configuration was modified by setting a `ClientConfiguration` instance on the client or client builder. In version 2.x, the client configuration is split into separate configuration classes. With the separate configuration classes, you can configure different HTTP clients for async versus synchronous clients but still use the same `ClientOverrideConfiguration` class.

**Example of client configuration in version 1.x**  

```
AmazonDynamoDBClientBuilder.standard()
.withClientConfiguration(clientConfiguration)
.build()
```

**Example of synchronous client configuration in version 2.x**  

```
ProxyConfiguration.Builder proxyConfig = ProxyConfiguration.builder();

ApacheHttpClient.Builder httpClientBuilder =
        ApacheHttpClient.builder()
                        .proxyConfiguration(proxyConfig.build());

ClientOverrideConfiguration.Builder overrideConfig =
        ClientOverrideConfiguration.builder();

DynamoDbClient client =
        DynamoDbClient.builder()
                      .httpClientBuilder(httpClientBuilder)
                      .overrideConfiguration(overrideConfig.build())
                      .build();
```

**Example of asynchronous client configuration in version 2.x**  

```
NettyNioAsyncHttpClient.Builder httpClientBuilder =
        NettyNioAsyncHttpClient.builder();

ClientOverrideConfiguration.Builder overrideConfig =
        ClientOverrideConfiguration.builder();

ClientAsyncConfiguration.Builder asyncConfig =
        ClientAsyncConfiguration.builder();

DynamoDbAsyncClient client =
        DynamoDbAsyncClient.builder()
                           .httpClientBuilder(httpClientBuilder)
                           .overrideConfiguration(overrideConfig.build())
                           .asyncConfiguration(asyncConfig.build())
                           .build();
```

## HTTP clients
<a name="client-configuration-http"></a>

### Notable changes
<a name="client-configuration-http-notables"></a>
+ In version 2.x, you can change which HTTP client to use at runtime by specifying an implementation using `clientBuilder.httpClientBuilder`.
+ When you pass an HTTP client by using `clientBuilder.httpClient` to a service client builder, the HTTP client is not closed by default if the service client closes. This allows you to share HTTP clients between service clients.
+ Asynchronous HTTP clients now use non-blocking IO.
+ Some operations now use HTTP/2 for improved performance.

### Settings changes
<a name="client-configuration-http-setting-diffs"></a>


| Setting | 1.x | 2.x Sync, Apache | 2.x Async, Netty | 
| --- | --- | --- | --- | 
|  |  <pre>ClientConfiguration clientConfig = <br />    new ClientConfiguration()</pre>  |  <pre>ApacheHttpClient.Builder httpClientBuilder = <br />    ApacheHttpClient.builder()</pre>  |  <pre>NettyNioAsyncHttpClient.Builder httpClientBuilder = <br />    NettyNioAsyncHttpClient.builder()</pre>  | 
| Max connections |  <pre>clientConfig.setMaxConnections(...)<br />clientConfig.withMaxConnections(...)</pre>  |  <pre>httpClientBuilder.maxConnections(...)</pre>  |  <pre>httpClientBuilder.maxConcurrency(...)</pre>  | 
| Connection timeout |  <pre>clientConfig.setConnectionTimeout(...)<br />clientConfig.withConnectionTimeout(...)</pre>  |  <pre>httpClientBuilder.connectionTimeout(...)<br />httpClientBuilder.connectionAcquisitionTimeout(...)</pre>  |  <pre>httpClientBuilder.connectionTimeout(...)</pre>  | 
| Socket timeout |  <pre>clientConfig.setSocketTimeout(...)<br />clientConfig.withSocketTimeout(...)</pre>  |  <pre>httpClientBuilder.socketTimeout(...)</pre>  |  <pre>httpClientBuilder.writeTimeout(...)<br />httpClientBuilder.readTimeout(...)</pre>  | 
| Connection TTL |  <pre>clientConfig.setConnectionTTL(...)<br />clientConfig.withConnectionTTL(...)</pre>  |  <pre>httpClientBuilder.connectionTimeToLive(...)</pre>  |  <pre>httpClientBuilder.connectionTimeToLive(...)</pre>  | 
| Connection max idle |  <pre>clientConfig.setConnectionMaxIdleMillis(...)<br />clientConfig.withConnectionMaxIdleMillis(...)</pre>  |  <pre>httpClientBuilder.connectionMaxIdleTime(...)</pre>  |  <pre>httpClientBuilder.connectionMaxIdleTime(...)</pre>  | 
| Validate after inactivity |  <pre>clientConfig.setValidateAfterInactivityMillis(...)<br />clientConfig.withValidateAfterInactivityMillis(...)</pre>  | Not supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | Not supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| Local address |  <pre>clientConfig.setLocalAddress(...)<br />clientConfig.withLocalAddress(...)</pre>  |  <pre>httpClientBuilder.localAddress(...)</pre>  | [Not supported](https://github.com/aws/aws-sdk-java-v2/issues/857) | 
| Expect-continue enabled |  <pre>clientConfig.setUseExpectContinue(...)<br />clientConfig.withUseExpectContinue(...)</pre>  |  <pre>httpClientBuilder.expectContinueEnabled(...)</pre>  | Not supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| Connection reaper |  <pre>clientConfig.setUseReaper(...)<br />clientConfig.withReaper(...)</pre>  |  <pre>httpClientBuilder.useIdleConnectionReaper(...)</pre>  |  <pre>httpClientBuilder.useIdleConnectionReaper(...)</pre>  | 
|  |  <pre>AmazonDynamoDBClientBuilder.standard()<br />    .withClientConfiguration(clientConfiguration)<br />    .build()</pre>  |  <pre>DynamoDbClient.builder()<br />    .httpClientBuilder(httpClientBuilder)<br />    .build()</pre>  |  <pre>DynamoDbAsyncClient.builder()<br />.httpClientBuilder(httpClientBuilder)<br />.build()</pre>  | 

## HTTP client proxies
<a name="client-configuration-http-proxy"></a>


| Settings | 1.x | 2.x Sync, Apache | 2.x Async, Netty | 
| --- | --- | --- | --- | 
|  |  <pre>ClientConfiguration clientConfig =<br />    new ClientConfiguration()</pre>  |  <pre>ProxyConfiguration.Builder proxyConfig =<br />    ProxyConfiguration.builder()</pre>  |  <pre>ProxyConfiguration.Builder proxyConfig =<br />    ProxyConfiguration.builder()</pre>  | 
| Proxy host |  <pre>clientConfig.setProxyHost(...)<br />clientConfig.withProxyHost(...)</pre>  |  <pre>proxyConfig.endpoint(...)</pre>  |  <pre>proxyConfig.host(...)</pre>  | 
| Proxy port |  <pre>clientConfig.setProxyPort(...)<br />clientConfig.withProxyPort(...)</pre>  |  <pre>proxyConfig.endpoint(...)</pre> [Proxy port](http-configuration-apache.md#http-configuration-apache-proxy-conf-ex) is embedded in `endpoint`  |  <pre>proxyConfig.port(...)</pre>  | 
| Proxy username |  <pre>clientConfig.setProxyUsername(...)<br />clientConfig.withProxyUsername(...)</pre>  |  <pre>proxyConfig.username(...)</pre>  |  <pre>proxyConfig.username(...)</pre>  | 
| Proxy password |  <pre>clientConfig.setProxyPassword(...)<br />clientConfig.withProxyPassword(...)</pre>  |  <pre>proxyConfig.password(...)</pre>  |  <pre>proxyConfig.password(...)</pre>  | 
| Proxy domain |  <pre>clientConfig.setProxyDomain(...)<br />clientConfig.withProxyDomain(...)</pre>  |  <pre>proxyConfig.ntlmDomain(...)</pre>  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| Proxy workstation |  <pre>clientConfig.setProxyWorkspace(...)<br />clientConfig.withProxyWorkstation(...)</pre>  |  <pre>proxyConfig.ntlmWorkstation(...)</pre>  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| Proxy authentication methods |  <pre>clientConfig.setProxyAuthenticationMethods(...)<br />clientConfig.withProxyAuthenticationMethods(...)</pre>  |  [Not Supported](https://github.com/aws/aws-sdk-java-v2/issues/858)  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| Preemptive basic proxy authentication |  <pre>clientConfig.setPreemptiveBasicProxyAuth(...)<br />clientConfig.withPreemptiveBasicProxyAuth(...)</pre>  |  <pre>proxyConfig.preemptiveBasicAuthenticationEnabled(...)</pre>  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| Non-proxy hosts |  <pre>clientConfig.setNonProxyHosts(...)<br />clientConfig.withNonProxyHosts(...)</pre>  |  <pre>proxyConfig.nonProxyHosts(...)</pre>  |  <pre>proxyConfig.nonProxyHosts(...)</pre>  | 
| Disable socket proxy |  <pre>clientConfig.setDisableSocketProxy(...)<br />clientConfig.withDisableSocketProxy(...)</pre>  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
|  |  <pre>AmazonDynamoDBClientBuilder.standard()<br />    .withClientConfiguration(clientConfiguration)<br />    .build()</pre>  |  <pre>httpClientBuilder.proxyConfiguration(<br />    proxyConfig.build())</pre>  |  <pre>httpClientBuilder.proxyConfiguration(<br />    proxyConfig.build())</pre>  | 

## Client overrides
<a name="client-override-config-diffs"></a>


| Setting | 1.x | 2.x | 
| --- | --- | --- | 
|  |  <pre>ClientConfiguration clientConfig =<br />    new ClientConfiguration()</pre>  |  <pre>ClientOverrideConfiguration.Builder overrideConfig =<br />    ClientOverrideConfiguration.builder()</pre>  | 
| User agent prefix |  <pre>clientConfig.setUserAgentPrefix(...)<br />clientConfig.withUserAgentPrefix(...)</pre>  |  <pre>overrideConfig.advancedOption(<br />    SdkAdvancedClientOption.USER_AGENT_PREFIX, ...)</pre>  | 
| User agent suffix |  <pre>clientConfig.setUserAgentSuffix(...)<br />clientConfig.withUserAgentSuffix(...)</pre>  |  <pre>overrideConfig.advancedOption(<br />    SdkAdvancedClientOption.USER_AGENT_SUFFIX, ...)</pre>  | 
| Signer |  <pre>clientConfig.setSignerOverride(...)<br />clientConfig.withSignerOverride(...)</pre>  |  <pre>overrideConfig.advancedOption(<br />    SdkAdvancedClientOption.SIGNER, ...)</pre>  | 
| Additional headers |  <pre>clientConfig.addHeader(...)<br />clientConfig.withHeader(...)</pre>  |  <pre>overrideConfig.putHeader(...)</pre>  | 
| Request timeout |  <pre>clientConfig.setRequestTimeout(...)<br />clientConfig.withRequestTimeout(...)</pre>  |  <pre>overrideConfig.apiCallAttemptTimeout(...)</pre>  | 
| Client execution timeout |  <pre>clientConfig.setClientExecutionTimeout(...)<br />clientConfig.withClientExecutionTimeout(...)</pre>  |  <pre>overrideConfig.apiCallTimeout(...)</pre>  | 
| Use Gzip |  <pre>clientConfig.setUseGzip(...)<br />clientConfig.withGzip(...)</pre>  |  Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new))  | 
| Socket buffer size hint |  <pre>clientConfig.setSocketBufferSizeHints(...)<br />clientConfig.withSocketBufferSizeHints(...)</pre>  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| Cache response metadata |  <pre>clientConfig.setCacheResponseMetadata(...)<br />clientConfig.withCacheResponseMetadata(...)</pre>  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| Response metadata cache size |  <pre>clientConfig.setResponseMetadataCacheSize(...)<br />clientConfig.withResponseMetadataCacheSize(...)</pre>  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| DNS resolver |  <pre>clientConfig.setDnsResolver(...)<br />clientConfig.withDnsResolver(...)</pre>  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
| TCP keepalive |  <pre>clientConfig.setUseTcpKeepAlive(...)<br />clientConfig.withTcpKeepAlive(...)</pre>  |  This option is now in the HTTP Client configuration <pre>- ApacheHttpClient.builder().tcpKeepAlive(true)<br />- NettyNioAsyncHttpClient.builder().tcpKeepAlive(true)</pre>  | 
| Secure random |  <pre>clientConfig.setSecureRandom(...)<br />clientConfig.withSecureRandom(...)</pre>  | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
|  |  <pre>AmazonDynamoDBClientBuilder.standard()<br />    .withClientConfiguration(clientConfiguration)<br />    .build()</pre>  |  <pre>DynamoDbClient.builder()<br />    .overrideConfiguration(overrideConfig.build())<br />    .build()</pre>  | 

## Client override retries
<a name="client-override-retry-config-diffs"></a>


| Setting | 1.x | 2.x | 
| --- | --- | --- | 
|  |  <pre>ClientConfiguration clientConfig =<br />    new ClientConfiguration()</pre>  |  <pre>ClientOverrideConfiguration.Builder overrideConfigBuilder = <br />    ClientOverrideConfiguration.builder();</pre>  | 
| Max error retry |  <pre>clientConfig.setMaxErrorRetry(...)<br />clientConfig.withMaxErrorRetry(...)</pre>  |  <pre>// Configure the default retry strategy.<br />overrideConfigBuilder.retryStrategy(b -> b.maxAttempts(...));</pre>  | 
| Use throttled retries |  <pre>clientConfig.setUseThrottleRetries(...)<br />clientConfig.withUseThrottleRetries(...)</pre>  | [Not supported](https://github.com/aws/aws-sdk-java-v2/issues/645) | 
| Max consecutive retries before throttling |  <pre>clientConfig.setMaxConsecutiveRetriesBeforeThrottling(...)<br />clientConfig.withMaxConsecutiveRetriesBeforeThrottling(...)</pre>  | [Not supported](https://github.com/aws/aws-sdk-java-v2/issues/645) | 
|  |  <pre>AmazonDynamoDBClientBuilder.standard()<br />    .withClientConfiguration(clientConfiguration)<br />    .build()</pre>  |  <pre>DynamoDbClient.builder()<br />        .overrideConfiguration(overrideConfigBuilder.build())<br />        .build();<br /><br />// You also have the option to use a lambda expression to configure and<br />// build the 'ClientOverrideConfiguration.Builder'.<br />DynamoDbClient client = DynamoDbClient.builder()<br />        .overrideConfiguration(o -> o.retryStrategy(b -> b.maxAttempts(5)))<br />        .build();</pre>  | 

## Asynchronous clients
<a name="client-async-config-diffs"></a>


| Setting | 1.x | 2.x | 
| --- | --- | --- | 
|  |  |  <pre>ClientAsyncConfiguration.Builder asyncConfig =<br />    ClientAsyncConfiguration.builder()</pre>  | 
| Executor |  <pre>AmazonDynamoDBAsyncClientBuilder.standard()<br />    .withExecutorFactory(...)<br />    .build()</pre>  |  <pre>asyncConfig.advancedOption(<br />    SdkAdvancedAsyncClientOption.FUTURE_COMPLETION_EXECUTOR, ...)</pre>  | 
|  |  |  <pre>DynamoDbAsyncClient.builder()<br />    .asyncConfiguration(asyncConfig)<br />    .build()</pre>  | 

## Other client changes
<a name="client-config-other-diffs"></a>

The following `ClientConfiguration` option from 1.x has changed in 2.x of the SDK and doesn't have a direct equivalent.


| Setting | 1.x | 2.x equivalent | 
| --- | --- | --- | 
| Protocol |  <pre>clientConfig.setProtocol(Protocol.HTTP)<br />clientConfig.withProtocol(Protocol.HTTP)</pre>  |  The protocol setting is HTTPS by default. To modify the setting, specify the protocol setting an HTTP endpoint on the client builder: <pre>clientBuilder.endpointOverride(<br />    URI.create("http://..."))</pre>  | 

# Credentials provider changes
<a name="migration-client-credentials"></a>

This section provides a mapping of the name changes of credentials provider classes and methods between versions 1.x and 2.x of the AWS SDK for Java. 

## Notable differences
<a name="client-credentials"></a>
+ The default credentials provider loads system properties before environment variables in version 2.x. For more information, see [Using credentials](credentials.md).
+ The constructor method is replaced with the `create` or `builder` methods.  
**Example**  

  ```
  DefaultCredentialsProvider.create();
  ```
+ Asynchronous refresh is no longer set by default. You must specify it with the `builder` of the credentials provider.  
**Example**  

  ```
  ContainerCredentialsProvider provider = ContainerCredentialsProvider.builder()
          		.asyncCredentialUpdateEnabled(true)
          		.build();
  ```
+ You can specify a path to a custom profile file using the `ProfileCredentialsProvider.builder()`.  
**Example**  

  ```
  ProfileCredentialsProvider profile = ProfileCredentialsProvider.builder()
          		.profileFile(ProfileFile.builder().content(Paths.get("myProfileFile.file")).build())
          		.build();
  ```
+ Profile file format has changed to more closely match the AWS CLI. For details, see [Configuring the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) in the *AWS Command Line Interface User Guide*.

## Credentials provider changes mapped between versions 1.x and 2.x
<a name="credentials-changes-mapping"></a>

### `AWSCredentialsProvider`
<a name="credentials-provider-changes-AWSCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.AWSCredentialsProvider | software.amazon.awssdk.auth.credentials.AwsCredentialsProvider | 
| Method name | getCredentials | resolveCredentials | 
| Unsupported method | refresh | Not supported | 

### `DefaultAWSCredentialsProviderChain`
<a name="credentials-provider-changes-DefaultAWSCredentialsProviderChain"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.DefaultAWSCredentialsProviderChain | software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider | 
| Creation | new DefaultAWSCredentialsProviderChain | DefaultCredentialsProvider.create | 
| Unsupported method | getInstance | Not supported | 
| Priority order of external settings |  Environment variables before system properties  |  System properties before environment variables  | 

### `AWSStaticCredentialsProvider`
<a name="credentials-provider-changes-AWSStaticCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.AWSStaticCredentialsProvider | software.amazon.awssdk.auth.credentials.StaticCredentialsProvider | 
| Creation | new AWSStaticCredentialsProvider | StaticCredentialsProvider.create | 

### `EnvironmentVariableCredentialsProvider`
<a name="credentials-provider-changes-EnvironmentVariableCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.EnvironmentVariableCredentialsProvider | software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider | 
| Creation | new EnvironmentVariableCredentialsProvider | EnvironmentVariableCredentialsProvider.create | 
| Environment variable name | AWS\$1ACCESS\$1KEY | AWS\$1ACCESS\$1KEY\$1ID | 
|  | AWS\$1SECRET\$1KEY | AWS\$1SECRET\$1ACCESS\$1KEY | 

### `SystemPropertiesCredentialsProvider`
<a name="credentials-provider-changes-SystemPropertiesCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.SystemPropertiesCredentialsProvider | software.amazon.awssdk.auth.credentials.SystemPropertyCredentialsProvider | 
| Creation | new SystemPropertiesCredentialsProvider | SystemPropertiesCredentialsProvider.create | 
| System property name | aws.secretKey | aws.secretAccessKey | 

### `ProfileCredentialsProvider`
<a name="credentials-provider-changes-ProfileCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.profile.ProfileCredentialsProvider | software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider | 
| Creation | new ProfileCredentialsProvider | ProfileCredentialsProvider.create | 
| Location of custom profile |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-client-credentials.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-client-credentials.html)  | 

### `ContainerCredentialsProvider`
<a name="credentials-provider-changes-ContainerCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.ContainerCredentialsProvider | software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider | 
| Creation | new ContainerCredentialsProvider | ContainerCredentialsProvider.create | 
| Specify asynchronous refresh | Not supported | Default behavior | 

### `InstanceProfileCredentialsProvider`
<a name="credentials-provider-changes-InstanceProfileCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.InstanceProfileCredentialsProvider | software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider | 
| Creation | new InstanceProfileCredentialsProvider | InstanceProfileCredentialsProvider.create | 
| Specify asynchronous refresh | new InstanceProfileCredentialsProvider(true) |  `InstanceProfileCredentialProvider.builder().asyncCredentialUpdateEnabled(true).build()`  | 
| System property name | com.amazonaws.sdk.disableEc2Metadata | aws.disableEc2Metadata | 
|  | com.amazonaws.sdk.ec2MetadataServiceEndpointOverride | aws.ec2MetadataServiceEndpoint | 

### `STSAssumeRoleSessionCredentialsProvider`
<a name="credentials-provider-changes-STSAssumeRoleSessionCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider | software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider | 
| Creation |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-client-credentials.html)  | StsAssumeRoleCredentialsProvider.builder | 
| Asynchronous refresh | Default behavior | Default behavior | 
| Configuration | new STSAssumeRoleSessionCredentialsProvider.Builder | Configure a StsClient and AssumeRoleRequest request | 

### `STSSessionCredentialsProvider`
<a name="credentials-provider-changes-STSSessionCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.STSSessionCredentialsProvider | software.amazon.awssdk.services.sts.auth.StsGetSessionTokenCredentialsProvider | 
| Creation |  `new STSSessionCredentialsProvider`  | StsGetSessionTokenCredentialsProvider.builder | 
| Asynchronous refresh | Default behavior | StsGetSessionTokenCredentialsProvider.builder | 
| Configuration | Constructor parameters | Configure an StsClient and GetSessionTokenRequest request in a builder | 

### `WebIdentityFederationSessionCredentialsProvider`
<a name="credentials-provider-changes-WebIdentityFederationSessionCredentialsProvider"></a>


| Change category | 1.x | 2.x | 
| --- | --- | --- | 
| Package/class name | com.amazonaws.auth.WebIdentityFederationSessionCredentialsProvider | software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithWebIdentityCredentialsProvider | 
| Creation |  `new WebIdentityFederationSessionCredentialsProvider`  | StsAssumeRoleWithWebIdentityCredentialsProvider.builder | 
| Asynchronous refresh | Default behavior | StsAssumeRoleWithWebIdentityCredentialsProvider.builder | 
| Configuration | Constructor parameters | Configure an StsClient and AssumeRoleWithWebIdentityRequest request in a builder | 

### Classes replaced
<a name="credentials-provider-changes-Replacements"></a>


| 1.x class | 2.x replacement classes | 
| --- | --- | 
| com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper | software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider and software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider | 
| com.amazonaws.services.s3.S3CredentialsProviderChain | software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider and software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider | 

### Classes removed
<a name="credentials-provider-changes-Removed"></a>


| 1.x class | 
| --- | 
| com.amazonaws.auth.ClasspathPropertiesFileCredentialsProvider | 
| com.amazonaws.auth.PropertiesFileCredentialsProvider | 

# Region changes
<a name="migration-client-region"></a>

This section describes the changes implemented in the AWS SDK for Java 2.x for using the `Region` and `Regions` classes.

## Region configuration
<a name="region-configuration"></a>
+ Some AWS services don’t have Region specific endpoints. When using those services, you must set the Region as `Region.AWS_GLOBAL` or `Region.AWS_CN_GLOBAL`.  
**Example**  

  ```
  Region region = Region.AWS_GLOBAL;
  ```
+  `com.amazonaws.regions.Regions` and `com.amazonaws.regions.Region` classes are now combined into one class, `software.amazon.awssdk.regions.Region`.

## Method and class name mappings
<a name="region-method-mapping"></a>

The following tables map Region related classes between versions 1.x and 2.x of the AWS SDK for Java. You can create an instance of these classes using the `of()` method.

**Example**  

```
RegionMetadata regionMetadata = RegionMetadata.of(Region.US_EAST_1);
```


**1.x Regions class method changes**  

| 1.x | 2.x | 
| --- | --- | 
|  `Regions.fromName`  |  `Region.of`  | 
|  `Regions.getName`  |  `Region.id`  | 
|  `Regions.getDescription`  |  `Region.metadata().description()`  | 
|  `Regions.getCurrentRegion`  |  Not Supported  | 
|  `Regions.DEFAULT_REGION`  |  Not Supported  | 
|  `Regions.name`  |  `Region.id`  | 


**1.x Region class method changes**  

| 1.x | 2.x | 
| --- | --- | 
|  `Region.getName`  |  `Region.id`  | 
|  `Region.hasHttpsEndpoint`  |  Not Supported  | 
|  `Region.hasHttpEndpoint`  |  Not Supported  | 
|  `Region.getAvailableEndpoints`  |  Not Supported  | 
|  `Region.createClient`  |  Not Supported  | 


**RegionMetadata class method changes**  

| 1.x | 2.x | 
| --- | --- | 
|  `RegionMetadata.getName`  |  `RegionMetadata.name`  | 
|  `RegionMetadata.getDomain`  |  `RegionMetadata.domain`  | 
|  `RegionMetadata.getPartition`  |  `RegionMetadata.partition`  | 


**ServiceMetadata class method changes**  

| 1.x | 2.x | 
| --- | --- | 
|  `Region.getServiceEndpoint`  |  `ServiceMetadata.endpointFor(Region)`  | 
|  `Region.isServiceSupported`  |  `ServiceMetadata.regions().contains(Region)`  | 

# Operations, requests and responses changes
<a name="migration-operation-requests-responses"></a>

In version 2 of the SDK for Java, requests are passed to a client operation. For example `DynamoDbClient's` `PutItemRequest` is passed to `DynamoDbClient.putItem` operation. These operations return a response from the AWS service, such as a `PutItemResponse`.

Version 2 of the SDK for Java has the following changes from version 1.
+ Operations with multiple response pages now have a `Paginator` method for automatically iterating over all items in the response.
+ You cannot mutate requests and responses.
+ You must create requests and responses with a static builder method instead of a constructor. For example, version 1's `new PutItemRequest().withTableName(...)` is now `PutItemRequest.builder().tableName(...).build()`.
+ Operations support a short-hand way to create requests: `dynamoDbClient.putItem(request -> request.tableName(...))`.

The following sections describe specific changes between version 1 and version 2. Some parameter type changes can be converted automatically using the [migration tool](migration-tool.md), while other changes require manual updates to your code.

# Date parameter changes
<a name="migration-date-parameters"></a>

In version 1, many operations accepted `java.util.Date` objects for time-based parameters. In version 2, these operations use `java.time.Instant` objects instead.

You can convert `Date` parameters automatically using the [migration tool](migration-tool.md), or you can convert them manually by calling the `toInstant()` method on your `Date` object.

**Example - Generate a presigned URL with an expiration date in version 1**  

```
// Generate a presigned URL that expires at a specific date
Date expiration = new Date(System.currentTimeMillis() + 3600000); // 1 hour from now
URL presignedUrl = s3Client.generatePresignedUrl(bucketName, keyName, expiration);
```

**Example - Generate a presigned URL with an expiration instant in version 2**  

```
// Generate a presigned URL that expires at a specific instant
Date expiration = new Date(System.currentTimeMillis() + 3600000); // 1 hour from now
PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(
    GetObjectPresignRequest.builder()
        .getObjectRequest(GetObjectRequest.builder()
            .bucket(bucketName)
            .key(keyName)
            .build())
        .signatureDuration(Duration.between(Instant.now(), expiration.toInstant()))
        .build());
```

# Binary data handling changes
<a name="migration-binary-data"></a>

In version 1, binary data was handled using `ByteBuffer` objects directly. In version 2, the SDK uses `SdkBytes` objects that provide a more convenient and type-safe way to work with binary data.

You can convert `SdkBytes` to `ByteBuffer` automatically using the [migration tool](migration-tool.md), or you can convert them manually by calling `asByteBuffer()` on the returned `SdkBytes` object.

**Example - Get binary data from a message attribute in version 1**  

```
// Get binary data from a message attribute
MessageAttributeValue messageAttributeValue = new MessageAttributeValue();
ByteBuffer binaryValue = messageAttributeValue.getBinaryValue();
String binaryString = new String(messageAttributeValue.getBinaryValue().array());
```

**Example - Get binary data from a message attribute in version 2**  

```
// Get binary data from a message attribute
MessageAttributeValue messageAttributeValue = MessageAttributeValue.builder().build();
ByteBuffer binaryValue = messageAttributeValue.binaryValue().asByteBuffer();
String binaryString = new String(messageAttributeValue.binaryValue().asByteBuffer().array());
```

# Timeout parameter changes
<a name="migration-timeout-parameters"></a>

In version 1, timeout values were specified as integer values representing milliseconds. In version 2, timeout parameters use `java.time.Duration` objects for better type safety and clarity.

You can convert numeric timeout values automatically using the [migration tool](migration-tool.md), or you can convert them manually by wrapping your numeric values with the appropriate `Duration` factory method.

**Example - Set a request timeout in version 1**  

```
// Set request timeout in milliseconds
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setRequestTimeout(5000); // 5 seconds
```

**Example - Set a request timeout in version 2**  

```
// Set request timeout using Duration
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setRequestTimeout(Duration.ofMillis(5000)); // 5 seconds

// Or more clearly:
clientConfiguration.setRequestTimeout(Duration.ofSeconds(5)); // 5 seconds
```

You can use the following `Duration` factory methods for timeout values:
+ `Duration.ofMillis(long millis)` - For millisecond values.
+ `Duration.ofSeconds(long seconds)` - For second values.
+ `Duration.ofMinutes(long minutes)` - For minute values.

# Streaming operation differences between 1.x and 2.x of the AWS SDK for Java
<a name="migration-streaming-ops"></a>

Streaming operations, such as Amazon S3 `getObject` and `putObject` methods, support non-blocking I/O in version 2.x of the SDK. As a result, the request and response model objects no longer take an `InputStream` as a parameter. Instead, for synchronous requests the request object accepts `RequestBody`, which is a stream of bytes. The asynchronous equivalent accepts an `AsyncRequestBody`.

**Example of Amazon S3 `putObject` operation in 1.x**  

```
s3client.putObject(BUCKET, KEY, new File(file_path));
```

**Example of Amazon S3 `putObject` operation in 2.x**  

```
s3client.putObject(PutObjectRequest.builder()
                                 .bucket(BUCKET)
                                 .key(KEY)
                                 .build(),
                 RequestBody.of(Paths.get("myfile.in")));
```

A streaming response object accepts a `ResponseTransformer` for synchronous clients and a `AsyncResponseTransformer` for asynchronous clients in V2.

**Example of Amazon S3 `getObject` operation in 1.x**  

```
S3Object o = s3.getObject(bucket, key);
S3ObjectInputStream s3is = o.getObjectContent();
FileOutputStream fos = new FileOutputStream(new File(key));
```

**Example of Amazon S3 `getObject` operation in 2.x**  

```
s3client.getObject(GetObjectRequest.builder().bucket(bucket).key(key).build(),
		ResponseTransformer.toFile(Paths.get("key")));
```

In the SDK for Java 2.x, streaming response operations have an `AsBytes` method to load the response into memory and simplify common type conversions in-memory.

# Serialization differences between 1.x and 2.x of the AWS SDK for Java
<a name="migration-serialization-changes"></a>

## List objects to request parameters difference
<a name="serialization-diffs-list-obj-to-req-param"></a>

The SDK for Java v1.x and v2.x differ in how they serialize List objects to request parameters.

The SDK for Java 1.x does not serialize an empty list, whereas the SDK for Java 2.x serializes an empty list as an empty parameter.

For example, consider a service with a `SampleOperation` that takes a `SampleRequest`. The `SampleRequest` accepts two parameters—a String type `str1` and List type `listParam`—as shown in the following examples.

**Example of `SampleOperation` in 1.x**  

```
SampleRequest v1Request = new SampleRequest()
    .withStr1("TestName");

sampleServiceV1Client.sampleOperation(v1Request);
```
Wire-level logging shows that the `listParam` parameter is not serialized.  

```
Action=SampleOperation&Version=2011-01-01&str1=TestName
```

**Example of `SampleOperation` in 2.x**  

```
sampleServiceV2Client.sampleOperation(b -> b
    .str1("TestName"));
```
Wire-level logging shows that the `listParam` parameter is serialized with no value.  

```
Action=SampleOperation&Version=2011-01-01&str1=TestName&listParam=
```

## POJOs in V1 compared to builders in V2
<a name="serialization-json-objects"></a>

Because the V1 SDK for Java uses mutable POJO classes, serialization and deserialization libraries—such as [Jackson](https://github.com/FasterXML/jackson-docs)—can use model objects directly. 

The V2 SDK for Java, by contrast, uses immutable model objects. You must use an intermediate builder to perform de/serialization.

The following example shows the differences between de/serializing a `headBucket` API call with V1 and V2 using a Jackson `ObjectMapper`.

```
    public void sendRequest() throws IOException {
        final String bucketName = "amzn-s3-demo-bucket";
        final ObjectMapper mapper = new ObjectMapper();

        // V1 uses POJOs to serialize and deserialize.
        final AmazonS3 v1S3Client = AmazonS3ClientBuilder.defaultClient();
        HeadBucketResult resultV1 = v1S3Client.headBucket(
            new HeadBucketRequest(bucketName));

        String v1Serialized = mapper.writeValueAsString(resultV1);

        HeadBucketResult deserializedV1 = mapper.readValue(v1Serialized, HeadBucketResult.class);
        
        // V2 uses builders to serialize and deserialize.
        S3Client v2S3Client = S3Client.create();
        HeadBucketResponse v2Response = v2S3Client.headBucket(
            b -> b.bucket(bucketName));

        String v2Serialized = mapper.writeValueAsString(
            v2Response.toBuilder());

        HeadBucketResponse v2Deserialized = mapper.readValue(
            v2Serialized, HeadBucketResponse.serializableBuilderClass())
            .build();
    }
```

# Deserialization differences between 1.x and 2.x of the AWS SDK for Java
<a name="migration-deserialization-changes"></a>

## Empty collections in V2 compared to `nulls` in V1
<a name="deserialization-diffs-list-obj-to-req-param"></a>

The SDK for Java v1.x and v2.x differ in how they deserialize JSON responses with lists and maps that are empty.

When the SDK receives a response with a missing property that is modeled as a list or map, V1 deserializes the missing property to `null`, whereas V2 deserializes the property to an immutable empty collection object.

For example, consider the response returned for the `describeTable` method from a DynamoDB client. The following example method contains a V2 DynamoDB client and a V1 DynamoDB client that both execute the `describeTable` method on a table that has no global secondary indexes

**Example of the deserialization of a property modeled as a list that is missing in the response**  

```
public void deserializationDiffs(){

    DescribeTableResponse v2Response = dynamoDbClientV2.describeTable(builder -> builder.tableName(TABLE_NAME));
    // V2 provides has* methods on model objects for list/map members. No null check needed.
    LOGGER.info( String.valueOf(v2Response.table().hasGlobalSecondaryIndexes()) );
    LOGGER.info( String.valueOf(v2Response.table().globalSecondaryIndexes().isEmpty()) );
    // V2 deserialize to an empty collection.
    LOGGER.info(v2Response.table().globalSecondaryIndexes().toString());

    // V1 deserialize to null.
    DescribeTableResult v1Result = dynamoDbClientV1.describeTable(new DescribeTableRequest(TABLE_NAME));
    if (v1Result.getTable().getGlobalSecondaryIndexes() != null){
        LOGGER.info(v1Result.getTable().getGlobalSecondaryIndexes().toString());
    } else {
        LOGGER.info("The list of global secondary indexes returned by the V1 call is <null>");
    }
}
```
The following shows the logged output:  

```
INFO  org.example.DeserializationDifferences:45 - false
INFO  org.example.DeserializationDifferences:46 - true
INFO  org.example.DeserializationDifferences:48 - []
INFO  org.example.DeserializationDifferences:55 - The list of global secondary indexes returned by the V1 call is <null>
```

The Java SDK 2.x takes an idiomatic approach by deserializing empty lists and maps to immutable empty collections instead of returning `null`, promoting safer and more concise code. With V2, you can check if a service returned an attribute modeled as a list or map with the `has*` method, such as the `hasGlobalSecondaryIndexes` shown in the previous example.

This approach avoids the need for explicit `null` checks and aligns with modern Java best practices for handling absent or empty data structures.

### Complete example
<a name="full-example-deserialization"></a>

```
package org.example;

import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.DescribeTableRequest;
import com.amazonaws.services.dynamodbv2.model.DescribeTableResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;

import java.util.UUID;

public class DeserializationDifferences {
    private static final Logger LOGGER = LoggerFactory.getLogger(DeserializationDifferences.class);
    private static final String TABLE_NAME = "DeserializationTable-" + UUID.randomUUID();
    DynamoDbClient dynamoDbClientV2 = DynamoDbClient.create();
    AmazonDynamoDB dynamoDbClientV1 = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.US_EAST_1).build();

    public static void main(String[] args) {

        DeserializationDifferences difference = new DeserializationDifferences();
        difference.createTable();
        difference.deserializationDiffs();
        difference.deleteTable();
    }

    public void createTable(){
        dynamoDbClientV2.createTable(b -> b
                .billingMode(BillingMode.PAY_PER_REQUEST)
                .tableName(TABLE_NAME)
                .keySchema(b1 -> b1.attributeName("Id").keyType(KeyType.HASH))
                .attributeDefinitions(b2 -> b2.attributeName("Id").attributeType(ScalarAttributeType.S)));
        dynamoDbClientV2.waiter().waitUntilTableExists(b -> b.tableName(TABLE_NAME));
    }

    public void deserializationDiffs(){

        DescribeTableResponse v2Response = dynamoDbClientV2.describeTable(builder -> builder.tableName(TABLE_NAME));
        // V2 provides has* methods on model objects for list/map members. No null check needed.
        LOGGER.info( String.valueOf(v2Response.table().hasGlobalSecondaryIndexes()) );
        LOGGER.info( String.valueOf(v2Response.table().globalSecondaryIndexes().isEmpty()) );
        // V2 deserialize to an empty collection.
        LOGGER.info(v2Response.table().globalSecondaryIndexes().toString());

        // V1 deserialize to null.
        DescribeTableResult v1Result = dynamoDbClientV1.describeTable(new DescribeTableRequest(TABLE_NAME));
        if (v1Result.getTable().getGlobalSecondaryIndexes() != null){
            LOGGER.info(v1Result.getTable().getGlobalSecondaryIndexes().toString());
        } else {
            LOGGER.info("The list of global secondary indexes returned by the V1 call is <null>");
        }
    }

    public void deleteTable(){
        dynamoDbClientV2.deleteTable(b -> b.tableName(TABLE_NAME));
        dynamoDbClientV2.waiter().waitUntilTableNotExists(b -> b.tableName(TABLE_NAME));
    }
}
```

The JSON response for the `describeTable` method from the V1 and V2 client contains no `GlobalSecondaryIndexes` attribute:

```
{
  "Table": {
    "AttributeDefinitions": [
      {
        "AttributeName": "Id",
        "AttributeType": "S"
      }
    ],
    "BillingModeSummary": {
      "BillingMode": "PAY_PER_REQUEST",
      "LastUpdateToPayPerRequestDateTime": ...
    },
    "CreationDateTime": ...,
    "DeletionProtectionEnabled": false,
    "ItemCount": 0,
    "KeySchema": [
      {
        "AttributeName": "Id",
        "KeyType": "HASH"
      }
    ],
    "ProvisionedThroughput": {
      "NumberOfDecreasesToday": 0,
      "ReadCapacityUnits": 0,
      "WriteCapacityUnits": 0 
    },
    "TableArn": "arn:aws:dynamodb:us-east-1:11111111111:table/DeserializationTable-...",
    "TableId": "...",
    "TableName": "DeserializationTable-...",
    "TableSizeBytes": 0,
    "TableStatus": "ACTIVE",
    "TableThroughputModeSummary": {
      "LastUpdateToPayPerRequestDateTime": ...,
      "TableThroughputMode": "PAY_PER_REQUEST"
    },
    "WarmThroughput": {
      "ReadUnitsPerSecond": 12000,
      "Status": "ACTIVE",
      "WriteUnitsPerSecond": 4000
    }
  }
}
```

# Exception changes
<a name="migration-exception-changes"></a>

Exception class names, their structures, and their relationships have changed. `software.amazon.awssdk.core.exception.SdkException` is the new base `Exception` class that all the other exceptions extend.

This table maps the exception class name changes.


| 1.x | 2.x | 
| --- | --- | 
|   `com.amazonaws.SdkBaseException` `com.amazonaws.AmazonClientException`   |   `software.amazon.awssdk.core.exception.SdkException`   | 
|   `com.amazonaws.SdkClientException`   |   `software.amazon.awssdk.core.exception.SdkClientException`   | 
|   `com.amazonaws.AmazonServiceException`   |   `software.amazon.awssdk.awscore.exception.AwsServiceException`   | 

The following table maps the methods on exception classes between version 1.x and 2.x.


| 1.x | 2.x | 
| --- | --- | 
|   `AmazonServiceException.getRequestId`   |   `SdkServiceException.requestId`   | 
|   `AmazonServiceException.getServiceName`   |   `AwsServiceException.awsErrorDetails().serviceName`   | 
|   `AmazonServiceException.getErrorCode`   |   `AwsServiceException.awsErrorDetails().errorCode`   | 
|   `AmazonServiceException.getErrorMessage`   |   `AwsServiceException.awsErrorDetails().errorMessage`   | 
|   `AmazonServiceException.getStatusCode`   |   `AwsServiceException.awsErrorDetails().sdkHttpResponse().statusCode`   | 
|   `AmazonServiceException.getHttpHeaders`   |   `AwsServiceException.awsErrorDetails().sdkHttpResponse().headers`   | 
|   `AmazonServiceException.rawResponse`   |   `AwsServiceException.awsErrorDetails().rawResponse`   | 

# Service-specific changes
<a name="migration-service-changes"></a>

## Amazon S3 changes
<a name="s3-operations-name"></a>

SDK for Java 2.x disables anonymous access by default. As a result, you must enable anonymous access by using the `AnonymousCredentialsProvider`.

### Operation name changes
<a name="s3-op-name-changes"></a>

Many of the operation names for the Amazon S3 client have changed in the AWS SDK for Java 2.x. In version 1.x, the Amazon S3 client is not generated directly from the service API. This results in inconsistency between the SDK operations and the service API. In version 2.x, we now generate the Amazon S3 client to be more consistent with the service API.

The following table shows the operation names in the two versions.


**Amazon S3 Operation names**  

| 1.x | 2.x | 
| --- | --- | 
| abortMultipartUpload | abortMultipartUpload | 
| changeObjectStorageClass  | copyObject | 
| completeMultipartUpload  | completeMultipartUpload | 
| copyObject | copyObject | 
| copyPart | uploadPartCopy | 
| createBucket | createBucket | 
| deleteBucket | deleteBucket | 
| deleteBucketAnalyticsConfiguration | deleteBucketAnalyticsConfiguration | 
| deleteBucketCrossOriginConfiguration | deleteBucketCors | 
| deleteBucketEncryption | deleteBucketEncryption | 
| deleteBucketInventoryConfiguration | deleteBucketInventoryConfiguration | 
| deleteBucketLifecycleConfiguration | deleteBucketLifecycle | 
| deleteBucketMetricsConfiguration | deleteBucketMetricsConfiguration | 
| deleteBucketPolicy | deleteBucketPolicy | 
| deleteBucketReplicationConfiguration | deleteBucketReplication | 
| deleteBucketTaggingConfiguration | deleteBucketTagging | 
| deleteBucketWebsiteConfiguration | deleteBucketWebsite | 
| deleteObject | deleteObject | 
| deleteObjectTagging | deleteObjectTagging | 
| deleteObjects | deleteObjects | 
| deleteVersion | deleteObject | 
| disableRequesterPays | putBucketRequestPayment | 
| doesBucketExist | headBucket | 
| doesBucketExistV2 | headBucket | 
| doesObjectExist | headObject | 
| enableRequesterPays | putBucketRequestPayment | 
| generatePresignedUrl | [S3Presigner](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/presigner/S3Presigner.html) | 
| getBucketAccelerateConfiguration | getBucketAccelerateConfiguration | 
| getBucketAcl | getBucketAcl | 
| getBucketAnalyticsConfiguration | getBucketAnalyticsConfiguration | 
| getBucketCrossOriginConfiguration | getBucketCors | 
| getBucketEncryption | getBucketEncryption | 
| getBucketInventoryConfiguration | getBucketInventoryConfiguration | 
| getBucketLifecycleConfiguration | getBucketLifecycle or getBucketLifecycleConfiguration | 
| getBucketLocation | getBucketLocation | 
| getBucketLoggingConfiguration | getBucketLogging | 
| getBucketMetricsConfiguration | getBucketMetricsConfiguration | 
| getBucketNotificationConfiguration | getBucketNotification or getBucketNotificationConfiguration | 
| getBucketPolicy | getBucketPolicy | 
| getBucketReplicationConfiguration | getBucketReplication | 
| getBucketTaggingConfiguration | getBucketTagging | 
| getBucketVersioningConfiguration | getBucketVersioning | 
| getBucketWebsiteConfiguration | getBucketWebsite | 
| getObject | getObject | 
| getObjectAcl | getObjectAcl | 
| getObjectAsString | getObjectAsBytes().asUtf8String | 
| getObjectMetadata | headObject | 
| getObjectTagging | getObjectTagging | 
| getResourceUrl | [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Utilities.html#getUrl(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Utilities.html#getUrl(java.util.function.Consumer)) | 
| getS3AccountOwner | listBuckets | 
| getUrl | [S3Utilities\$1getUrl](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Utilities.html#getUrl(java.util.function.Consumer)) | 
| headBucket | headBucket | 
| initiateMultipartUpload | createMultipartUpload | 
| isRequesterPaysEnabled | getBucketRequestPayment | 
| listBucketAnalyticsConfigurations | listBucketAnalyticsConfigurations | 
| listBucketInventoryConfigurations | listBucketInventoryConfigurations | 
| listBucketMetricsConfigurations | listBucketMetricsConfigurations | 
| listBuckets | listBuckets | 
| listMultipartUploads | listMultipartUploads | 
| listNextBatchOfObjects | listObjectsV2Paginator | 
| listNextBatchOfVersions | listObjectVersionsPaginator | 
| listObjects | listObjects | 
| listObjectsV2 | listObjectsV2 | 
| listParts | listParts | 
| listVersions | listObjectVersions | 
| putObject | putObject | 
| restoreObject | restoreObject | 
| restoreObjectV2 | restoreObject | 
| selectObjectContent | selectObjectContent | 
| setBucketAccelerateConfiguration | putBucketAccelerateConfiguration | 
| setBucketAcl | putBucketAcl | 
| setBucketAnalyticsConfiguration | putBucketAnalyticsConfiguration | 
| setBucketCrossOriginConfiguration | putBucketCors | 
| setBucketEncryption | putBucketEncryption | 
| setBucketInventoryConfiguration | putBucketInventoryConfiguration | 
| setBucketLifecycleConfiguration | putBucketLifecycle or putBucketLifecycleConfiguration | 
| setBucketLoggingConfiguration | putBucketLogging | 
| setBucketMetricsConfiguration | putBucketMetricsConfiguration | 
| setBucketNotificationConfiguration | putBucketNotification or putBucketNotificationConfiguration | 
| setBucketPolicy | putBucketPolicy | 
| setBucketReplicationConfiguration | putBucketReplication | 
| setBucketTaggingConfiguration | putBucketTagging | 
| setBucketVersioningConfiguration | putBucketVersioning | 
| setBucketWebsiteConfiguration | putBucketWebsite | 
| setObjectAcl | putObjectAcl | 
| setObjectRedirectLocation | copyObject | 
| setObjectTagging | putObjectTagging | 
| uploadPart | uploadPart | 

## Amazon SNS changes
<a name="sns-changes"></a>

An SNS client can no longer access SNS topics in Regions other than the Region that it is configured to access.

## Amazon SQS changes
<a name="sqs-changes"></a>

An SQS client can no longer access SQS queues in Regions other than the Region that it is configured to access.

## Amazon RDS changes
<a name="rds-changes"></a>

The SDK for Java 2.x uses `RdsUtilities#generateAuthenticationToken` in place of the class `RdsIamAuthTokenGenerator` in 1.x.

# Changes in working with Amazon S3 from version 1 to version 2 of the AWS SDK for Java
<a name="migration-s3"></a>

The AWS SDK for Java 2.x introduces significant changes to the S3 client, including a new package structure, updated class names, and revised method signatures. While many methods can be automatically migrated from V1 to V2 using the [migration tool](migration-tool.md), some require manual migration, such as `listNextBatchOfObjects` and `selectObjectContent`. Additionally, V2 replaces certain V1 classes like `AccessControlList` and `CannedAccessControlList` with new implementations.

**Topics**
+ [S3 client differences between version 1 and version 2 of the AWS SDK for Java](migration-s3-client.md)
+ [Migrate the Transfer Manager from version 1 to version 2 of the AWS SDK for Java](migration-s3-transfer-manager.md)
+ [Changes in parsing Amazon S3 URIs from version 1 to version 2](migration-s3-uri-parser.md)
+ [Changes in the S3 Event Notifications API from version 1 to version 2](migration-s3-event-notification.md)

# S3 client differences between version 1 and version 2 of the AWS SDK for Java
<a name="migration-s3-client"></a>

In this topic, the differences between the S3 clients in version 1 and version 2 of SDK for Java are organized by how the [migration tool](migration-tool.md) can automate the migration. The tool supports migration of most methods from V1 to V2, but some methods require manual migration. In additional to S3 client methods, some S3 V1 classes do not have a direct V2 equivalent requiring you to manually migrate them.

**Contents**
+ [Example V1 methods supported by the migration tool](#methods-tool-migration)
  + [`putObject`](#V1-V2-putobject)
  + [`getObject`](#V1-V2-getobject)
+ [V1 methods that require manual migration](#s3-methods-manual-migration)
  + [`getObject` using `S3ObjectId`](#V1s-getObject-using-V1s-S3ObjectId)
  + [`getETag` using `ObjectMetadata`](#V1s-ObjectMetadata-using-V1s-getETag)
  + [`listNextBatchOfObjects`](#V1-listNextBatchOfObjects)
  + [`listNextBatchOfVersions`](#V1-listNextBatchOfVersions)
  + [`selectObjectContent`](#V1-selectObjectContent)
  + [`setBucketAcl`](#V1-setBucketAcl)
  + [`setObjectAcl`](#V1-setObjectAcl)
  + [`initiateMultipartUpload`](#V1-initiateMultipartUpload)
    + [Example migration](#V1-initiateMultipartUpload-migration-ex)
    + [Implementation differences](#V1-initiateMultipartUpload-impl-diffs)
  + [`setRegion`](#V1-setRegion)
  + [`setS3ClientOptions(S3ClientOptions clientOptions)`](#V1-setS3ClientOptions)
  + [`setBucketLoggingConfiguration`](#V1-setBucketLoggingConfiguration)
  + [`setBucketLifecycleConfiguration`](#V1-setBucketLifecycleConfiguration)
  + [`setBucketTaggingConfiguration`](#V1-setBucketTaggingConfiguration)
+ [V1 classes that require manual migration](#s3-classes-manual-migration)
  + [`AccessControlList`](#V1-AccessControlList)
  + [`CannedAccessControlList`](#V1-CannedAccessControlList)
  + [`BucketNotificationConfiguration`](#V1-BucketNotificationConfiguration)
  + [`MultiFactorAuthentication`](#V1-MultifactorAuthentication)

## Example V1 methods supported by the migration tool
<a name="methods-tool-migration"></a>

The migration tool automatically migrates most methods from V1 to V2. The `putObject` and `getObject` methods are two examples.

### `putObject`
<a name="V1-V2-putobject"></a>

```
// SDK V1
s3Client.putObject("amzn-s3-demo-bucket", "my-key", "Hello World!");


// SDK V2
s3Client.putObject(req -> req 
    .bucket("amzn-s3-demo-bucket") 
    .key("my-key"), 
    RequestBody.fromString("Hello World!"));
```

### `getObject`
<a name="V1-V2-getobject"></a>

```
// SDK V1
S3Object object = s3Client.getObject("amzn-s3-demo-bucket", "my-key");
InputStream content = object.getObjectContent();


// SDK V2
ResponseInputStream<GetObjectResponse> response = s3Client.getObject(req -> req 
    .bucket("amzn-s3-demo-bucket") 
    .key("my-key"));
```

## V1 methods that require manual migration
<a name="s3-methods-manual-migration"></a>

You need to manually migrate the following V1 S3 client methods. When you use the migration tool, you see a comment in the V2 output Java file that directs you to this topic.

### V1's `getObject` using V1's `S3ObjectId` to V2's `GetObjectRequest.builder()`
<a name="V1s-getObject-using-V1s-S3ObjectId"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
        .withRegion(Regions.US_WEST_2)
        .build();

S3ObjectId s3ObjectId = new S3ObjectId(
    "amzn-s3-demo-bucket",
    "object-key",
    "abc123version" 
);

GetObjectRequest getRequest= new GetObjectRequest(s3ObjectId);
S3Object s3ObjectVersioned = s3Client.getObject(getRequest);


// SDK V2
// V2 does not include a 'S3ObjectId' class. V2 uses the request builder pattern 
// to supply the bucket, key, and version parameters.
S3Client s3Client = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

GetObjectRequest getRequest = GetObjectRequest.builder()
    .bucket("amzn-s3-demo-bucket")
    .key("object-key")
    .versionId("abc123version")
    .build();

ResponseInputStream<GetObjectResponse> response = s3Client.getObject(getRequest);
```

### V1's `getETag()` using V1's `ObjectMetadata` to V2's `GetObjectResponse.eTag()`
<a name="V1s-ObjectMetadata-using-V1s-getETag"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

S3Object object = s3ClientV1.getObject("amzn-s3-demo-bucket", "my-key");

// Double quotes are removed by the S3 client.
System.out.println(object.getObjectMetadata().getETag());

// SDK V2
S3Client s3ClientV2 = S3Client.builder()
        .region(Region.US_WEST_2)
        .build();

ResponseInputStream<GetObjectResponse> response = s3ClientV2.getObject(
        req -> req.bucket("amzn-s3-demo-bucket").key("my-key"));

// Double quotes are *NOT* removed. This is the unchanged ETag value as S3 sent it.
System.out.println(response.response().eTag());
```

### V1's `listNextBatchOfObjects` to V2's `listObjectsV2Paginator`
<a name="V1-listNextBatchOfObjects"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

ObjectListing objectListing = s3ClientV1.listObjects("bucket-name");
while (objectListing.isTruncated()) {
    objectListing = s3ClientV1.listNextBatchOfObjects(objectListing);
    for (S3ObjectSummary summary : objectListing.getObjectSummaries()) {
        System.out.println(summary.getKey());
    }
}


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

ListObjectsV2Request request = ListObjectsV2Request.builder()
    .bucket("bucket-name")
    .build();

// V2 returns a paginator.
ListObjectsV2Iterable responses = s3Client.listObjectsV2Paginator(request);

for (ListObjectsV2Response page : responses) {
    page.contents().forEach(content -> {
        System.out.println(content.key());
    });
}
```

### V1's `listNextBatchOfVersions` to V2's `listObjectVersionsPaginator`
<a name="V1-listNextBatchOfVersions"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

VersionListing versionListing = s3ClientV1.listVersions("bucket-name", "prefix");
while (versionListing.isTruncated()) {
    versionListing = s3ClientV1.listNextBatchOfVersions(versionListing);
    for (S3VersionSummary version : versionListing.getVersionSummaries()) {
        System.out.println(version.getKey() + " " + version.getVersionId());
    }
}


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

ListObjectVersionsRequest request = ListObjectVersionsRequest.builder()
    .bucket("bucket-name")
    .prefix("prefix")
    .build();

// V2 returns a paginator.
ListObjectVersionsIterable responses = s3ClientV2.listObjectVersionsPaginator(request);

for (ListObjectVersionsResponse page : responses) {
    page.versions().forEach(version -> {
        System.out.println(version.key() + " " + version.versionId());
    });
}
```

### `selectObjectContent`
<a name="V1-selectObjectContent"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

SelectObjectContentRequest request = new SelectObjectContentRequest()
    .withBucket("bucket-name")
    .withKey("object-key")
    .withExpression("select * from S3Object")
    .withExpressionType(ExpressionType.SQL)
 

SelectObjectContentResult result = s3ClientV1.selectObjectContent(request);
InputStream resultInputStream = result.getPayload().getRecordsInputStream();


// SDK V2
// In V2, 'selectObjectContent()' is available only on the S3AsyncClient. 
// V2 handles responses using an event-based 'SelectObjectContentEventStream'.
S3AsyncClient s3ClientV2 = S3AsyncClient.builder()
    .region(Region.US_WEST_2)
    .build();

SelectObjectContentRequest request = SelectObjectContentRequest.builder()
    .bucket("bucket-name")
    .key("object-key")
    .expression("select * from S3Object")
    .expressionType(ExpressionType.SQL)
    .build();
    
SelectObjectContentResponseHandler handler = new SelectObjectContentResponseHandler() {
    // Implement the required abstract methods such as 'onEventStream()'.
};

CompletableFuture<Void> future = s3ClientV2.selectObjectContent(request, handler);
// The 'SelectObjectContentResponseHandler' implementation processes the results.
```

### V1's `setBucketAcl` to V2's `acl` method on `PutBucketAclRequest.builder()`
<a name="V1-setBucketAcl"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

AccessControlList acl = new AccessControlList();
acl.grantPermission(GroupGrantee.AllUsers, Permission.Read);
s3ClientV1.setBucketAcl("bucket-name", acl);


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

PutBucketAclRequest request = PutBucketAclRequest.builder()
    .bucket("bucket-name")
    .acl(BucketCannedACL.PRIVATE)
    .build();

s3ClientV2.putBucketAcl(request);
```

### V1's `setObjectAcl` to V2's `acl` method on `PutObjectAclRequest.builder()`
<a name="V1-setObjectAcl"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

AccessControlList acl = new AccessControlList();
acl.grantPermission(GroupGrantee.AllUsers, Permission.Read);
s3ClientV1.setObjectAcl("bucket-name", "object-key", acl);


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

PutObjectAclRequest request = PutObjectAclRequest.builder()
    .bucket("bucket-name")
    .key("object-key")
    .acl(ObjectCannedACL.PRIVATE)
    .build();

s3ClientV2.putObjectAcl(request);
```

### V1's `initiateMultipartUpload` to V2's `createMultipartUpload`
<a name="V1-initiateMultipartUpload"></a>

#### Example migration
<a name="V1-initiateMultipartUpload-migration-ex"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();
    
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("application/zip");
metadata.addUserMetadata("mykey", "myvalue");

InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(
    "bucket-name", 
    "object-key",
    metadata
);

InitiateMultipartUploadResult initResponse = s3ClientV1.initiateMultipartUpload(initRequest);
String uploadId = initResponse.getUploadId();


// SDK V2
// V1 uses ObjectMetadata methods, whereas V2 uses a simple Map.
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

CreateMultipartUploadRequest createMultipartRequest = CreateMultipartUploadRequest.builder() 
    .bucket("amzn-s3-demo-bucket") 
    .key("object-key") 
    .contentType("application/zip") 
    .metadata(Collections.singletonMap("mykey", "myvalue"))
    .build();

CreateMultipartUploadResponse response = s3ClientV2.createMultipartUpload(createMultipartRequest);
String uploadId = response.uploadId();
```

#### Implementation differences
<a name="V1-initiateMultipartUpload-impl-diffs"></a>

The default `Content-Type` header value for the following methods differ as shown in the following table.


****  

| SDK version | Method | Default `Content-Type` value | 
| --- | --- | --- | 
| version 1 | [initiateMultipartUpload](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3Client.html#initiateMultipartUpload-com.amazonaws.services.s3.model.InitiateMultipartUploadRequest-) | application/octet-stream | 
| version 2 | [createMultipartUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html#createMultipartUpload(software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest)) | binary/octet-stream | 

### V1's `setRegion` to V2's `region` method on client builder
<a name="V1-setRegion"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard().build();
s3ClientV1.setRegion(Region.getRegion(Regions.US_WEST_2));


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();
```

### V1's `setS3ClientOptions(S3ClientOptions clientOptions)`
<a name="V1-setS3ClientOptions"></a>

Instead of using a single `S3ClientOptions` object with the `setS3ClientOptions` method, V2 provides methods on the client builder to set options.

### V1's `setBucketLoggingConfiguration` to V2's `putBucketLogging`
<a name="V1-setBucketLoggingConfiguration"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

BucketLoggingConfiguration loggingConfig = new BucketLoggingConfiguration();
loggingConfig.setDestinationBucketName("log-bucket");

SetBucketLoggingConfigurationRequest request = new SetBucketLoggingConfigurationRequest(
    "amzn-s3-demo-source-bucket",
    loggingConfig
);

s3ClientV1.setBucketLoggingConfiguration(request);


// SDK V2
// In V2, V1's 'BucketLoggingConfiguration' is replaced by 'BucketLoggingStatus' 
// and 'LoggingEnabled'.
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

LoggingEnabled loggingEnabled = LoggingEnabled.builder()
    .targetBucket("log-bucket")
    .build();

BucketLoggingStatus loggingStatus = BucketLoggingStatus.builder()
    .loggingEnabled(loggingEnabled)
    .build();

PutBucketLoggingRequest request = PutBucketLoggingRequest.builder()
    .bucket("amzn-s3-demo-source-bucket")
    .bucketLoggingStatus(loggingStatus)
    .build();

s3ClientV2.putBucketLogging(request);
```

### V1's `setBucketLifecycleConfiguration` to V2's `putBucketLifecycleConfiguration`
<a name="V1-setBucketLifecycleConfiguration"></a>

```
// SDK V1
BucketLifecycleConfiguration.Rule rule = new BucketLifecycleConfiguration.Rule()
    .withId("Archive and Delete Rule")
    .withPrefix("documents/")
    .withStatus(BucketLifecycleConfiguration.ENABLED)
    .withTransitions(Arrays.asList(
        new Transition()
            .withDays(30)
            .withStorageClass(StorageClass.StandardInfrequentAccess.toString()),
        new Transition()
            .withDays(90)
            .withStorageClass(StorageClass.Glacier.toString())
    ))
    .withExpirationInDays(365);

BucketLifecycleConfiguration configuration = new BucketLifecycleConfiguration()
    .withRules(Arrays.asList(rule));

s3ClientV1.setBucketLifecycleConfiguration("amzn-s3-demo-bucket", configuration);


// SDK V2
LifecycleRule rule = LifecycleRule.builder()
    .id("Archive and Delete Rule")
    .filter(LifecycleRuleFilter.builder()
        .prefix("documents/")
        .build())
    .status(ExpirationStatus.ENABLED)
    .transitions(Arrays.asList(
        Transition.builder()
            .days(30)
            .storageClass(TransitionStorageClass.STANDARD_IA)
            .build(),
        Transition.builder()
            .days(90)
            .storageClass(TransitionStorageClass.GLACIER)
            .build()
    ))
    .expiration(LifecycleExpiration.builder()
        .days(365)
        .build())
    .build();

PutBucketLifecycleConfigurationRequest request = PutBucketLifecycleConfigurationRequest.builder()
    .bucket("amzn-s3-demo-bucket")
    .lifecycleConfiguration(BucketLifecycleConfiguration.builder()
        .rules(rule)
        .build())
    .build();

s3ClientV2.putBucketLifecycleConfiguration(request);
```

### V1's `setBucketTaggingConfiguration` to V2's `putBucketTagging`
<a name="V1-setBucketTaggingConfiguration"></a>

```
// SDK V1
List<TagSet> tagsets = new ArrayList<>();
TagSet tagSet = new TagSet();
tagSet.setTag("key1", "value1");
tagSet.setTag("key2", "value2");
tagsets.add(tagSet);

BucketTaggingConfiguration bucketTaggingConfiguration = new BucketTaggingConfiguration();
bucketTaggingConfiguration.setTagSets(tagsets);

SetBucketTaggingConfigurationRequest request = new SetBucketTaggingConfigurationRequest(
    "amzn-s3-demo-bucket",
    bucketTaggingConfiguration
);

s3ClientV1.setBucketTaggingConfiguration(request);


// SDK V2
Tagging tagging = Tagging.builder()
    .tagSet(Arrays.asList(
        Tag.builder()
            .key("key1")
            .value("value1")
            .build(),
        Tag.builder()
            .key("key2")
            .value("value2")
            .build()
    ))
    .build();

PutBucketTaggingRequest request = PutBucketTaggingRequest.builder()
    .bucket("amzn-s3-demo-bucket")
    .tagging(tagging)
    .build();

s3ClientV2.putBucketTagging(request);
```

## V1 classes that require manual migration
<a name="s3-classes-manual-migration"></a>

### V1's `AccessControlList` to V2's `AccessControlPolicy`
<a name="V1-AccessControlList"></a>

```
// SDK V1
AccessControlList aclV1 = new AccessControlList();
aclV1.setOwner(new Owner("owner-id", "owner-name"));
aclV1.grantPermission(GroupGrantee.AllUsers, Permission.Read);

// SDK V2
// To migrate from V1 to V2, replace direct 'AccessControlList' modifications with an
// 'AccessControlPolicy.builder()' that contains both owner information and grants. 
// Note that V2's approach requires building the complete permission set upfront rather than modifying permissions incrementally.
AccessControlPolicy acpV2 = AccessControlPolicy.builder()
    .owner(Owner.builder()
        .id("owner-id")
        .displayName("owner-name")
        .build())
    .grants(Arrays.asList(
         Grant.builder()
            .grantee(Grantee.builder()
                 .type(Type.GROUP)
                 .uri("http://acs.amazonaws.com/groups/global/AllUsers") 
                 .build())
             .permission(Permission.READ)
             .build()
     ))
     .build();
```

### V1's `CannedAccessControlList` enum to V2's `BucketCannedACL` and `ObjectCannedACL` enums
<a name="V1-CannedAccessControlList"></a>

```
// SDK V1
// In V1, 'CannedAccessControlList' is an enumeration of predefined ACLs.
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard().build();

// Creating a bucket.
s3ClientV1.setBucketAcl("bucket-name", CannedAccessControlList.PublicRead);

// Creating an object.
PutObjectRequest putObjectRequest = new PutObjectRequest("bucket-name", "object-key", file)
    .withCannedAcl(CannedAccessControlList.PublicRead);
s3ClientV1.putObject(putObjectRequest);


// SDK V2
// V2 replaces V1's 'CannedAccessControlList' with 'BucketCannedACL' for buckets and 'ObjectCannedACL' for objects.
S3Client s3ClientV2 = S3Client.builder().build();

// Creating a bucket.
PutBucketAclRequest bucketRequest = PutBucketAclRequest.builder()
    .bucket("bucket-name")
    .acl(BucketCannedACL.PRIVATE)
    .build();
s3ClientV2.putBucketAcl(bucketRequest);

// Creating an object.
PutObjectRequest objectRequest = PutObjectRequest.builder()
    .bucket("bucket-name")
    .key("object-key")
    .acl(ObjectCannedACL.PUBLIC_READ)
    .build();
s3ClientV2.putObject(objectRequest, RequestBody.fromFile(file));
```

### V1's `BucketNotificationConfiguration` to V2's `NotificationConfiguration`
<a name="V1-BucketNotificationConfiguration"></a>

```
//SDK V1
BucketNotificationConfiguration notificationConfig = new BucketNotificationConfiguration();

// Adding configurations by name
notificationConfig.addConfiguration("lambdaConfig", 
    new LambdaConfiguration("arn:aws:lambda:function", "s3:ObjectCreated:"));

notificationConfig.addConfiguration("topicConfig",
    new TopicConfiguration("arn:aws:sns:topic", "s3:ObjectRemoved:"));

notificationConfig.addConfiguration("queueConfig",
    new QueueConfiguration("arn:aws:sqs:queue", "s3:ObjectRestore:*"));

s3Client.setBucketNotificationConfiguration("bucket", notificationConfig);


// SDK V2
// In V2, V1's BucketNotificationConfiguration is renamed to NotificationConfiguration. 
// V2 contains no common abstract class for LambdaFunction/Topic/Queue configurations.
NotificationConfiguration notificationConfig = NotificationConfiguration.builder()
    .lambdaFunctionConfigurations(
        LambdaFunctionConfiguration.builder()
            .lambdaFunctionArn("arn:aws:lambda:function")
            .events(Event.valueOf("s3:ObjectCreated:"))
            .build())
    .topicConfigurations(
        TopicConfiguration.builder()
            .topicArn("arn:aws:sns:topic")
            .events(Event.valueOf("s3:ObjectRemoved:"))
            .build())
    .queueConfigurations(
        QueueConfiguration.builder()
            .queueArn("arn:aws:sqs:queue")
            .events(Event.valueOf("s3:ObjectRestore:*"))
            .build())
    .build();

s3Client.putBucketNotificationConfiguration(req -> req
    .bucket("bucket")
    .notificationConfiguration(notificationConfig));
```

### V1's `MultiFactorAuthentication` to V2's `mfa` method on a request builder
<a name="V1-MultifactorAuthentication"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

BucketVersioningConfiguration versioningConfig = new BucketVersioningConfiguration()
    .withStatus(BucketVersioningConfiguration.ENABLED);

// Create an MFA configuration object.
MultiFactorAuthentication mfa = new MultiFactorAuthentication(
    "arn:aws:iam::1234567890:mfa/user",
    "123456"
);

// Create the request object.
SetBucketVersioningConfigurationRequest request = new SetBucketVersioningConfigurationRequest(
    "bucket-name",
    versioningConfig,
    mfa
);

// Send the request.
s3ClientV1.setBucketVersioningConfiguration(request);


// SDK V2
// V2 replaces V1's MultiFactorAuthentication POJO with parameters you set on the request builder.
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

PutBucketVersioningRequest request = PutBucketVersioningRequest.builder()
    .bucket("bucket-name")
    .versioningConfiguration(VersioningConfiguration.builder()
        .status(BucketVersioningStatus.ENABLED)
        .build())
    .mfa("arn:aws:iam::1234567890:mfa/user 123456")  // Single method takes both MFA erial number and token.
    .build();

s3ClientV2.putBucketVersioning(request);
```

# Migrate the Transfer Manager from version 1 to version 2 of the AWS SDK for Java
<a name="migration-s3-transfer-manager"></a>

This migration guide covers the key differences between Transfer Manager v1 and S3 Transfer Manager v2, including constructor changes, method mappings, and code examples for common operations. After reviewing these differences, you can successfully migrate your existing Transfer Manager code to take advantage of improved performance and asynchronous operations in v2.

**About the AWS SDK migration tool**  
The AWS SDK for Java provides an automated [migration tool](migration-tool.md) that can migrate much of the v1 Transfer Manager API to v2. However, the migration tool doesn't support several v1 Transfer Manager features. For these cases, you need to manually migrate Transfer Manager code using the guidance in this topic.  
Throughout this guide, the **Migration Status** shows whether the migration tool can automatically migrate a constructor, method, or feature:  
**Supported**: The migration tool can automatically transform this code
**Not Supported**: You need to manually migrate code
Even for items marked as "Supported," review the migration results and test thoroughly. Transfer Manager migration involves significant architectural changes from synchronous to asynchronous operations.

## Overview
<a name="s3-tm-migration-overview"></a>

S3 Transfer Manager v2 introduces significant changes to the Transfer Manager API. S3 Transfer Manager v2 is built on asynchronous operations and provides better performance, especially when you use the AWS CRT-based Amazon S3 client.

### Key differences
<a name="s3-tm-migration-key-differences"></a>
+ **Package**: `com.amazonaws.services.s3.transfer` → `software.amazon.awssdk.transfer.s3`
+ **Class name**: `TransferManager` → `S3TransferManager`
+ **Client dependency**: Synchronous Amazon S3 client → Asynchronous Amazon S3 client (`S3AsyncClient`)
+ **Architecture**: Synchronous operations → Asynchronous operations with `CompletableFuture`
+ **Performance**: Enhanced with AWS CRT-based client support

## High-level changes
<a name="s3-tm-migration-high-level-changes"></a>


| Aspect | V1 | V2 | 
| --- | --- | --- | 
| Maven dependency | aws-java-sdk-s3 | s3-transfer-manager | 
| Package | com.amazonaws.services.s3.transfer | software.amazon.awssdk.transfer.s3 | 
| Main class | TransferManager | S3TransferManager | 
| Amazon S3 client | AmazonS3 (sync) | S3AsyncClient (async) | 
| Return types | Blocking operations | CompletableFuture<T> | 

## Maven dependencies
<a name="s3-tm-migration-dependencies"></a>


| V1 | V2 | 
| --- | --- | 
|  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>>1.12.7871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-s3</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.31.682</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>s3-transfer-manager</artifactId><br />    </dependency><br />    <!-- Optional: For enhanced performance with AWS CRT --><br />    <dependency><br />        <groupId>software.amazon.awssdk.crt</groupId><br />        <artifactId>aws-crt</artifactId><br />        <version>0.38.53</version><br />    </dependency><br /></dependencies></pre>  | 

1 [Latest version](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom). 2 [Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom). 3[Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk.crt/aws-crt).

## Client constructor migration
<a name="s3-tm-migration-client-constructor"></a>

### Supported constructors (automatic migration)
<a name="s3-tm-migration-supported-constructors"></a>


| V1 constructor | V2 equivalent | Migration status | 
| --- | --- | --- | 
| new TransferManager() | S3TransferManager.create() | Supported | 
| TransferManagerBuilder. defaultTransferManager() | S3TransferManager.create() | Supported | 
| TransferManagerBuilder. standard().build() | S3TransferManager.builder().build() | Supported | 
| new TransferManager(AWSCredentials) | S3TransferManager.builder() .s3Client(S3AsyncClient.builder() .credentialsProvider(...).build()) .build() | Supported | 
| new TransferManager( AWSCredentialsProvider) | S3TransferManager.builder() .s3Client(S3AsyncClient.builder() .credentialsProvider(...).build()) .build() | Supported | 

### Unsupported constructors (manual migration required)
<a name="s3-tm-migration-unsupported-constructors"></a>


| V1 constructor | V2 equivalent | Migration notes | 
| --- | --- | --- | 
| new TransferManager(AmazonS3) | Manual migration required | Create an S3AsyncClient separately | 
| new TransferManager(AmazonS3, ExecutorService) | Manual migration required | Create an S3AsyncClient and configure executor | 
| new TransferManager(AmazonS3, ExecutorService, boolean) | Manual migration required | shutDownThreadPools parameter not supported | 

### Manual migration examples
<a name="s3-tm-migration-manual-examples"></a>

**V1 code:**

```
AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();
TransferManager transferManager = new TransferManager(s3Client);
```

**V2 code:**

```
// Create an `S3AsyncClient` with similar configuration
S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
    .credentialsProvider(DefaultCredentialsProvider.create())
    .build();

// Provide the configured `S3AsyncClient` to the S3 transfer manager builder.
S3TransferManager transferManager = S3TransferManager.builder()
    .s3Client(s3AsyncClient)
    .build();
```

## Client method migration
<a name="s3-tm-migration-client-methods"></a>

Currently, the migration tool supports basic `copy`, `download`, `upload`, `uploadDirectory`, `downloadDirectory`, `resumeDownload`, and `resumeUpload` methods.

### Core transfer methods
<a name="s3-tm-migration-core-transfer-methods"></a>


| V1 method | V2 method | Return type change | Migration status | 
| --- | --- | --- | --- | 
| upload(String, String, File) | uploadFile(UploadFileRequest) | Upload → FileUpload | Supported | 
| upload(PutObjectRequest) | upload(UploadRequest) | Upload → Upload | Supported | 
| download(String, String, File) | downloadFile(DownloadFileRequest) | Download → FileDownload | Supported | 
| download(GetObjectRequest, File) | downloadFile(DownloadFileRequest) | Download → FileDownload | Supported | 
| copy(String, String, String, String) | copy(CopyRequest) | Copy → Copy | Supported | 
| copy(CopyObjectRequest) | copy(CopyRequest) | Copy → Copy | Supported | 
| uploadDirectory(String, String, File, boolean) | uploadDirectory( UploadDirectoryRequest) | MultipleFileUpload → DirectoryUpload | Supported | 
| downloadDirectory(String, String, File) | downloadDirectory( DownloadDirectoryRequest) | MultipleFileDownload → DirectoryDownload | Supported | 

### Resumable transfer methods
<a name="s3-tm-migration-resumable-methods"></a>


| V1 method | V2 method | Migration status | 
| --- | --- | --- | 
| resumeUpload(PersistableUpload) | resumeUploadFile(ResumableFileUpload) | Supported | 
| resumeDownload(PersistableDownload) | resumeDownloadFile(ResumableFileDownload) | Supported | 

### Lifecycle methods
<a name="s3-tm-migration-lifecycle-methods"></a>


| V1 method | V2 method | Migration status | 
| --- | --- | --- | 
| shutdownNow() | close() | Supported | 
| shutdownNow(boolean) | Manually adjust code using the close() method | Not Supported | 

### Unsupported V1 client methods
<a name="s3-tm-migration-unsupported-methods"></a>


| V1 method | V2 alternative | Notes | 
| --- | --- | --- | 
| abortMultipartUploads(String, Date) | Use the low-level Amazon S3 client | Not Supported | 
| getAmazonS3Client() | Save a reference separately | Not Supported; no getter in v2 | 
| getConfiguration() | Save a reference separately | Not Supported; no getter in v2 | 
| uploadFileList(...) | Make multiple uploadFile() calls | Not Supported | 
| copy methods with a TransferStateChangeListener parameter | Use TransferListener | [See manual migration example](#tm-unsupported-client-methods-copy) | 
| download methods with an S3ProgressListener parameter | Use [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/progress/TransferListener.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/progress/TransferListener.html) | [See manual migration example](#tm-unsupported-client-methods-download) | 
|  `downloadDirectory` methods with 4 or more parameters  |  | [See manual migration example](#tm-unsupported-client-methods-download-dir) | 
| upload method with an ObjectMetadataProvider parameter | Set metadata in request | [See manual migration example](#tm-unsupported-client-methods-upload) | 
| uploadDirectory methods with \$1Provider parameter | Set tags in request | [See manual migration example](#tm-unsupported-client-methods-uploadDirectory) | 

#### `copy` methods with a `TransferStateChangeListener` parameter
<a name="tm-unsupported-client-methods-copy"></a>
+ `copy(CopyObjectRequest copyObjectRequest, AmazonS3 srcS3, TransferStateChangeListener stateChangeListener)`
+ `copy(CopyObjectRequest copyObjectRequest, TransferStateChangeListener stateChangeListener)`

```
// V1 ----------------------------------------------------------------------------------------------
// Initialize source S3 client
AmazonS3 s3client = AmazonS3ClientBuilder.standard()
                .withRegion("us-west-2")
                .build();
                
// Initialize Transfer Manager
TransferManager tm = TransferManagerBuilder.standard()
                .withS3Client(srcS3)
                .build();

CopyObjectRequest copyObjectRequest = new CopyObjectRequest(
                "amzn-s3-demo-source-bucket",
                "source-key",         
                "amzn-s3-demo-destination-bucket", 
                "destination-key"    
        );

TransferStateChangeListener stateChangeListener = new TransferStateChangeListener() {
            @Override
            public void transferStateChanged(Transfer transfer, TransferState state) {
              //Implementation of the TransferStateChangeListener
            }
        };

Copy copy = tm.copy(copyObjectRequest, srcS3, stateChangeListener);


// V2 ----------------------------------------------------------------------------------------------
S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
                .region(Region.US_WEST_2)          
                .build();

S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(s3AsyncClient)
                .build();

// Create transfer listener (equivalent to TransferStateChangeListener in v1)                                
TransferListener transferListener = new TransferListener() {
            @Override
            public void transferInitiated(Context.TransferInitiated context) {
               //Implementation
               System.out.println("Transfer initiated");
            }

            @Override
            public void bytesTransferred(Context.BytesTransferred context) {
                //Implementation
                System.out.println("Bytes transferred");
            }

            @Override
            public void transferComplete(Context.TransferComplete context) {
                //Implementation
                System.out.println("Transfer completed!");
            }

            @Override
            public void transferFailed(Context.TransferFailed context) {
                //Implementation
                System.out.println("Transfer failed");
            }
        };

CopyRequest copyRequest = CopyRequest.builder()
                              .copyObjectRequest(req -> req
                                  .sourceBucket("amzn-s3-demo-source-bucket")
                                  .sourceKey("source-key")
                                  .destinationBucket("amzn-s3-demo-destination-bucket")
                                  .destinationKey("destination-key")
                               )
                                .addTransferListener(transferListener) // Configure the transferListener into the request
                                .build();
  
Copy copy = transferManager.copy(copyRequest);
```

#### `download` methods with an `S3ProgressListener` parameter
<a name="tm-unsupported-client-methods-download"></a>
+ `download(GetObjectRequest getObjectRequest, File file, S3ProgressListener progressListener)`
+ `download(GetObjectRequest getObjectRequest, File file, S3ProgressListener progressListener, long timeoutMillis)`
+ `download(GetObjectRequest getObjectRequest, File file, S3ProgressListener progressListener, long timeoutMillis, boolean resumeOnRetry)`

```
// V1 ----------------------------------------------------------------------------------------------
S3ProgressListener progressListener = new S3ProgressListener() {
        @Override
        public void progressChanged(com.amazonaws.event.ProgressEvent progressEvent) {
            long bytes = progressEvent.getBytesTransferred();
            ProgressEventType eventType = progressEvent.getEventType();
            // Use bytes and eventType as needed
        }

        @Override
        public void onPersistableTransfer(PersistableTransfer persistableTransfer) {

        }
    };

Download download1 = tm.download(getObjectRequest, file, progressListener); 
Download download2 = tm.download(getObjectRequest, file, progressListener, timeoutMillis)
Download download3 = tm.download(getObjectRequest, file, progressListener, timeoutMillis, true)

// V2 ----------------------------------------------------------------------------------------------
TransferListener transferListener = new TransferListener() {
    @Override
    public void transferInitiated(Context.InitializedContext context) {
        // Equivalent to ProgressEventType.TRANSFER_STARTED_EVENT
        System.out.println("Transfer initiated");
    }

    @Override
    public void bytesTransferred(Context.BytesTransferred context) {
        // Equivalent to ProgressEventType.REQUEST_BYTE_TRANSFER_EVENT
        long bytes = context.bytesTransferred();
        System.out.println("Bytes transferred: " + bytes);
    }

    @Override
    public void transferComplete(Context.TransferComplete context) {
        // Equivalent to ProgressEventType.TRANSFER_COMPLETED_EVENT
        System.out.println("Transfer completed");
    }

    @Override
    public void transferFailed(Context.TransferFailed context) {
        // Equivalent to ProgressEventType.TRANSFER_FAILED_EVENT
        System.out.println("Transfer failed: " + context.exception().getMessage());
    }
};
DownloadFileRequest downloadFileRequest = 
                         DownloadFileRequest.builder()
                             .getObjectRequest(getObjectRequest)
                             .destination(file.toPath())
                             .addTransferListener(transferListener)
                             .build();

// For download1
FileDownload download = transferManager.downloadFile(downloadFileRequest);

// For download2
CompletedFileDownload completedFileDownload = download.completionFuture()
                                                  .get(timeoutMillis, TimeUnit.MILLISECONDS);

// For download3, the v2 SDK does not have a direct equiavalent to the `resumeOnRetry` method of v1.
// If a download is interrupted, you need to start a new download request.
```

#### `downloadDirectory` methods with 4 or more parameters
<a name="tm-unsupported-client-methods-download-dir"></a>
+ `downloadDirectory(String bucketName, String keyPrefix, File destinationDirectory, boolean resumeOnRetry)`
+ `downloadDirectory(String bucketName, String keyPrefix, File destinationDirectory, boolean resumeOnRetry, KeyFilter filter)`
+ `downloadDirectory(String bucketName, String keyPrefix, File destinationDirectory, KeyFilter filter)`

```
// V1 ----------------------------------------------------------------------------------------------
KeyFilter filter = new KeyFilter() {
            @Override
            public boolean shouldInclude(S3ObjectSummary objectSummary) {
                //Filter implementation
            }
        };
MultipleFileDownload multipleFileDownload = tm.downloadDirectory(bucketName, keyPrefix, destinationDirectory, filter);

// V2 ----------------------------------------------------------------------------------------------
// The v2 SDK does not have a direct equiavalent to the `resumeOnRetry` method of v1.
// If a download is interrupted, you need to start a new download request.
DownloadFilter filter = new DownloadFilter() {
            @Override
            public boolean test(S3Object s3Object) {
                // Filter implementation.
            }
        };

DownloadDirectoryRequest downloadDirectoryRequest = 
                              DownloadDirectoryRequest.builder()
                                  .bucket(bucketName)
                                  .filter(filter)
                                  .listObjectsV2RequestTransformer(builder -> builder.prefix(keyPrefix))
                                  .destination(destinationDirectory.toPath())
                                  .build();
                                                                            
DirectoryDownload directoryDownload = transferManager.downloadDirectory(downloadDirectoryRequest);
```

#### `upload` method with `ObjectMetadata` parameter
<a name="tm-unsupported-client-methods-upload"></a>
+ `upload(String bucketName, String key, InputStream input, ObjectMetadata objectMetadata)`

```
// V1 ----------------------------------------------------------------------------------------------ObjectMetadata metadata = new ObjectMetadata();
ObjectMetadata metadata = new ObjectMetadata();

metadata.setContentType("text/plain");        // System-defined metadata
metadata.setContentLength(22L);               // System-defined metadata
metadata.addUserMetadata("myKey", "myValue"); // User-defined metadata

PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream, metadata);

Upload upload = transferManager.upload("amzn-s3-demo-bucket", "my-key", inputStream, metadata);

// V2 ----------------------------------------------------------------------------------------------
/* When you use an InputStream to upload in V2, you should specify the content length 
   and use `RequestBody.fromInputStream()`. 
   If you don't provide the content length, the entire stream will be buffered in memory. 
   If you can't determine the content length, we recommend using the CRT-based S3 client.
*/
Map<String, String> userMetadata = new HashMap<>();
userMetadata.put("x-amz-meta-myKey", "myValue");

PutObjectRequest putObjectRequest = 
                        PutObjectRequest.builder()
                            .bucket("amzn-s3-demo-bucket1")
                            .key("k")
                            .contentType("text/plain") //System-defined metadata usually has separate methods in the builder.
                            .contentLength(22L)
                            .metadata(userMetadata) //metadata() is only for user-defined metadata.
                            .build();

UploadRequest uploadRequest = 
                        UploadRequest.builder()
                            .putObjectRequest(putObjectRequest)
                            .requestBody(AsyncRequestBody.fromInputStream(stream, 22L, executor))
                            .build();
                                                   
transferManager.upload(uploadRequest).completionFuture().join();
```

#### `uploadDirectory` with `ObjectMetadataProvider` parameter
<a name="tm-unsupported-client-methods-uploadDirectory"></a>
+ `uploadDirectory(String bucketName, String virtualDirectoryKeyPrefix, File directory, boolean includeSubdirectories, ObjectMetadataProvider metadataProvider)`
+ `uploadDirectory(String bucketName, String virtualDirectoryKeyPrefix, File directory, boolean includeSubdirectories, ObjectMetadataProvider metadataProvider, ObjectTaggingProvider taggingProvider)`
+ `uploadDirectory(String bucketName, String virtualDirectoryKeyPrefix, File directory, boolean includeSubdirectories, ObjectMetadataProvider metadataProvider, ObjectTaggingProvider taggingProvider, ObjectCannedAclProvider cannedAclProvider)`

```
// V1 ----------------------------------------------------------------------------------------------
tm.uploadDirectory(bucketName, virtualDirectoryKeyPrefix, directory, includeSubdirectories, metadataProvider)
tm.uploadDirectory(bucketName, virtualDirectoryKeyPrefix, directory, includeSubdirectories, metadataProvider, taggingProvider)
tm.uploadDirectory(bucketName, virtualDirectoryKeyPrefix, directory, includeSubdirectories, metadataProvider, taggingProvider, cannedAclProvider)

// V2 ----------------------------------------------------------------------------------------------
UploadDirectoryRequest request = UploadDirectoryRequest.builder()
                                  .bucket(bucketName)
                                  .s3Prefix(virtualDirectoryKeyPrefix)
                                  .source(directory.toPath())
                                  .maxDepth(includeSubdirectories ? Integer.MAX_VALUE : 1)
                                  .uploadFileRequestTransformer(builder -> {
                                      // 1.Replace `ObjectMetadataProvider`, `ObjectTaggingProvider`, and `ObjectCannedAclProvider` with an
                                        // `UploadFileRequestTransformer` that can combine the functionality of all three *Provider implementations.
                                        // 2. Convert your v1 `ObjectMetadata` to v2 `PutObjectRequest` parameters.
                                        // 3. Convert your v1 `ObjectTagging` to v2 `Tagging`.
                                        // 4. Convert your v1 `CannedAccessControlList` to v2 `ObjectCannedACL`.
                                  })
                                  .build();
        
DirectoryUpload directoryUpload = transferManager.uploadDirectory(request);
```

## Model object migration
<a name="s3-tm-migration-model-objects"></a>

In AWS SDK for Java 2.x, many of the `TransferManager` model objects have been redesigned, and several getter and setter methods available in v1's model objects are no longer supported. 

In v2, you can use the `CompletableFuture<T>` class to perform actions when the transfer completes—either successfully or with an exception. You can use the `join()` method to wait for completion if needed. 

### Core transfer objects
<a name="s3-tm-migration-core-transfer-objects"></a>


| V1 class | V2 class | Migration status | 
| --- | --- | --- | 
| TransferManager | S3TransferManager | Supported | 
| TransferManagerBuilder | S3TransferManager.Builder | Supported | 
| Transfer | Transfer | Supported | 
| AbortableTransfer | Transfer | Supported (no separate class) | 
| Copy | Copy | Supported | 
| Download | FileDownload | Supported | 
| Upload | Upload / FileUpload | Supported | 
| MultipleFileDownload | DirectoryDownload | Supported | 
| MultipleFileUpload | DirectoryUpload | Supported | 

### Persistence objects
<a name="s3-tm-migration-persistence-objects"></a>


| V1 class | V2 class | Migration status | 
| --- | --- | --- | 
| PersistableDownload | ResumableFileDownload | Supported | 
| PersistableUpload | ResumableFileUpload | Supported | 
| PersistableTransfer | ResumableTransfer | Supported | 
| PauseResult<T> | Direct resumable object | Not Supported | 

### Result objects
<a name="s3-tm-migration-result-objects"></a>


| V1 class | V2 class | Migration status | 
| --- | --- | --- | 
| CopyResult | CompletedCopy | Supported | 
| UploadResult | CompletedUpload | Supported | 

### Configuration objects
<a name="s3-tm-migration-configuration-objects"></a>


| V1 class | V2 class | Migration status | 
| --- | --- | --- | 
| TransferManagerConfiguration | MultipartConfiguration (on Amazon S3 client) | Supported | 
| TransferProgress | TransferProgress \$1 TransferProgressSnapshot | Supported | 
| KeyFilter | DownloadFilter | Supported | 

### Unsupported objects
<a name="s3-tm-migration-unsupported-objects"></a>


| V1 class | V2 alternative | Migration status | 
| --- | --- | --- | 
| PauseStatus | Not supported | Not Supported | 
| UploadContext | Not supported | Not Supported | 
| ObjectCannedAclProvider | PutObjectRequest.builder().acl() | Not Supported | 
| ObjectMetadataProvider | PutObjectRequest.builder().metadata() | Not Supported | 
| ObjectTaggingProvider | PutObjectRequest.builder().tagging() | Not Supported | 
| PresignedUrlDownload | Not supported | Not Supported | 

## TransferManagerBuilder configuration migration
<a name="s3-tm-migration-builder-configuration"></a>

### Configuration changes
<a name="migration-transfer-manager-config-changes"></a>

The configuration changes that you need to set for the v2 transfer manager depend on which S3 client that you use. You have the choice of the AWS CRT-based S3 client or the standard Java-based S3 async client. For information about the differences, see the [S3 clients in the AWS SDK for Java 2.x](examples-s3.md#s3-clients) topic.

------
#### [ Use the AWS CRT-based S3 client ]


****  

| Setting | v1 | v2 - Transfer Manager using AWS CRT-based S3 client | 
| --- | --- | --- | 
|    (get a builder)  |  <pre>TransferManagerBuilder tmBuilder = <br />   TransferManagerBuilder.standard();</pre>  |  <pre>S3TransferManager.Builder tmBuilder  = <br />  S3TransferManager.builder();</pre>  | 
|    S3 client  |  <pre>tmBuilder.withS3Client(...);<br />tmBuilder.setS3Client(...);</pre>  |  <pre>tmBuilder.s3Client(...);</pre>  | 
|    Executor  |  <pre>tmBuilder.withExecutorFactory(...);<br />tmBuilder.setExecutorFactory(...);</pre>  |  <pre>tmBuilder.executor(...);</pre>  | 
|    Shutdown thread pools  |  <pre>tmBuilder.withShutDownThreadPools(...);<br />tmBuilder.setShutdownThreadPools(...);</pre>  | Not supported. The provided executor will not be shut down when the S3TransferManager is closed | 
|    Minimum upload part size  |  <pre>tmBuilder.withMinimumUploadPartSize(...);<br />tmBuilder.setMinimumUploadPartSize(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.crtBuilder().<br />      minimumPartSizeInBytes(...).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    Multipart upload threshold  |  <pre>tmBuilder.withMultipartUploadThreshold(...);<br />tmBuilder.setMultipartUploadThreshold(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.crtBuilder().<br />      thresholdInBytes(...).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    Minimum copy part size  |  <pre>tmBuilder.withMultipartCopyPartSize(...);<br />tmBuilder.setMultipartCopyPartSize(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.crtBuilder().<br />      minimumPartSizeInBytes(...).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    Multipart copy threshold  |  <pre>tmBuilder.withMultipartCopyThreshold(...);<br />tmBuilder.setMultipartCopyThreshold(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.crtBuilder().<br />      thresholdInBytes(...).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    Disable parallel downloads  |  <pre>tmBuilder.withDisableParallelDownloads(...);<br />tmBuilder.setDisableParallelDownloads(...);</pre>  | Disable parallel downloads by passing a standard Java-based S3 client with multipart disabled (default) to the transfer manager.<pre>S3AsyncClient s3 =<br />   S3AsyncClient.builder().build();<br /><br />tmBuilder.s3Client(s3);</pre> | 
|    Always calculate multipart md5  |  <pre>tmBuilder.withAlwaysCalculateMultipartMd5(...);<br />tmBuilder.setAlwaysCalculateMultipartMd5(...);</pre>  | Not supported. | 

------
#### [ Use Java-based S3 async client ]


****  

| Setting | v1 | v2 - Transfer Manager using Java-based S3 async client | 
| --- | --- | --- | 
|    (get a builder)  |  <pre>TransferManagerBuilder tmBuilder = <br />   TransferManagerBuilder.standard();</pre>  |  <pre>S3TransferManager.Builder tmBuilder  = <br />  S3TransferManager.builder();</pre>  | 
|    S3 client  |  <pre>tmBuilder.withS3Client(...);<br />tmBuilder.setS3Client(...);</pre>  |  <pre>tmBuilder.s3Client(...);</pre>  | 
|    Executor  |  <pre>tmBuilder.withExecutorFactory(...);<br />tmBuilder.setExecutorFactory(...);</pre>  |  <pre>tmBuilder.executor(...);</pre>  | 
|    Shutdown thread pools  |  <pre>tmBuilder.withShutDownThreadPools(...);<br />tmBuilder.setShutdownThreadPools(...);</pre>  | Not supported. The provided executor will not be shut down when the S3TransferManager is closed | 
|    Minimum upload part size  |  <pre>tmBuilder.withMinimumUploadPartSize(...);<br />tmBuilder.setMinimumUploadPartSize(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.builder()<br />    .multipartConfiguration(cfg -><br />        cfg.minimumPartSizeInBytes(...)).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    Multipart upload threshold  |  <pre>tmBuilder.withMultipartUploadThreshold(...);<br />tmBuilder.setMultipartUploadThreshold(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.builder()<br />    .multipartConfiguration(cfg -><br />        cfg.thresholdInBytes(...)).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    Minimum copy part size  |  <pre>tmBuilder.withMultipartCopyPartSize(...);<br />tmBuilder.setMultipartCopyPartSize(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.builder()<br />    .multipartConfiguration(cfg -><br />        cfg.minimumPartSizeInBytes(...)).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    Multipart copy threshold  |  <pre>tmBuilder.withMultipartCopyThreshold(...);<br />tmBuilder.setMultipartCopyThreshold(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.builder()<br />    .multipartConfiguration(cfg -><br />        cfg.thresholdInBytes(...)).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    Disable parallel downloads  |  <pre>tmBuilder.withDisableParallelDownloads(...);<br />tmBuilder.setDisableParallelDownloads(...);</pre>  | Disable parallel downloads by passing a standard Java-based S3 client with multipart disabled (default) to the transfer manager.<pre>S3AsyncClient s3 =<br />   S3AsyncClient.builder().build();<br /><br />tmBuilder.s3Client(s3);</pre> | 
|    Always calculate multipart md5  |  <pre>tmBuilder.withAlwaysCalculateMultipartMd5(...);<br />tmBuilder.setAlwaysCalculateMultipartMd5(...);</pre>  | Not supported. | 

------

## Behavior changes
<a name="s3-tm-migration-behavior-changes"></a>

### Asynchronous operations
<a name="s3-tm-migration-async-operations"></a>

**V1 (blocking):**

```
Upload upload = transferManager.upload("amzn-s3-demo-bucket", "key", file);
upload.waitForCompletion(); // Blocks until complete
```

**V2 (asynchronous):**

```
FileUpload upload = transferManager.uploadFile(UploadFileRequest.builder()
    .putObjectRequest(PutObjectRequest.builder()
        .bucket("amzn-s3-demo-bucket")
        .key("key")
        .build())
    .source(file)
    .build());

CompletedFileUpload result = upload.completionFuture().join(); // Blocks until complete
// Or handle asynchronously:
upload.completionFuture().thenAccept(result -> {
    System.out.println("Upload completed: " + result.response().eTag());
});
```

### Error handling
<a name="s3-tm-migration-error-handling"></a>

**V1:** Directory transfers fail completely if any sub-request fails.

**V2:** Directory transfers complete successfully even if some sub-requests fail. Check for errors explicitly:

```
DirectoryUpload directoryUpload = transferManager.uploadDirectory(request);
CompletedDirectoryUpload result = directoryUpload.completionFuture().join();

// Check for failed transfers
if (!result.failedTransfers().isEmpty()) {
    System.out.println("Some uploads failed:");
    result.failedTransfers().forEach(failed -> 
        System.out.println("Failed: " + failed.exception().getMessage()));
}
```

### Parallel download via byte-range fetches
<a name="migration-transfer-manager-behavior-fetches"></a>

When the automatic parallel transfer feature is enabled in the v2 SDK, the S3 Transfer Manager uses [byte-range fetches](https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance-guidelines.html#optimizing-performance-guidelines-get-range) to retrieve specific portions of the object in parallel (multipart download). The way an object is downloaded with v2 does not depend on how the object was originally uploaded. All downloads can benefit from high throughput and concurrency. 

In contrast, with v1's Transfer Manager, it does matter how the object was originally uploaded. The v1 Transfer Manager retrieves the parts of the object the same way that the parts were uploaded. If an object was originally uploaded as a single object, the v1 Transfer Manager is not able to accelerate the downloading process by using sub-requests.

# Changes in parsing Amazon S3 URIs from version 1 to version 2
<a name="migration-s3-uri-parser"></a>

This topic details the changes in parsing Amazon S3 URIs from version 1 (v1) to version 2 (v2.).

## High-level changes
<a name="migration-3-uri-parser-api-changes"></a>

To begin parsing an S3 URI in v1, you instantiate an `AmazonS3URI` by using a constructor. In v2 you call `parseUri()` on an instance of `S3Utilities`, to return an `S3URI`.


****  

| Change | v1 | v2 | 
| --- | --- | --- | 
|    Maven dependencies  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.5871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency>  <br />        <groupId>com.amazonaws</groupId><br />        <artifactId>s3</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.212</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>s3</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| Package name | com.amazonaws.services.s3 | software.amazon.awssdk.services.s3 | 
| Class names | [AmazonS3URI](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3URI.html) | [S3URI](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Uri.html) | 

1 [Latest version](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom). 2 [Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

## API changes
<a name="migration-3-uri-parser-api-changes"></a>


| Behavior | v1 | v2 | 
| --- | --- | --- | 
| Parse an S3 URI. |  <pre>URI uri = URI.create( "https://s3.amazonaws.com");<br /><br />AmazonS3Uri s3Uri = <br />    new AmazonS3URI(uri, false);</pre>  |  <pre>S3Client s3Client = S3Client.create();<br />S3Utilities s3Utilities =<br />    s3Client.utilities();<br /><br />S3Uri s3Uri =<br />    s3Utilities.parseUri(uri);</pre>  | 
| Retrieve the bucket name from an S3 URI. |  <pre>String bucket = s3Uri.getBucket();</pre>  |  <pre>Optional<String> bucket = s3Uri.bucket();</pre>  | 
| Retrieve the key. |  <pre>String key = s3Uri.getKey();</pre>  |  <pre>Optional<String> key = s3Uri.key();</pre>  | 
| Retrieve the region. |  <pre>String region = s3Uri.getRegion();</pre>  |  <pre>Optional<Region> region = s3Uri.region();<br /><br />String region;<br />if (s3Uri.region().isPresent()) {<br />    region = s3Uri.region().get().id();<br />}</pre>  | 
|  Retrieve whether the S3 URI is path style.  |  <pre>boolean isPathStyle = s3Uri.isPathStyle();</pre>  |  <pre>boolean isPathStyle = s3Uri.isPathStyle();</pre>  | 
| Retrieve the version ID. |  <pre>String versionId = s3Uri.getVersionId();</pre>  |  <pre>Optional<String> versionId = <br />    s3Uri.firstMatchingRawQueryParameter("versionId");</pre>  | 
| Retrieve the query parameters. | N/A |  <pre>Map<String, List<String>> queryParams =<br />    s3Uri.rawQueryParameters();</pre>  | 

### Behavior changes
<a name="migration-s3-uri-parser-behavior-changes"></a>

#### URL encoding
<a name="migration-s3-uri-parser-behavior-changes-URLencoding"></a>

v1 provides the option to pass in a flag to specify whether the URI should be URL encoded. The default value is `true`. 

In v2, URL encoding is not supported. If you work with object keys or query parameters that have reserved or unsafe characters, you must URL encode them. For example you need to replace a whitespace `" "` with `%20`.

# Changes in the S3 Event Notifications API from version 1 to version 2
<a name="migration-s3-event-notification"></a>

This topic details the changes in the S3 Event Notifications API from version 1.x (v1) to version 2 .x (v2) of the AWS SDK for Java.

## High-level changes
<a name="migration-s3-event-notification-hl"></a>

### Structural changes
<a name="migration-s3-event-notification-hl-struct"></a>

V1 uses static inner classes for `EventNotificationRecord` types and their attributes, whereas v2 uses separate public classes for `EventNotificationRecord` types.

### Naming convention changes
<a name="migration-s3-event-notification-hl-naming"></a>

In v1, attribute class names include the suffix *Entity*, whereas v2 omits this suffix for simpler naming: for example, *eventData* instead of *eventDataEntity*.

## Changes in dependencies, packages and class names
<a name="migration-s3-event-notification-deps"></a>

In v1, S3 Event Notification API classes are transitively imported with along with the S3 module (artifactId `aws-java-sdk-s3`). However, in v2, you need to add a dependency on the `s3-event-notifications` artifact.


****  

| Change | v1 | v2 | 
| --- | --- | --- | 
|    Maven dependencies  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.X.X</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-s3</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.X.X1</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>s3-event-notifications</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| Package name | com.amazonaws.services.s3.event | software.amazon.awssdk.eventnotifications.s3.model | 
| Class names |  [S3EventNotification](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.html) [S3EventNotification.S3EventNotificationRecord](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.S3EventNotificationRecord.html) [ S3EventNotification.GlacierEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.GlacierEventDataEntity.html) [S3EventNotification.IntelligentTieringEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.IntelligentTieringEventDataEntity.html) [S3EventNotification.LifecycleEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.LifecycleEventDataEntity.html) [S3EventNotification.ReplicationEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.ReplicationEventDataEntity.html) [S3EventNotification.RequestParametersEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.RequestParametersEntity.html) [S3EventNotification.ResponseElementsEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.ResponseElementsEntity.html) [S3EventNotification.RestoreEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.RestoreEventDataEntity.html) [S3EventNotification.S3BucketEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.S3BucketEntity.html) [ S3EventNotification.S3Entity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.S3Entity.html) [S3EventNotification.S3ObjectEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.S3ObjectEntity.html) [S3EventNotification.TransitionEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.TransitionEventDataEntity.html) [S3EventNotification.UserIdentityEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.UserIdentityEntity.html)  |   [S3EventNotification](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotification.html) [S3EventNotificationRecord](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationRecord.html) [GlacierEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/GlacierEventData.html) [IntelligentTieringEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/IntelligentTieringEventData.html) [LifecycleEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/LifecycleEventData.html) [ReplicationEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/ReplicationEventData.html) [RequestParameters](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/RequestParameters.html) [ResponseElements](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/ResponseElements.html) [RestoreEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/RestoreEventData.html) [S3Bucket](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3Bucket.html) [S3](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3.html) [S3Object](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3Object.html) [TransitionEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/TransitionEventData.html) [UserIdentity](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/UserIdentity.html)  | 

1 [Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

## API changes
<a name="migration-s3-event-notification-API-changes"></a>

### JSON to `S3EventNotification` and reverse
<a name="migration-s3-event-notification-API-changes-conv"></a>


| Use case | v1 | v2 | 
| --- | --- | --- | 
| Create S3EventNotification from JSON String |  <pre>S3EventNotification notification = <br />        S3EventNotification.parseJson(message.body());</pre>  |  <pre>S3EventNotification notification = <br />        S3EventNotification.fromJson(message.body());</pre>  | 
| Convert S3EventNotification to JSON String |  <pre>String json = notification.toJson();</pre>  |  <pre>String json = notification.toJson();</pre>  | 

### Access attributes of `S3EventNotification`
<a name="migration-s3-event-notification-API-changes-attr"></a>


| Use case | v1 | v2 | 
| --- | --- | --- | 
| Retrieve records from a notification |  <pre>List<S3EventNotification.S3EventNotificationRecord> records = <br />        notifcation.getRecords();</pre>  |  <pre>List<S3EventNotificationRecord> records = <br />        notification.getRecords();</pre>  | 
| Retrieve a record from a list of records |  <pre>S3EventNotification.S3EventNotificationRecord record = <br />        records.stream().findAny().get();</pre>  |  <pre>S3EventNotificationRecord record = <br />        records.stream().findAny().get();</pre>  | 
| Retrieve Glacier event data |  <pre>S3EventNotification.GlacierEventDataEntity glacierEventData =<br />        record.getGlacierEventData();</pre>  |  <pre>GlacierEventData glacierEventData = <br />        record.getGlacierEventData();</pre>  | 
| Retrieve restore event data from a Glacier event |  <pre>S3EventNotification.RestoreEventDataEntity restoreEventData = <br />        glacierEventData.getRestoreEventDataEntity();</pre>  |  <pre>RestoreEventData restoreEventData = <br />        glacierEventData.getRestoreEventData();</pre>  | 
| Retrieve request parameters |  <pre>S3EventNotification.RequestParametersEntity requestParameters = <br />        record.getRequestParameters();</pre>  |  <pre>RequestParameters requestParameters = <br />        record.getRequestParameters();</pre>  | 
| Retrieve Intelligent Tiering event data |  <pre>S3EventNotification.IntelligentTieringEventDataEntity tieringEventData = <br />        record.getIntelligentTieringEventData();</pre>  |  <pre>IntelligentTieringEventData intelligentTieringEventData = <br />        record.getIntelligentTieringEventData();</pre>  | 
| Retrieve lifecyle event data |  <pre>S3EventNotification.LifecycleEventDataEntity lifecycleEventData = <br />        record.getLifecycleEventData();</pre>  |  <pre>LifecycleEventData lifecycleEventData = <br />        record.getLifecycleEventData();</pre>  | 
| Retrieve event name as enum |  <pre>S3Event eventNameAsEnum = record.getEventNameAsEnum();</pre>  |  <pre>//getEventNameAsEnum does not exist; use 'getEventName()'<br />String eventName = record.getEventName();</pre>  | 
| Retrieve replication event data |  <pre>S3EventNotification.ReplicationEventDataEntity replicationEntity = <br />        record.getReplicationEventDataEntity();</pre>  |  <pre>ReplicationEventData replicationEventData = <br />        record.getReplicationEventData();</pre>  | 
| Retrieve S3 bucket and object information |  <pre>S3EventNotification.S3Entity s3 = record.getS3();</pre>  |  <pre>S3 s3 = record.getS3();</pre>  | 
| Retrieve user identity information |  <pre>S3EventNotification.UserIdentityEntity userIdentity = <br />        record.getUserIdentity();</pre>  |  <pre>UserIdentity userIdentity = <br />        record.getUserIdentity();</pre>  | 
| Retrieve response elements |  <pre>S3EventNotification.ResponseElementsEntity responseElements = <br />        record.getResponseElements();</pre>  |  <pre>ResponseElements responseElements = <br />        record.getResponseElements();</pre>  | 

## Migrate the `aws-lambda-java-events` library version
<a name="migration-s3-events-notification-lambda-lib"></a>

If you use [aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-events) to work with S3 notification events within a Lambda function, we recommend that you upgrade to the latest 3.x.x version. Recent versions eliminate all dependencies on AWS SDK for Java 1.x from the S3 event notification API.

For more information about the differences in handling S3 event notifications between the `aws-lambda-java-events` library and the SDK for Java 2.x, see [Process S3 Events in Lambda with Java Libraries: AWS SDK for Java 2.x and `aws-lambda-java-events`](examples-s3-event-notifications.md#s3-event-notif-processing-options).

# Profile file changes
<a name="migration-profile-file"></a>

The AWS SDK for Java 2.x parses the profile definitions in `~/.aws/config` and `~/.aws/credentials` to more closely emulate the way the AWS CLI parses the files.

The SDK for Java 2.x:
+ Resolves a `~/` or `~` followed by the file system's default path separator at the start of the path by checking, in order, `$HOME`, `$USERPROFILE` (Windows only), `$HOMEDRIVE`, `$HOMEPATH` (Windows only), and then the `user.home` system property.
+ Looks for the `AWS_SHARED_CREDENTIALS_FILE` environment variable instead of `AWS_CREDENTIAL_PROFILES_FILE`.
+ Silently drops profile definitions in configuration files without the word `profile` at the beginning of the profile name.
+ Silently drops profile definitions that do not consist of alphanumeric, underscore or dash characters (after the leading `profile` word has been removed for configuration files).
+ Merges settings of profile definitions duplicated within the same file.
+ Merges settings of profile definitions duplicated in both the configuration and credentials files.
+ Does NOT merge settings if both `[profile foo]` and `[foo]` are found in the same file.
+ Uses settings in `[profile foo]` if both `[profile foo]` and `[foo]` are found in the configuration file.
+ Uses the value of the last duplicated setting in the same file and profile.
+ Recognizes both `;` and `#` for defining a comment.
+ Recognizes `;` and `#` in profile definitions to define a comment, even if the characters are adjacent to the closing bracket.
+ Recognizes `;` and `#` to define a comment only in setting values only if they are preceded by whitespace.
+ Recognizes `;` and `#` and all following content in setting values if they are not preceded by whitespace.
+ Considers role-based credentials the highest-priority credentials. The 2.x SDK always uses role-based credentials if the user specifies the `role_arn` property.
+ Considers session-based credentials the second-highest-priority credentials. The 2.x SDK always uses session-based credentials if role-based credentials were not used and the user specifies the `aws_access_key_id` and `aws_session_token` properties.
+ Uses basic credentials if role-based and session-based credentials are not used and the user specified the `aws_access_key_id` property.

# Environment variables and system properties changes
<a name="migration-env-and-system-props"></a>


| 1.x Environment Variable | 1.x System Property | 2.x Environment Variable | 2.x System Property | 
| --- | --- | --- | --- | 
| AWS\$1ACCESS\$1KEY\$1IDAWS\$1ACCESS\$1KEY | aws.accessKeyId | AWS\$1ACCESS\$1KEY\$1ID | aws.accessKeyId | 
| AWS\$1SECRET\$1KEYAWS\$1SECRET\$1ACCESS\$1KEY | aws.secretKey | AWS\$1SECRET\$1ACCESS\$1KEY | aws.secretAccessKey | 
| AWS\$1SESSION\$1TOKEN | aws.sessionToken | AWS\$1SESSION\$1TOKEN | aws.sessionToken | 
| AWS\$1REGION | aws.region | AWS\$1REGION | aws.region | 
| AWS\$1CONFIG\$1FILE |   | AWS\$1CONFIG\$1FILE | aws.configFile | 
| AWS\$1CREDENTIAL\$1PROFILES\$1FILE |   | AWS\$1SHARED\$1CREDENTIALS\$1FILE | aws.sharedCredentialsFile | 
| AWS\$1PROFILE | aws.profile | AWS\$1PROFILE | aws.profile | 
| AWS\$1EC2\$1METADATA\$1DISABLED | com.amazonaws.sdk.disableEc2Metadata | AWS\$1EC2\$1METADATA\$1DISABLED | aws.disableEc2Metadata | 
|   | com.amazonaws.sdk.ec2MetadataServiceEndpointOverride | AWS\$1EC2\$1METADATA\$1SERVICE\$1ENDPOINT | aws.ec2MetadataServiceEndpoint | 
| AWS\$1CONTAINER\$1CREDENTIALS\$1RELATIVE\$1URI |   | AWS\$1CONTAINER\$1CREDENTIALS\$1RELATIVE\$1URI | aws.containerCredentialsPath | 
| AWS\$1CONTAINER\$1CREDENTIALS\$1FULL\$1URI |   | AWS\$1CONTAINER\$1CREDENTIALS\$1FULL\$1URI | aws.containerCredentialsFullUri | 
| AWS\$1CONTAINER\$1AUTHORIZATION\$1TOKEN |   | AWS\$1CONTAINER\$1AUTHORIZATION\$1TOKEN | aws.containerAuthorizationToken | 
| AWS\$1CBOR\$1DISABLED | com.amazonaws.sdk.disableCbor | CBOR\$1ENABLED | aws.cborEnabled | 
| AWS\$1ION\$1BINARY\$1DISABLE | com.amazonaws.sdk.disableIonBinary | BINARY\$1ION\$1ENABLED | aws.binaryIonEnabled | 
| AWS\$1EXECUTION\$1ENV |   | AWS\$1EXECUTION\$1ENV | aws.executionEnvironment | 
|   | com.amazonaws.sdk.disableCertChecking | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
|   | com.amazonaws.sdk.enableDefaultMetrics | [Not supported](https://github.com/aws/aws-sdk-java-v2/issues/23) | [Not supported](https://github.com/aws/aws-sdk-java-v2/issues/23) | 
|   | com.amazonaws.sdk.enableThrottledRetry | [Not supported](https://github.com/aws/aws-sdk-java-v2/issues/645) | [Not supported](https://github.com/aws/aws-sdk-java-v2/issues/645) | 
|   | com.amazonaws.regions.RegionUtils.fileOverride | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
|   | com.amazonaws.regions.RegionUtils.disableRemote | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
|   | com.amazonaws.services.s3.disableImplicitGlobalClients | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 
|   | com.amazonaws.sdk.enableInRegionOptimizedMode | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | Not supported ([Request feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | 

# Changes in Waiters from version 1 to version 2
<a name="migration-waiters"></a>

This topic details the changes in the functionality of Waiters from version 1 (v1) to version 2 (v2).

The following tables demonstrate the difference for DynamoDB waiters specifically. Waiters for other services follow the same pattern.

## High-level changes
<a name="migration-waiters-api-changes"></a>

Waiters classes are in the same Maven artifact as the service. 


| Change | v1 | v2 | 
| --- | --- | --- | 
|    Maven dependencies  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.6801</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>dynamodb</artifactId><br />    </dependency><br /></dependencies><br /></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.102</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>dynamodb</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| Package name | com.amazonaws.services.dynamodbv2.waiters | software.amazon.awssdk.services.dynamodb.waiters | 
| Class names |  `[AmazonDynamoDBWaiters](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/waiters/AmazonDynamoDBWaiters.html)`  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-waiters.html)  | 

1 [Latest version](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom). 2 [Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

## API changes
<a name="migration-cf-presign-behavior-changes"></a>


| Change | v1 | v2 | 
| --- | --- | --- | 
| Create a waiter |  <pre>AmazonDynamoDB client = AmazonDynamoDBClientBuilder <br />                            .standard().build();<br />AmazonDynamoDBWaiters waiter = client.waiters();</pre>  | Synchronous:<pre>DynamoDbClient client = DynamoDbClient.create();<br />DynamoDbWaiter waiter = client.waiter();</pre>Asynchronous:<pre>DynamoDbAsyncClient asyncClient = <br />        DynamoDbAsyncClient.create();<br />DynamoDbAsyncWaiter waiter = asyncClient.waiter();</pre> | 
| Wait until a table exists | Synchronous:<pre>waiter.tableExists()<br />    .run(new WaiterParameters<>(<br />        new DescribeTableRequest(tableName)));</pre>Asynchronous:<pre>waiter.tableExists()<br />    .runAsync(new WaiterParameters()<br />      .withRequest(new DescribeTableRequest(tableName)),<br />          new WaiterHandler() {<br />              @Override<br />              public void onWaitSuccess(<br />                  AmazonWebServiceRequest amazonWebServiceRequest) {<br />                    System.out.println("Table creation succeeded");<br />              }<br /><br />              @Override<br />              public void onWaitFailure(Exception e) {<br />                  e.printStackTrace();<br />              }<br />          }).get();</pre> |  Synchronous: <pre>WaiterResponse<DescribeTableResponse> waiterResponse =<br />    waiter.waitUntilTableExists(<br />        r -> r.tableName("myTable"));<br />waiterResponse.matched().response()<br />       .ifPresent(System.out::println);</pre> Asynchronous: <pre>waiter.waitUntilTableExists(r -> r.tableName(tableName))<br />           .whenComplete((r, t) -> {<br />               if (t != null) {<br />                   t.printStackTrace();<br />               } else {<br />                   System.out.println(<br />                        "Table creation succeeded");<br />               }<br />           }).join();</pre>  | 

## Configuration changes
<a name="migration-waiters-config"></a>


| Change | v1 | v2 | 
| --- | --- | --- | 
| Polling Strategy (max attempts and fixed delay) |  <pre>MaxAttemptsRetryStrategy maxAttemptsRetryStrategy = <br />        new MaxAttemptsRetryStrategy(10);<br /><br />FixedDelayStrategy fixedDelayStrategy = <br />        new FixedDelayStrategy(3);<br /><br />PollingStrategy pollingStrategy = <br />        new PollingStrategy(maxAttemptsRetryStrategy, <br />                fixedDelayStrategy);<br /><br />waiter.tableExists().run(<br />        new WaiterParameters<>(<br />            new DescribeTableRequest(tableName)), <br />                pollingStrategy);</pre>  |  <pre><br />FixedDelayBackoffStrategy fixedDelayBackoffStrategy = <br />        FixedDelayBackoffStrategy<br />            .create(Duration.ofSeconds(3));<br /><br />waiter.waitUntilTableExists(r -> r.tableName(tableName),<br />        c -> c.maxAttempts(10)<br />                .backoffStrategy(fixedDelayBackoffStrategy));</pre>  | 

# Changes in the EC2 metadata utility from version 1 to version 2
<a name="migration-imds"></a>

This topic details the changes in the SDK for Java Amazon Elastic Compute Cloud (EC2) metadata utility from version 1 (v1) to version 2 (v2).

## High-level changes
<a name="migration-imds-high-level-changes"></a>


****  

| Change | v1 | v2 | 
| --- | --- | --- | 
|    Maven dependencies  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.5871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-core</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.212</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>imds</artifactId><br />    </dependency><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>apache-client3</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| Package name |  com.amazonaws.util  |  software.amazon.awssdk.imds  | 
| Instantiation approach |  Use static utility methods; no instantiation: <pre>String localHostName = <br />           EC2MetadataUtils.getLocalHostName();</pre>  |  Use a static factory method: <pre>Ec2MetadataClient client = Ec2MetadataClient.create();</pre> Or use a builder approach: <pre>Ec2MetadataClient client = Ec2MetadataClient.builder()<br />    .endpointMode(EndpointMode.IPV6)<br />    .build();</pre>  | 
| Types of clients | Synchronous only utility methods: EC2MetadataUtils |  Synchronous: `Ec2MetadataClient` Asynchronous: `Ec2MetadataAsyncClient`  | 

1 [Latest version](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom). 2 [Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

3Notice the declaration of the `apache-client` module for v2. V2 of the EC2 metadata utility requires an implementation of the `SdkHttpClient` interface for the synchronous metadata client, or the `SdkAsyncHttpClient` interface for the asynchronous metadata client. The [Configure HTTP clients in the AWS SDK for Java 2.x](http-configuration.md) section shows the list of HTTP clients that you can use.

### Requesting metadata
<a name="migration-imds-fetching-changes"></a>

In v1, you use static methods that accept no parameters to request metadata for an EC2 resource. In contrast, you need to specify the path to the EC2 resource as a parameter in v2. The following table shows the different approaches.


****  

| v1 | v2 | 
| --- | --- | 
|  <pre>String userMetaData = EC2MetadataUtils.getUserData();</pre>  |  <pre>Ec2MetadataClient client = Ec2MetadataClient.create();<br />Ec2MetadataResponse response = <br />                client.get("/latest/user-data");<br />String userMetaData = <br />                response.asString();</pre>  | 

Refer to the [instance metadata categories](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/instancedata-data-categories.html) to find the path you need to supply to request a piece of metadata. 

**Note**  
When you use an instance metadata client in v2, you should aim to use the same client for all request to retrieve metadata.

 

## Behavior changes
<a name="migration-imds-behavior-changes"></a>

### JSON data
<a name="migration-imds-behavior-json"></a>

On EC2, the locally running Instance Metadata Service (IMDS) returns some metadata as JSON formatted strings. One such example is the dynamic metadata of an [instance identity document](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/instance-identity-documents.html).

The v1 API contains separate methods for each piece of instance identity metadata, whereas the v2 API directly returns the JSON string. To work with the JSON string, you can use the [Document API ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/document/package-summary.html) to parse the response and navigate the JSON structure.

The following table compares how you retrieve metadata of an instance identity document in v1 and v2.


****  

| Use case | v1 | v2 | 
| --- | --- | --- | 
| Retrieve the Region |  <pre>InstanceInfo instanceInfo = <br />        EC2MetadataUtils.getInstanceInfo();<br />String region = instanceInfo.getRegion();</pre>  |  <pre>Ec2MetadataResponse response = <br />    client.get("/latest/dynamic/instance-identity/document");<br />Document instanceInfo = response.asDocument();<br />String region = instanceInfo.asMap().get("region").asString();</pre>  | 
| Retrieve the instance id |  <pre>InstanceInfo instanceInfo = <br />        EC2MetadataUtils.getInstanceInfo();<br />String instanceId = instanceInfo.instanceId;</pre>  |  <pre>Ec2MetadataResponse response = <br />    client.get("/latest/dynamic/instance-identity/document");<br />Document instanceInfo = response.asDocument();<br />String instanceId = instanceInfo.asMap().get("instanceId").asString();</pre>  | 
| Retrieve the instance type |  <pre>InstanceInfo instanceInfo = <br />        EC2MetadataUtils.getInstanceInfo();<br />String instanceType = instanceInfo.instanceType();</pre>  |  <pre>Ec2MetadataResponse response = <br />    client.get("/latest/dynamic/instance-identity/document");<br />Document instanceInfo = response.asDocument();<br />String instanceType = instanceInfo.asMap().get("instanceType").asString();</pre>  | 

### Endpoint resolution differences
<a name="migration-imds-behavior-endpoint-res"></a>

The following table shows the locations that the SDK checks to resolve the endpoint to IMDS. The locations are listed in descending priority.


****  

| v1 | v2 | 
| --- | --- | 
| System property: com.amazonaws.sdk.ec2MetadataServiceEndpointOverride | Client builder configuration method: endpoint(...) | 
| Environment variable: AWS\$1EC2\$1METADATA\$1SERVICE\$1ENDPOINT | System property: aws.ec2MetadataServiceEndpoint | 
| Default Value: http://169.254.169.254 | Config file: \$1.aws/config with the ec2\$1metadata\$1service\$1endpoint setting | 
|  | Value associated with resolved endpoint-mode  | 
|  | Default value: http://169.254.169.254 | 

### Endpoint resolution in v2
<a name="migration-imds-behavior-endpoint-res2"></a>

When you explicitly set an endpoint by using the builder, that endpoint value takes priority over all other settings. When the following code executes, the `aws.ec2MetadataServiceEndpoint` system property and config file `ec2_metadata_service_endpoint` setting are ignored if they exist.

```
Ec2MetadataClient client = Ec2MetadataClient
  .builder()
  .endpoint(URI.create("endpoint.to.use"))
  .build();
```

#### Endpoint-mode
<a name="migration-imds-behavior-endpoint-mode"></a>

With v2, you can specify an endpoint-mode to configure the metadata client to use the default endpoint values for IPv4 or IPv6. Endpoint-mode is not available for v1. The default value used for IPv4 is `http://169.254.169.254` and `http://[fd00:ec2::254]` for IPv6.

The following table shows the different ways that you can set the endpoint mode in order of descending priority.


****  

|  |  | Possible values | 
| --- | --- | --- | 
| Client builder configuration method: endpointMode(...) |  <pre>Ec2MetadataClient client = Ec2MetadataClient<br />  .builder()<br />  .endpointMode(EndpointMode.IPV4)<br />  .build();</pre>  | EndpointMode.IPV4, EndpointMode.IPV6 | 
| System property | aws.ec2MetadataServiceEndpointMode | IPv4, IPv6 (case does not matter) | 
| Config file: \$1.aws/config | ec2\$1metadata\$1service\$1endpoint setting | IPv4, IPv6 (case does not matter) | 
| Not specified in the previous ways | IPv4 is used |  | 

#### How the SDK resolves `endpoint` or `endpoint-mode` in v2
<a name="migration-imds-behavior-endpoint-res2-which"></a>

1. The SDK uses the value that you set in code on the client builder and ignores any external settings. Because the SDK throws an exception if both `endpoint` and `endpointMode` are called on the client builder, the SDK uses the endpoint value from whichever method you use.

1. If you do not set a value in code, the SDK looks to external configuration—first for system properties and then for a setting in the config file. 

   1. The SDK first checks for an endpoint value. If a value is found, it is used. 

   1. If the SDK still hasn't found a value, the SDK looks for endpoint mode settings.

1. Finally, if the SDK finds no external settings and you have not configured the metadata client in code, the SDK uses the IPv4 value of `http://169.254.169.254`.

### IMDSv2
<a name="migration-imds-behavior-imdsv2"></a>

Amazon EC2 defines two approaches to access instance metadata:
+ Instance Metadata Service Version 1 (IMDSv1) – Request/response approach
+ Instance Metadata Service Version 2 (IMDSv2) – Session-oriented approach

The following table compares how the Java SDKs work with IMDS.


****  

| v1 | v2 | 
| --- | --- | 
| IMDSv2 is used by default | Always uses IMDSv2 | 
| Attempts to fetch a session token for each request and falls back to IMDSv1 if it fails to fetch a session token | Keeps a session token in an internal cache that is reused for multiple requests | 

The SDK for Java 2.x supports only IMDSv2 and does not fall back to IMDSv1.

## Configuration differences
<a name="migration-imds-config-diffs"></a>

The following table lists the differing configuration options.


****  

| Configuration | v1 | v2 | 
| --- | --- | --- | 
| Retries | Configuration not available | Configurable through builder method retryPolicy(...) | 
| HTTP | Connection timeout configurable through the AWS\$1METADATA\$1SERVICE\$1TIMEOUT environment variable. The default is 1 second. | Configuration available by passing an HTTP client to the builder method httpClient(...). The default connection timeout for HTTP clients is 2 seconds. | 

### Example v2 HTTP configuration
<a name="migration-imds-http-conf-v2-ex"></a>

The following example shows how you can configure the metadata client. This example configures the connection timeout and uses the Apache HTTP client.

```
SdkHttpClient httpClient = ApacheHttpClient.builder()
    .connectionTimeout(Duration.ofSeconds(1))
    .build();

Ec2MetadataClient imdsClient = Ec2MetadataClient.builder()
    .httpClient(httpClient)
    .build();
```

# Changes in Amazon CloudFront presigning from version 1 to version 2
<a name="migration-cloudfront-presigning"></a>

This topic details the changes in the Amazon CloudFront from version 1 (v1) to version 2 (v2).

## High-level changes
<a name="migration-cloudfront-presigning-api-changes"></a>


****  

| Change | v1 | v2 | 
| --- | --- | --- | 
|    Maven dependencies  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.5871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency>  <br />        <groupId>com.amazonaws</groupId><br />        <artifactId>cloudfront</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.212</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>cloudfront</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| Package name | com.amazonaws.services.cloudfront | software.amazon.awssdk.services.cloudfront | 
| Class names |  [CloudFrontUrlSigner](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/cloudfront/CloudFrontUrlSigner.html) [CloudFrontCookieSigner](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/cloudfront/CloudFrontCookieSigner.html)  |  [CloudFrontUtilities](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.html) [SignedUrl](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudfront/url/SignedUrl.html) [CannedSignerRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudfront/model/CannedSignerRequest.html) [CustomSignerRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudfront/model/CustomSignerRequest.html)  | 

1 [Latest version](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom). 2 [Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

## API changes
<a name="migration-cf-presign-behavior-changes"></a>


| Behavior | v1 | v2 | 
| --- | --- | --- | 
| Build a canned request | Arguments are passed directly to the API. |  <pre>CannedSignerRequest cannedRequest =<br />      CannedSignerRequest.builder()<br />                         .resourceUrl(resourceUrl)<br />                         .privateKey(privateKey)<br />                         .keyPairId(keyPairId)<br />                         .expirationDate(expirationDate)<br />                         .build();</pre>  | 
| Build a custom request | Arguments are passed directly to the API. |  <pre>CustomSignerRequest customRequest =<br />      CustomSignerRequest.builder()<br />                         .resourceUrl(resourceUrl)<br />                         .resourceUrlPattern(resourceUrlPattern)<br />                         .privateKey(keyFile)<br />                         .keyPairId(keyPairId)<br />                         .expirationDate(expirationDate)<br />                         .activeDate(activeDate)<br />                         .ipRange(ipRange)<br />                         .build();</pre>  | 
| Generate a signed URL (canned) |  <pre>String signedUrl =<br />  CloudFrontUrlSigner.getSignedURLWithCannedPolicy(<br />    resourceUrl, keyPairId, privateKey, expirationDate);</pre>  |  <pre>CloudFrontUtilities cloudFrontUtilities =<br />    CloudFrontUtilities.create();<br /><br />SignedUrl signedUrl =        <br />    cloudFrontUtilities.getSignedUrlWithCannedPolicy(cannedRequest);<br /><br />String url = signedUrl.url();<br /></pre>  | 
| Generate a signed cookie (custom) |  <pre>CookiesForCustomPolicy cookies =<br />    CloudFrontCookieSigner.getCookiesForCustomPolicy(<br />        resourceUrl, privateKey, keyPairId, expirationDate, <br />        activeDate, ipRange);<br /></pre>  |  <pre>CloudFrontUtilities cloudFrontUtilities =<br />    CloudFrontUtilities.create();<br /><br />CookiesForCustomPolicy cookies =<br />     cloudFrontUtilities.getCookiesForCustomPolicy(customRequest);<br /></pre>  | 

### Refactored cookie headers in v2
<a name="migration-cf-presign-behavior-headers"></a>

In Java v1, the Java SDK delivers cookie headers as a `Map.Entry<String, String>`.

```
Map.Entry<String, String> signatureMap = cookies.getSignature();
String signatureKey = signatureMap.getKey(); // "CloudFront-Signature"
String signatureValue = signatureMap.getValue(); // "[SIGNATURE_VALUE]"
```

The Java v2 SDK delivers the entire header as a single `String`.

```
String signatureHeaderValue = cookies.signatureHeaderValue(); // "CloudFront-Signature=[SIGNATURE_VALUE]"
```

# Changes in the IAM Policy Builder API from version 1 to version 2
<a name="migration-iam-policy-builder"></a>

This topic details the changes in the IAM Policy Builder API from version 1 (v1) to version 2 (v2).

## High-level changes
<a name="migration-iam-policy-builder-high-level"></a>


****  

| Change | v1 | v2 | 
| --- | --- | --- | 
|    Maven dependencies  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.5871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-core</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.212</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>iam-policy-builder</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| Package name | com.amazonaws.auth.policy | software.amazon.awssdk.policybuilder.iam | 
| Class names |  [Policy](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Policy.html) [Statement](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Statement.html) [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-iam-policy-builder.html)  |  [IamPolicy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamPolicy.html) [IamStatement](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamStatement.html) [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration-iam-policy-builder.html)  | 

1 [Latest version](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom). 2 [Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

## API changes
<a name="migration-iam-policy-builder-api"></a>


****  

| Setting | v1 | v2 | 
| --- | --- | --- | 
|  Instantiate a policy |  <pre>Policy policy = new Policy();</pre>  |  <pre>IamPolicy.Builder policyBuilder = IamPolicy.builder();<br />...<br />IamPolicy policy = policyBuilder.build();</pre>  | 
|    Set id  |  <pre>policy.withtId(...);<br />policy.setId(...);</pre>  |  <pre>policyBuilder.id(...);</pre>  | 
|    Set version  | N/A - uses default version of 2012-10-17 |  <pre>policyBuilder.version(...);</pre>  | 
|    Create statement  |  <pre>Statement statement = <br />    new Statement(Effect.Allow)<br />            .withActions(...)<br />            .withConditions(...)<br />            .withId(...)<br />            .withPrincipals(...)<br />            .withResources(...);</pre>  |  <pre>IamStatement statement = <br />    IamStatement.builder()<br />            .effect(IamEffect.ALLOW)<br />            .actions(...)<br />            .notActions(...)<br />            .conditions(...)<br />            .sid(...)<br />            .principals(...)<br />            .notPrincipals(...)<br />            .resources(...)<br />            .notResources(...)<br />            .build()</pre>  | 
|    Set statement  |  <pre>policy.withStatements(statement);<br />policy.setStatements(statement);</pre>  |  <pre>policyBuilder.addStatement(statement);</pre>  | 

## Differences in building a statement
<a name="migration-iam-policy-builder-statement"></a>

### Actions
<a name="migration-iam-policy-builder-statement-actions"></a>

#### v1
<a name="migration-iam-policy-builder-statement-actions.v1"></a>

The v1 SDK has [`enum` types](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Action.html) for service actions that represent `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html)` elements in a policy statement. The following `enum` types are some examples.
+ `[IdentityManagementActions](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/actions/IdentityManagementActions.html)`
+ `[DynamoDBv2Actions](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/actions/DynamoDBv2Actions.html)`
+ `[SQSActions](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/actions/SQSActions.html)`

The following example shows the `SendMessage` constant for `SQSActions`.

```
Action action = SQSActions.SendMessage;
```

You cannot specify a `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html)` element to a statement in v1.

#### v2
<a name="migration-iam-policy-builder-statement-actions.v2"></a>

In v2, the [IamAction](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamAction.html) interface represents all actions. To specify a [service-specific action](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html) element, pass a string to the `create` method as shown in the following code.

```
IamAction action = IamAction.create("sqs:SendMessage");
```

You can specify a `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html)` for a statement with v2 as shown in the following code.

```
IamAction action = IamAction.create("sqs:SendMessage");
IamStatement.builder().addNotAction(action);
```

### Conditions
<a name="migration-iam-policy-builder-statement-conditions"></a>

#### v1
<a name="migration-iam-policy-builder-statement-conditions-v1"></a>

To represent statement conditions, the v1 SDK uses subclasses of [https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Condition.html](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Condition.html). 
+  [ArnCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/ArnCondition.html) 
+  [BooleanCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/BooleanCondition.html)
+  [DateCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/DateCondition.html)
+ [IpAddressCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/IpAddressCondition.html)
+ [NumericCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/NumericCondition.html)
+ [ StringCondition ](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/StringCondition.html)

Each `Condition` subclass defines a comparison `enum` type to help define the condition. For example, the following shows a *not like*[ string comparison](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_String) for a condition.

```
Condition condition = new StringCondition(StringComparisonType.StringNotLike, "key", "value");
```

#### v2
<a name="migration-iam-policy-builder-statement-conditions-v2"></a>

In v2, you build a condition for a policy statement by using `[IamCondition](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamCondition.html)` and provide an `[IamConditionOperator](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamConditionOperator.html)`, which contains `enums` for all types.

```
IamCondition condition = IamCondition.create(IamConditionOperator.STRING_NOT_LIKE, "key", "value");
```

### Resources
<a name="migration-iam-policy-builder-statement-resources"></a>

#### v1
<a name="migration-iam-policy-builder-statement-resources-v1"></a>

A policy statement's `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html)` element is represented by the SDK's `[Resource](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Resource.html)` class. You supply the ARN as a string in the constructor. The following subclasses provide convenience constructors.
+ [S3BucketResource](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/resources/S3BucketResource.html)
+ [S3ObjectResource](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/resources/S3ObjectResource.html)
+ [SQSQueueResource](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/resources/SQSQueueResource.html)

In v1, you can specify a `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html)` element for a `[Resource](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Resource.html)` by calling the `withIsNotType` method as shown in the following statement.

```
Resource resource = new Resource("arn:aws:s3:::amzn-s3-demo-bucket").withIsNotType(true);
```

#### v2
<a name="migration-iam-policy-builder-statement-resources-v2"></a>

In v2, you create a `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html)` element by passing an ARN to the `IamResource.create` method.

```
IamResource resource = IamResource.create("arn:aws:s3:::amzn-s3-demo-bucket");
```

An `[IamResource](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamResource.html)` can be set as *[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html)* element as shown in the following snippet.

```
IamResource resource = IamResource.create("arn:aws:s3:::amzn-s3-demo-bucket");
IamStatement.builder().addNotResource(resource);
```

`IamResource.ALL` represents all resources. 

### Principals
<a name="migration-iam-policy-builder-statement-principal"></a>

#### v1
<a name="migration-iam-policy-builder-statement-principal-v1"></a>

The v1 SDK offers the following `[Principal](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Principal.html)` classes to represent types of principals that include all members:
+ `AllUsers`
+ `AllServices`
+ `AllWebProviders`
+ `All`

You cannot add a `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html)` element to a statement.

#### v2
<a name="migration-iam-policy-builder-statement-principal-v2"></a>

In v2, `IamPrincipal.ALL` represents all principals:

To represent all members in other types of principals, use the `[IamPrincipalType](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamPrincipalType.html)` classes when you create a `IamPrincipal`.
+ `IamPrincipal.create(IamPrincipalType.AWS,"*")` for all users.
+ `IamPrincipal.create(IamPrincipalType.SERVICE,"*")` for all services.
+ `IamPrincipal.create(IamPrincipalType.FEDERATED,"*")` for all web providers.
+ `IamPrincipal.create(IamPrincipalType.CANONICAL_USER,"*")` for all canonical users.

You can use the `addNotPrincipal` method to represent a `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html)` element when you create a policy statement as shown in the following statement.

```
IamPrincipal principal = IamPrincipal.create(IamPrincipalType.AWS, "arn:aws:iam::444455556666:root");
IamStatement.builder().addNotPrincipal(principal);
```

# Changes in working with DynamoDB from version 1 to version 2 of the AWS SDK for Java
<a name="migration-ddb-mapper"></a>



**Topics**
+ [DynamoDB mapping API differences between version 1 and version 2 of the AWS SDK for Java](ddb-mapping.md)
+ [Document API differences between version 1 and version 2 of the AWS SDK for Java](dynamodb-mapping-document-api.md)
+ [Encryption library migration](ddb-encryption-lib-migrate.md)

# DynamoDB mapping API differences between version 1 and version 2 of the AWS SDK for Java
<a name="ddb-mapping"></a>

The DynamoDB mapping APIs changed significantly between version 1 and version 2 of the AWS SDK for Java. In version 1, you use the `DynamoDBMapper` to work with Java POJOs. In version 2, you use the `DynamoDbEnhancedClient` with updated method names, enhanced schema definition options, and improved type safety.

Key differences include:
+ New method names (such as `getItem` instead of `load`)
+ Explicit table schema creation
+ Built-in support for both synchronous and asynchronous operations
+ Changes in how empty strings and configuration are handled

This section covers the mapping API changes, annotation differences, configuration updates, and migration guidance to help you transition from the v1 `DynamoDBMapper` to the v2 `DynamoDbEnhancedClient`.

**Contents**
+ [High-level changes in mapping libraries from version 1 to version 2 of the SDK for Java](dynamodb-mapping-high-level.md)
  + [Import dependency differences](dynamodb-mapping-high-level.md#dynamodb-mapping-deps)
+ [Changes in the DynamoDB mapping APIs between version 1 and version 2 of the SDK for Java](dynamodb-mapping-api-changes.md)
  + [Create a client](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-client)
  + [Establish mapping to DynamoDB table/index](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-mapping)
  + [Table operations](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-tobleops)
  + [Map classes and properties](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas)
    + [Bean annotations](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas-annos)
    + [V2 additional annotations](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas-annos-v2-addnl)
  + [Configuration](dynamodb-mapping-api-changes.md#dynamodb-mapping-configuration)
    + [Per-operation configuration](dynamodb-mapping-api-changes.md#dynamodb-mapping-configuration-per-op)
  + [Conditionals](dynamodb-mapping-api-changes.md#dynamodb-mapping-conditionals)
  + [Type conversion](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv)
    + [Default converters](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-defaults)
    + [Set a custom converter for an attribute](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-anno)
    + [Add a type converter factory or provider](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-factory)
+ [String handling differences between version 1 and version 2 of the SDK for Java](dynamodb-migration-string-handling.md)
+ [Optimistic locking differences between version 1 and version 2 of the SDK for Java](dynamodb-migrate-optimstic-locking.md)
+ [Fluent setters differences between version 1 and version 2 of the SDK for Java](dynamodb-migrate-fluent-setters.md)

# High-level changes in mapping libraries from version 1 to version 2 of the SDK for Java
<a name="dynamodb-mapping-high-level"></a>

The names of the mapping client in each library differ in V1 and V2:
+ V1 - DynamoDBMapper
+ V2 - DynamoDB Enhanced Client

You interact with the two libraries in much the same way: you instantiate a mapper/client and then supply a Java POJO to APIs that read and write these items to DynamoDB tables. Both libraries also offer annotations for the class of the POJO to direct how the client handles the POJO. 

Notable differences when you move to V2 include:
+ V2 and V1 use different method names for the low-level DynamoDB operations. For example:    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-mapping-high-level.html)
+ V2 offers multiple ways to define table schemas and map POJOs to tables. You can choose from the use of annotations or a schema generated from code using a builder. V2 also offers mutable and immutable versions of schemas.
+ With V2, you specifically create the table schema as one of the first steps, whereas in V1, the table schema is inferred from the annotated class as needed.
+ V2 includes the [Document API client ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html) in the enhanced client API, whereas V1 uses a [separate API](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html).
+ All APIs are available in synchronous and asynchronous versions in V2.

See the [DynamoDB mapping section](dynamodb-enhanced-client.md) in this guide for more detailed information on the V2 enhanced client.

## Import dependency differences
<a name="dynamodb-mapping-deps"></a>


| V1 | V2 | 
| --- | --- | 
|  <pre><dependencyManagement><br />  <dependencies><br />    <dependency><br />      <groupId>com.amazonaws</groupId><br />      <artifactId>aws-java-sdk-bom</artifactId><br />      <version>1.X.X</version><br />      <type>pom</type><br />      <scope>import</scope><br />    </dependency><br />  </dependencies><br /></dependencyManagement> <br /><br /><dependencies><br />  <dependency><br />    <groupId>com.amazonaws</groupId><br />    <artifactId>aws-java-sdk-dynamodb</artifactId><br />  </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />  <dependencies><br />    <dependency><br />      <groupId>software.amazon.awssdk</groupId><br />      <artifactId>bom</artifactId><br />      <version>2.X.X*</version><br />      <type>pom</type><br />      <scope>import</scope><br />    </dependency><br />  </dependencies><br /></dependencyManagement> <br /><br /><dependencies><br />  <dependency><br />    <groupId>software.amazon.awssdk</groupId><br />    <artifactId>dynamodb-enhanced</artifactId><br />  </dependency><br /></dependencies></pre>  | 

\$1 [Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

In V1, a single dependency includes both the low-level DynamoDB API and the mapping/document API, whereas in V2, you use the `dynamodb-enhanced` artifact dependency to access the mapping/document API. The `dynamodb-enhanced` module contains a transitive dependency on the low-level `dynamodb` module. 

# Changes in the DynamoDB mapping APIs between version 1 and version 2 of the SDK for Java
<a name="dynamodb-mapping-api-changes"></a>

## Create a client
<a name="dynamodb-mapping-api-changes-client"></a>


****  

| Use case | V1 | V2 | 
| --- | --- | --- | 
|   Normal instantiation  |  <pre>AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard()<br />    .withCredentials(credentialsProvider)<br />    .withRegion(Regions.US_EAST_1)<br />    .build();<br />DynamoDBMapper mapper = new DynamoDBMapper(standardClient);</pre>  |  <pre>DynamoDbClient standardClient = DynamoDbClient.builder()<br />    .credentialsProvider(ProfileCredentialsProvider.create())<br />    .region(Region.US_EAST_1)<br />    .build();<br />DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()<br />    .dynamoDbClient(standardClient)<br />    .build();</pre>  | 
|   Minimal instantiation  |  <pre>AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard();<br />DynamoDBMapper mapper = new DynamoDBMapper(standardClient);</pre>  |  <pre>DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.create();</pre>  | 
|   With attribute transformer\$1  |  <pre>DynamoDBMapper mapper = new DynamoDBMapper(standardClient, <br />                        attributeTransformerInstance);</pre>  |  <pre>DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()<br />    .dynamoDbClient(standardClient)<br />    .extensions(extensionAInstance, extensionBInstance)<br />    .build();</pre>  | 

\$1Extensions in V2 correspond roughly to attribute transformers in V1. The [Use extensions to customize DynamoDB Enhanced Client operations](ddb-en-client-extensions.md) section contains more information on extensions in V2. 

## Establish mapping to DynamoDB table/index
<a name="dynamodb-mapping-api-changes-mapping"></a>

In V1, you specify a DynamoDB table name through a bean annotation. In V2, a factory method, `table()`, produces an instance of `DynamoDbTable` that represents the remote DynamoDB table. The first parameter of the `table()` method is the DynamoDB table name.


****  

| Use case | V1 | V2 | 
| --- | --- | --- | 
|   Map the Java POJO class to the DynamoDB table  |  <pre>@DynamoDBTable(tableName ="Customer")<br />public class Customer {<br />  ...<br />}</pre>  |  <pre>DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer",<br />    TableSchema.fromBean(Customer.class));</pre>  | 
|   Map to a DynamoDB secondary index  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) The section in the DynamoDB Developer Guide that discusses[ the V1 `query` method](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html#DynamoDBMapper.Methods.query) shows a complete example.  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) The [Use secondary indices](ddb-en-client-use-secindex.md) section in this guide provides more information.  | 

## Table operations
<a name="dynamodb-mapping-api-changes-tobleops"></a>

This section describes operation APIs that differ between V1 and V2 for most standard use cases. 

In V2, all operations that involve a single table are called on the `DynamoDbTable` instance, not on the enhanced client. The enhanced client contains methods that can target multiple tables. 

In the table named *Table operations* below, a POJO instance is referred to as `item` or as a specific type such as `customer1`. For the V2 examples the instances named, `table` is the result of previously calling `enhancedClient.table()` that returns a reference to the `DynamoDbTable` instance.

Note that most V2 operations can be called with a fluent consumer pattern even when not shown. For example,

```
Customer customer = table.getItem(r → r.key(key));
  or
Customer customer = table.getItem(r → r.key(k -> k.partitionValue("id").sortValue("email")))
```

For V1 operations, *Table operations* (below) contains some of the commonly used forms and not all overloaded forms. For example, the `load()` method has the following overloads:

```
mapper.load(Customer.class, hashKey)
mapper.load(Customer.class, hashKey, rangeKey)
mapper.load(Customer.class, hashKey, config)
mapper.load(Customer.class, hashKey, rangeKey, config)
mapper.load(item)
mapper.load(item, config)
```

*Table operations* (below) shows the commonly used forms:

```
mapper.load(item)
mapper.load(item, config)
```


**Table operations**  

| Use case | V1 | V2 | 
| --- | --- | --- | 
|  Write a Java POJO to a DynamoDB table **DynamoDB operation:** `PutItem`, `UpdateItem`  |  <pre>mapper.save(item)<br />mapper.save(item, config)<br />mapper.save(item, saveExpression, config)</pre> In V1, `DynamoDBMapperConfig.SaveBehavior` and annotations determines which low-level DynamoDB method will be called. In general, `UpdateItem` is called except when using `SaveBehavior.CLOBBER` and `SaveBehavior.PUT`. Auto-generated keys are a special use case, and occasionally both `PutItem` and `UpdateItem` are used.  |  <pre>table.putItem(putItemRequest)<br />table.putItem(item)<br />table.putItemWithResponse(item) //Returns metadata.<br /><br />updateItem(updateItemRequest)<br />table.updateItem(item)<br />table.updateItemWithResponse(item) //Returns metadata.</pre>  | 
|  Read an item from a DynamoDB table to a Java POJO **DynamoDB operation:** `GetItem`  |  <pre>mapper.load(item)<br />mapper.load(item, config)</pre>  |  <pre>table.getItem(getItemRequest)<br />table.getItem(item)<br />table.getItem(key)<br />table.getItemWithResponse(key) //Returns POJO with metadata.</pre>  | 
|  Delete an item from a DynamoDB table **DynamoDB operation:** `DeleteItem`  |  <pre>mapper.delete(item, deleteExpression, config)</pre>  |  <pre>table.deleteItem(deleteItemRequest)<br />table.deleteItem(item)<br />table.deleteItem(key)</pre>  | 
|  Query a DynamoDB table or secondary index and return a paginated list **DynamoDB operation:** `Query`  |  <pre>mapper.query(Customer.class, queryExpression)<br />mapper.query(Customer.class, queryExpression, <br />                             mapperConfig)</pre>  |  <pre>table.query(queryRequest)<br />table.query(queryConditional)</pre> Use the returned `PageIterable.stream()` (lazy loading) for sync responses and `PagePublisher.subscribe()` for async responses  | 
|  Query a DynamoDB table or secondary index and return a list **DynamoDB operation:** `Query`  |  <pre>mapper.queryPage(Customer.class, queryExpression)<br />mapper.queryPage(Customer.class, queryExpression, <br />                                 mapperConfig)</pre>  |  <pre>table.query(queryRequest)<br />table.query(queryConditional)</pre> Use the returned `PageIterable.items()` (lazy loading) for sync responses and `PagePublisher.items.subscribe()` for async responses  | 
|  Scan a DynamoDB table or secondary index and return a paginated list **DynamoDB operation:** `Scan`  |  <pre>mapper.scan(Customer.class, scanExpression)<br />mapper.scan(Customer.class, scanExpression, <br />                            mapperConfig)</pre>  |  <pre>table.scan()<br />table.scan(scanRequest)</pre> Use the returned `PageIterable.stream()` (lazy loading) for sync responses and `PagePublisher.subscribe()` for async responses  | 
|  Scan a DynamoDB table or secondary index and return a list **DynamoDB operation:** `Scan`  |  <pre>mapper.scanPage(Customer.class, scanExpression)<br />mapper.scanPage(Customer.class, scanExpression, <br />                                mapperConfig)</pre>  |  <pre>table.scan()<br />table.scan(scanRequest)</pre> Use the returned `PageIterable.items()` (lazy loading) for sync responses and `PagePublisher.items.subscribe()` for async responses  | 
|  Read multiple items from multiple tables in a batch **DynamoDB operation:** `BatchGetItem`  |  <pre>mapper.batchLoad(Arrays.asList(customer1, <br />                               customer2, <br />                               book1))<br />mapper.batchLoad(itemsToGet) <br />           // itemsToGet: Map<Class<?>, List<KeyPair>></pre>  |  <pre>enhancedClient.batchGetItem(batchGetItemRequest)<br /><br />enhancedClient.batchGetItem(r -> r.readBatches(<br />    ReadBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addGetItem(i -> i.key(k -> k.partitionValue(0)))<br />             .build(),<br />    ReadBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addGetItem(i -> i.key(k -> k.partitionValue(0)))<br />             .build()))<br /><br />// Iterate over pages with lazy loading or over all items <br />   from the same table.</pre>  | 
|  Write multiple items to multiple tables in a batch **DynamoDB operation:** `BatchWriteItem`  |  <pre>mapper.batchSave(Arrays.asList(customer1, <br />                               customer2, <br />                               book1)) </pre>  |  <pre>enhancedClient.batchWriteItem(batchWriteItemRequest)<br /><br />enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addPutItem(item1)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addPutItem(item2)<br />             .build()))</pre>  | 
|  Delete multiple items from multiple tables in a batch **DynamoDB operation:** `BatchWriteItem`  |  <pre>mapper.batchDelete(Arrays.asList(customer1, <br />                                 customer2, <br />                                 book1)) </pre>  |  <pre>enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addDeleteItem(item1key)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addDeleteItem(item2key)<br />             .build()))</pre>  | 
|  Write/delete multiple items in a batch **DynamoDB operation:** `BatchWriteItem`  |  <pre>mapper.batchWrite(Arrays.asList(customer1, book1), <br />                  Arrays.asList(customer2)) </pre>  |  <pre>enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addPutItem(item1)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addDeleteItem(item2key)<br />             .build()))</pre>  | 
|  Carry out a transactional write **DynamoDB operation:** `TransactWriteItems`  |  <pre>mapper.transactionWrite(transactionWriteRequest)</pre>  |  <pre>enhancedClient.transactWriteItems(transasctWriteItemsRequest)</pre>  | 
|  Carry out a transactional read **DynamoDB operation:** `TransactGetItems`  |  <pre>mapper.transactionLoad(transactionLoadRequest)</pre>  |  <pre>enhancedClient.transactGetItems(transactGetItemsRequest) </pre>  | 
|  Get a count of matching items of a query **DynamoDB operation:** `Query` with `Select.COUNT`  |  <pre>mapper.count(Customer.class, queryExpression)</pre>  |  <pre>// Get the count from query results.<br />PageIterable<Customer> pageIterable =<br />    customerTable.query(QueryEnhancedRequest.builder()<br />        .queryConditional(queryConditional)<br />        .select(Select.COUNT)<br />        .build());<br />Iterator<Page<Customer>> iterator = pageIterable.iterator();<br />Page<Customer> page = iterator.next();<br />int count = page.count();<br /><br />// For a more concise approach, you can chain the method calls:<br />int count = customerTable.query(QueryEnhancedRequest.builder()<br />                .queryConditional(queryConditional)<br />                .select(Select.COUNT)<br />                .build())<br />            .iterator().next().count();</pre>  | 
|  Get a count of matching items of a scan **DynamoDB operation:**`Scan` with `Select.COUNT`  |  <pre>mapper.count(Customer.class, scanExpression)</pre>  |  <pre>// Get the count from scan results.<br />PageIterable<Customer> pageIterable =<br />    customerTable.scan(ScanEnhancedRequest.builder()<br />        .filterExpression(filterExpression)<br />        .select(Select.COUNT)<br />        .build());<br />Iterator<Page<Customer>> iterator = pageIterable.iterator();<br />Page<Customer> page = iterator.next();<br />int count = page.count();<br /><br />// For a more concise approach, you can chain the method calls:<br />int count = customerTable.scan(ScanEnhancedRequest.builder()<br />                .filterExpression(filterExpression)<br />                .select(Select.COUNT)<br />                .build())<br />            .iterator().next().count();</pre>  | 
|  Create a table in DynamoDB corresponding to the POJO class **DynamoDB operation:** `CreateTable`  |  <pre>mapper.generateCreateTableRequest(Customer.class)</pre> The previous statement generates a low-level create table request; users must call `createTable` on the DynamoDB client.  |  <pre>table.createTable(createTableRequest)<br /><br />table.createTable(r -> r.provisionedThroughput(defaultThroughput())<br />    .globalSecondaryIndices(<br />        EnhancedGlobalSecondaryIndex.builder()<br />            .indexName("gsi_1")<br />            .projection(p -> p.projectionType(ProjectionType.ALL))<br />            .provisionedThroughput(defaultThroughput())<br />            .build()));</pre>  | 
|  Perform a parallel scan in DynamoDB **DynamoDB operation:** `Scan` with `Segment` and `TotalSegments` parameters  |  <pre>mapper.parallelScan(Customer.class, <br />                    scanExpression, <br />                    numTotalSegments)</pre>  |  Users are required to handle the worker threads and call `scan` for each segment: <pre>table.scan(r -> r.segment(0).totalSegments(5))</pre>  | 
|  Integrate Amazon S3 with DynamoDB to store intelligent S3 links  |  <pre>mapper.createS3Link(bucket, key)<br />mapper.getS3ClientCache()</pre>  |  Not supported because it couples Amazon S3 and DynamoDB.  | 

## Map classes and properties
<a name="dynamodb-mapping-schemas"></a>

In both V1 and V2, you map classes to tables using bean-style annotations. V2 also offers [other ways to define schemas](ddb-en-client-adv-features.md#ddb-en-client-adv-features-schm-overview) for specific use cases, such as working with immutable classes.

### Bean annotations
<a name="dynamodb-mapping-schemas-annos"></a>

The following table shows the equivalent bean annotations for a specific use case that are used in V1 and V2. A `Customer` class scenario is used to illustrate parameters.

Annotations—as well as classes and enumerations—in V2 follow camel case convention and use 'DynamoDb', not 'DynamoDB'.


| Use case | V1 | V2 | 
| --- | --- | --- | 
| Map class to table |  <pre>@DynamoDBTable (tableName ="CustomerTable")</pre>  | <pre>@DynamoDbBean<br />@DynamoDbBean(converterProviders = {...})</pre>The table name is defined when calling the DynamoDbEnhancedClient\$1table() method. | 
| Designate a class member as a table attribute  |  <pre>@DynamoDBAttribute(attributeName = "customerName")</pre>  |  <pre>@DynamoDbAttribute("customerName") </pre>  | 
| Designate a class member is a hash/partition key |  <pre>@DynamoDBHashKey </pre>  |  <pre>@DynamoDbPartitionKey</pre>  | 
| Designate a class member is a range/sort key |  <pre>@DynamoDBRangeKey </pre>  |  <pre>@DynamoDbSortKey </pre>  | 
| Designate a class member is a secondary index hash/partition key |  <pre>@DynamoDBIndexHashKey </pre>  |  <pre>@DynamoDbSecondaryPartitionKey </pre>  | 
| Designate a class member is a secondary index range/sort key |  <pre>@DynamoDBIndexRangeKey </pre>  |  <pre>@DynamoDbSecondarySortKey </pre>  | 
| Ignore this class member when mapping to a table |  <pre>@DynamoDBIgnore </pre>  |  <pre>@DynamoDbIgnore</pre>  | 
| Designate a class member as an auto-generated UUID key attribute |  <pre>@DynamoDBAutoGeneratedKey</pre>  |  <pre>@DynamoDbAutoGeneratedUuid </pre> The extension that provides this is not loaded by default; you must add the extension to client builder.  | 
| Designate a class member as an auto-generated timestamp attribute |  <pre>@DynamoDBAutoGeneratedTimestamp</pre>  |  <pre>@DynamoDbAutoGeneratedTimestampAttribute</pre> The extension that provides this is not loaded by default; you must add the extension to client builder.  | 
| Designate a class member as an auto-incremented version attribute |  <pre>@DynamoDBVersionAttribute</pre>  |  <pre>@DynamoDbVersionAttribute</pre> The extension that provides this is auto-loaded.  | 
| Designate a class member as requiring a custom conversion |  <pre>@DynamoDBTypeConverted</pre>  |  <pre>@DynamoDbConvertedBy</pre>  | 
| Designate a class member to be stored as a different attribute type |  <pre>@DynamoDBTyped(<DynamoDBAttributeType>)</pre>  |  Use an `AttributeConverter` implementation. V2 provides many built-in converters for common Java types. You can also implement your own custom `AttributeConverter` or `AttributeConverterProvider`. See [Control attribute conversion](ddb-en-client-adv-features-conversion.md) in this guide.  | 
| Designate a class that can be serialized to a DynamoDB document (JSON-style document) or sub-document  |  <pre>@DynamoDBDocument</pre>  | Use the Enhanced Document API. See the following resources:[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) | 

### V2 additional annotations
<a name="dynamodb-mapping-schemas-annos-v2-addnl"></a>


| Use case | V1 | V2 | 
| --- | --- | --- | 
| Designate a class member not to be stored as a NULL attribute if the Java value is null | N/A |  <pre>@DynamoDbIgnoreNulls</pre>  | 
| Designate a class member to be an empty object if all attributes are null | N/A |  <pre>@DynamoDbPreserveEmptyObject</pre>  | 
| Designate special update action for a class member | N/A |  <pre>@DynamoDbUpdateBehavior</pre>  | 
| Designate an immutable class | N/A |  <pre>@DynamoDbImmutable</pre>  | 
| Designate a class member as an auto-incremented counter attribute | N/A |  <pre>@DynamoDbAtomicCounter</pre> The extension that provides this functionality is auto-loaded.  | 

## Configuration
<a name="dynamodb-mapping-configuration"></a>

In V1, you generally control specific behaviors by using an instance of `DynamoDBMapperConfig`. You can supply the configuration object either when you create the mapper or when you make a request. In V2, configuration is specific to the request object for the operation.


| Use case | V1 | Default in V1 | V2 | 
| --- | --- | --- | --- | 
|  |  <pre>DynamoDBMapperConfig.builder()</pre>  |  |  | 
| Batch load/write retry strategy |  <pre>  .withBatchLoadRetryStrategy(loadRetryStrategy)</pre> <pre>  .withBatchWriteRetryStrategy(writeRetryStrategy)</pre>  | retry failed items | Configure the retry strategy on the underlying DynamoDBClient. See [Configure retry behavior in the AWS SDK for Java 2.x](retry-strategy.md) in this guide. | 
| Consistent reads |  <pre>  .withConsistentReads(CONSISTENT)</pre>  | EVENTUAL | By default, consistent reads is false for read operations. Override with .consistentRead(true) on the request object. | 
| Conversion schema with sets of marshallers/unmarshallers |  <pre>  .withConversionSchema(conversionSchema)</pre> Static implementations provide backwards compatibility with older versions.  | V2\$1COMPATIBLE | Not applicable. This is a legacy feature that refers to how the earliest versions of DynamoDB (V1) stored data types, and this behavior will not be preserved in the enhanced client. An example of behavior in DynamoDB V1 is storing booleans as Number instead of as Boolean. | 
| Table names |  <pre>  .withObjectTableNameResolver()<br />  .withTableNameOverride() <br />  .withTableNameResolver()</pre> Static implementations provide backwards compatibility with older versions  | use annotation or guess from class |  The table name is defined when calling the `DynamoDbEnhancedClient#table()` method.  | 
| Pagination load strategy |  <pre>  .withPaginationLoadingStrategy(strategy)</pre>  Options are: LAZY\$1`LOADING`, `EAGER_LOADING`, or `ITERATION_ONLY`  | LAZY\$1LOADING |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html)  | 
| Request metric collection |  <pre>  .withRequestMetricCollector(collector)</pre>  | null | Use metricPublisher() in ClientOverrideConfiguration when building the standard DynamoDB client.  | 
| Save behavior |  <pre>  .withSaveBehavior(SaveBehavior.CLOBBER) </pre> Options are `UPDATE`, `CLOBBER`, `PUT`, `APPEND_SET`, or `UPDATE_SKIP_NULL_ATTRIBUTES`.  | UPDATE |  In V2, you call `putItem()` or `updateItem()` explicitly. `CLOBBER or PUT`: Corresponding action in v 2 is calling `putItem()`. There is no specific `CLOBBER` configuration. `UPDATE`: Corresponds to `updateItem()` `UPDATE_SKIP_NULL_ATTRIBUTES`: Corresponds to `updateItem()`. Control update behavior with the request setting `ignoreNulls` and the annotation/tag `DynamoDbUpdateBehavior`. `APPEND_SET`: Not supported  | 
| Type converter factory |  <pre>  .withTypeConverterFactory(typeConverterFactory) </pre>  | standard type converters |  Set on the bean by using <pre>@DynamoDbBean(converterProviders = {ConverterProvider.class, <br />        DefaultAttributeConverterProvider.class})</pre>  | 

### Per-operation configuration
<a name="dynamodb-mapping-configuration-per-op"></a>

In V1, some operations, such as `query()`, are highly configurable through an “expression” object submitted to the operation. For example:

```
DynamoDBQueryExpression<Customer> emailBwQueryExpr = new DynamoDBQueryExpression<Customer>()
    .withRangeKeyCondition("Email",
        new Condition()
            .withComparisonOperator(ComparisonOperator.BEGINS_WITH)
            .withAttributeValueList(
                new AttributeValue().withS("my")));

mapper.query(Customer.class, emailBwQueryExpr);
```

In V2, instead of using a configuration object, you set parameters on the request object by using a builder. For example:

```
QueryEnhancedRequest emailBw = QueryEnhancedRequest.builder()
    .queryConditional(QueryConditional
        .sortBeginsWith(kb -> kb
            .sortValue("my"))).build();

customerTable.query(emailBw);
```

## Conditionals
<a name="dynamodb-mapping-conditionals"></a>

In V2, conditional and filtering expressions are expressed using an `Expression` object, which encapsulates the condition and the mapping of names and filters. 


| Use case | Operations | V1 | V2 | 
| --- | --- | --- | --- | 
| Expected attribute conditions | save(), delete(), query(), scan() |  <pre>new DynamoDBSaveExpression()<br />  .withExpected(Collections.singletonMap(<br />      "otherAttribute", new ExpectedAttributeValue(false)))<br />  .withConditionalOperator(ConditionalOperator.AND);</pre>  | Deprecated; use ConditionExpression instead. | 
| Condition expression | delete() |  <pre>deleteExpression.setConditionExpression("zipcode = :zipcode")<br />deleteExpression.setExpressionAttributeValues(...)<br /></pre>  |  <pre>Expression conditionExpression =<br />    Expression.builder()<br />        .expression("#key = :value OR #key1 = :value1")<br />        .putExpressionName("#key", "attribute")<br />        .putExpressionName("#key1", "attribute3")<br />        .putExpressionValue(":value", AttributeValues.stringValue("wrong"))<br />        .putExpressionValue(":value1", AttributeValues.stringValue("three"))<br />        .build();<br /><br />DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder()<br />         .conditionExpression(conditionExpression).build();</pre>  | 
| Filter expression | query(), scan() |  <pre>scanExpression<br />  .withFilterExpression("#statename = :state")<br />  .withExpressionAttributeValues(attributeValueMapBuilder.build())<br />  .withExpressionAttributeNames(attributeNameMapBuilder.build())<br /></pre>  |  <pre>Map<String, AttributeValue> values = singletonMap(":key", stringValue("value"));<br />Expression filterExpression =<br />    Expression.builder()<br />        .expression("name = :key")<br />        .expressionValues(values)<br />        .build();<br />QueryEnhancedRequest request = QueryEnhancedRequest.builder()<br />    .filterExpression(filterExpression).build();<br /></pre>  | 
| Condition expression for query | query() |  <pre>queryExpression.withKeyConditionExpression()</pre>  |  <pre>QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b<br />                .partitionValue("movie01"));<br /><br />QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()<br />                .queryConditional(keyEqual)<br />                .build();</pre>  | 

## Type conversion
<a name="dynamodb-mapping-type-conv"></a>

### Default converters
<a name="dynamodb-mapping-type-conv-defaults"></a>

In V2, the SDK provides a set of default converters for all common types. You can change type converters both at the overall provider level as well as for a single attribute. You can find a list of the available converters in the [AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html) API reference.

### Set a custom converter for an attribute
<a name="dynamodb-mapping-type-conv-anno"></a>

In V1, you can annotate a getter method with `@DynamoDBTypeConverted` to specify the class that converts between the Java attribute type and a DynamoDB attribute type. For instance, a `CurrencyFormatConverter` that converts between a Java `Currency` type and DynamoDB String can be applied as shown in the following snippet.

```
@DynamoDBTypeConverted(converter = CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
```

The V2 equivalent of the previous snippet is shown below.

```
@DynamoDbConvertedBy(CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
```

**Note**  
In V1, you can apply the annotation to the attribute itself , a type or a user-defined annotation, V2 supports applying the annotation it only to the getter.

### Add a type converter factory or provider
<a name="dynamodb-mapping-type-conv-factory"></a>

In V1, you can provide your own set of type converters, or override the types you care about by adding a type converter factory to the configuration. The type converter factory extends `DynamoDBTypeConverterFactory`, and overrides are done by getting a reference to the default set and extending it. The following snippet demonstrates how to do this.

```
DynamoDBTypeConverterFactory typeConverterFactory =
    DynamoDBTypeConverterFactory.standard().override()
        .with(String.class, CustomBoolean.class, new DynamoDBTypeConverter<String, CustomBoolean>() {
            @Override
            public String convert(CustomBoolean bool) {
                return String.valueOf(bool.getValue());
            }
            @Override
            public CustomBoolean unconvert(String string) {
                return new CustomBoolean(Boolean.valueOf(string));
            }}).build();
DynamoDBMapperConfig config =
    DynamoDBMapperConfig.builder()
        .withTypeConverterFactory(typeConverterFactory)
        .build();
DynamoDBMapper mapperWithTypeConverterFactory = new DynamoDBMapper(dynamo, config);
```

V2 provides similar functionality through the `@DynamoDbBean` annotation. You can provide a single `AttributeConverterProvider` or a chain of ordered `AttributeConverterProvider`s. Note that if you supply your own chain of attribute converter providers, you will override the default converter provider and must include it in the chain to use its attribute converters. 

```
@DynamoDbBean(converterProviders = {
   ConverterProvider1.class, 
   ConverterProvider2.class,
   DefaultAttributeConverterProvider.class})
public class Customer {
  ...
}
```

The section on [attribute conversion](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example) in this guide contains a complete example for V2.

# String handling differences between version 1 and version 2 of the SDK for Java
<a name="dynamodb-migration-string-handling"></a>

V1 and V2 handle empty strings differently when sending data to DynamoDB:
+ **V1**: Converts empty strings to null values before sending to DynamoDB (resulting in no attribute)
+ **V2**: Sends empty strings as actual empty string values to DynamoDB

**Important**  
After migrating to V2, if you don't want empty strings stored in DynamoDB, you must implement custom converters. Without custom converters, V2 stores empty strings as actual empty string attributes in your DynamoDB items, which differs from V1's behavior of omitting these attributes entirely.

**Example custom converter for V2 that converts an empty string attribute to null**  

```
/**
 * Custom converter that maintains V1 behavior by converting empty strings to null values
 * when writing to DynamoDB, ensuring compatibility with existing data. No attribute will be saved to DynamoDB.
 */
public class NullifyEmptyStringConverter implements AttributeConverter<String> {
    @Override
    public AttributeValue transformFrom(String value) {
        if (value == null || value.isEmpty()) {
            return AttributeValue.builder().nul(true).build();
        }
        return AttributeValue.builder().s(value).build();
    }

    @Override
    public String transformTo(AttributeValue attributeValue) {
        if (attributeValue.nul()) {
            return null;
        }
        return attributeValue.s();
    }

    @Override
    public EnhancedType<String> type() {
        return EnhancedType.of(String.class);
    }

    @Override
    public AttributeValueType attributeValueType() {
        return AttributeValueType.S;
    }
}

// V2 usage:
@DynamoDbBean
public class Customer {
    private String name;

    @DynamoDbConvertedBy(NullifyEmptyStringConverter.class)
    public String getName() {
        return name;
    }
}
```



# Optimistic locking differences between version 1 and version 2 of the SDK for Java
<a name="dynamodb-migrate-optimstic-locking"></a>

Both V1 and V2 implement optimistic locking with an attribute annotation that marks one property on your bean class to store the version number.


**Differences in optimistic locking behavior**  

|  | V1 | V2 | 
| --- | --- | --- | 
| Bean class annotation | @DynamoDBVersionAttribute | @DynamoDbVersionAttribute (note that V2 uses a lowercase "b") | 
| Initial save | Version number attribute set to 1. |  The starting value for the version attribute set with `@DynamoDbVersionAttribute(startAt = X)`. Default value is 0.  | 
| Update | The version number attribute is incremented by 1 if the conditional check verifies that the version number of the object being updated matches the number in the database. |  The version number attribute is incremented if the conditional check verifies that the version number of the object being updated matches the number in the database. The version number attribute incremented by the `incrementBy` option set with `@DynamoDbVersionAttribute(incrementBy = X)`. Default value is 1.  | 
| Delete | DynamoDBMapper adds a conditional check that the version number of the object being deleted matches the version number in the database. |  V2 does not does not automatically add conditions for the delete operations. You must add condition expressions manually if you want to control the delete behavior. In the following example `recordVersion` is the bean's version attribute. <pre>// 1. Read the item and get its current version.<br />Customer item = customerTable.getItem(Key.builder().partitionValue("someId").build());<br />AttributeValue currentVersion = item.getRecordVersion();<br /><br />// 2. Create conditional delete with the `currentVersion` value.<br />DeleteItemEnhancedRequest deleteItemRequest =<br />    DeleteItemEnhancedRequest.builder()<br />       .key(KEY)<br />       .conditionExpression(Expression.builder()<br />           .expression("recordVersion = :current_version_value")<br />           .putExpressionValue(":current_version_value", currentVersion)<br />           .build()).build();<br /><br />customerTable.deleteItem(deleteItemRequest);</pre>  | 
| Transactional Write with a Condition Check | You cannot use a bean class that is annotated with @DynamoDBVersionAttribute in an addConditionCheck method. | You can use a bean class with the @DynamoDbVersionAttribute annotation in an addConditionCheck builder method for a transactWriteItems request. | 
| Disable | Disable optimistic locking by changing the DynamoDBMapperConfig.SaveBehavior enumeration value from UPDATE to CLOBBER. |  Do not use the `@DynamoDbVersionAttribute` annotation.  | 

# Fluent setters differences between version 1 and version 2 of the SDK for Java
<a name="dynamodb-migrate-fluent-setters"></a>

You can use POJOs with fluent setters in the DynamoDB mapping API for V1 and with V2 since version 2.30.29. 

For example, the following POJO returns a `Customer` instance from the `setName` method:

```
// V1

@DynamoDBTable(tableName ="Customer")
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){
     this.name = name;
     return this;
  }
}
```

However, if you use a version of V2 prior to 2.30.29, `setName` returns a `Customer` instance with a `name` value of `null`.

```
// V2 prior to version 2.30.29.

@DynamoDbBean
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){ 
     this.name = name;
     return this;  // Bug: returns this instance with a `name` value of `null`.
  }
}
```

```
// Available in V2 since version 2.30.29.

@DynamoDbBean
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){ 
     this.name = name;
     return this;  // Returns this instance for method chaining with the `name` value set.
  }
}
```

# Document API differences between version 1 and version 2 of the AWS SDK for Java
<a name="dynamodb-mapping-document-api"></a>

The Document API supports working with JSON-style documents as single items in a DynamoDB table. The V1 Document API has a corresponding API in V2, but instead of using a separate client for the document API as in V1, V2 incorporates document API features in the DynamoDB enhanced client. 

In V1, the [https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Item.html](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Item.html) class represents an unstructured record from a DynamoDB table. In V2, an unstructured record is represented by an instance of the [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html) class. Note that primary keys are defined in the table schema for V2, and on the item itself in V1.

The table below compares the differences between the Document APIs in V1 and V2.


| Use case | V1 | V2 | 
| --- |--- |--- |
| Create a document client |  <pre>AmazonDynamoDB client = ... //Create a client.<br />DynamoDB documentClient = new DynamoDB(client);</pre>  |  <pre>// The V2 Document API uses the same DynamoDbEnhancedClient<br />// that is used for mapping POJOs.<br />DynamoDbClient standardClient = ... //Create a standard client.<br />DynamoDbEnhancedClient enhancedClient = ... // Create an enhanced client.<br /></pre>  | 
| Reference a table |  <pre>Table documentTable = docClient.documentClient("Person");</pre>  |  <pre>DynamoDbTable<EnhancedDocument> documentTable = enhancedClient.table("Person",  <br />        TableSchema.documentSchemaBuilder()<br />              .addIndexPartitionKey(TableMetadata.primaryIndexName(),"id", AttributeValueType.S)<br />              .attributeConverterProviders(AttributeConverterProvider.defaultProvider())<br />              .build());</pre>  | 
| **Work with semi-structured data** | 
| --- |
| Put item |  <pre>Item item = new Item()<br />      .withPrimaryKey("id", 50)<br />      .withString("firstName", "Shirley");<br />PutItemOutcome outcome = documentTable.putItem(item);</pre>  |  <pre>EnhancedDocument personDocument = EnhancedDocument.builder()<br />        .putNumber("id", 50)<br />        .putString("firstName", "Shirley")<br />        .build();<br />documentTable.putItem(personDocument);</pre>  | 
| Get item |  <pre>GetItemOutcome outcome = documentTable.getItemOutcome( "id", 50);<br />Item personDocFromDb = outcome.getItem();<br />String firstName = personDocFromDb.getString("firstName");<br /></pre>  |  <pre>EnhancedDocument personDocFromDb = documentTable<br />        .getItem(Key.builder()<br />            .partitionValue(50)<br />            .build()); <br />String firstName = personDocFromDb.getString("firstName");<br /></pre>  | 
| **Work with JSON items** | 
| --- |
| Convert a JSON structure to use it with the Document API |  <pre>// The 'jsonPerson' identifier is a JSON string. <br />Item item = new Item().fromJSON(jsonPerson);</pre>  |  <pre>// The 'jsonPerson' identifier is a JSON string.<br />EnhancedDocument document = EnhancedDocument.builder()<br />        .json(jsonPerson).build());</pre>  | 
| Put JSON |  <pre>documentTable.putItem(item)</pre>  |  <pre>documentTable.putItem(document);</pre>  | 
| Read JSON |  <pre>GetItemOutcome outcome = //Get item.<br />String jsonPerson = outcome.getItem().toJSON();</pre>  |  <pre>String jsonPerson = documentTable.getItem(Key.builder()<br />        .partitionValue(50).build())<br />        .fromJson();</pre>  | 

## API reference and guides for document APIs
<a name="dynamodb-mapping-document-api-ref"></a>


|  | V1 | V2 | 
| --- | --- | --- | 
| API reference | [API reference](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/package-summary.html) | [API reference](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) | 
| Documentation guide | [Amazon DynamoDB Developer Guide](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/JavaDocumentAPIItemCRUD.html) | [Enhanced Document API](ddb-en-client-doc-api.md) (this guide) | 

# V1 Xpec API to V2 Expressions API
<a name="ddb-v1-xspec-migrate"></a>

The Expression Specification (Xspec) API available in V1 that helps create expressions to work with document-oriented data is not available in V2. V2 uses the Expression API, which works with both document-oriented data and object-to-item mapped data.


****  

|  | V1 | V2 | 
| --- | --- | --- | 
| API name | Expression Specification (Xspec) API | Expression API | 
| Works with | Methods of the Document API [Table](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Table.html) class such as [updateItem](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Table.html#updateItem-java.lang.String-java.lang.Object-com.amazonaws.services.dynamodbv2.xspec.UpdateItemExpressionSpec-) and [scan](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Table.html#scan-com.amazonaws.services.dynamodbv2.xspec.ScanExpressionSpec-) |  Both APIs of DynamoDB Enhanced Client: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-v1-xspec-migrate.html) For both types of APIs, after you have acquired a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html) instance: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-v1-xspec-migrate.html) you use expressions in `DynamoDbTable` methods when you create request objects. For example in the `filterExpression` method of the [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryEnhancedRequest.Builder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryEnhancedRequest.Builder.html)  | 
| Resources |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-v1-xspec-migrate.html)  | [Expressions information](ddb-en-client-expressions.md) in this Java Developer Guide | 

# Encryption library migration
<a name="ddb-encryption-lib-migrate"></a>

For information about migrating the encryption library for DynamoDB to work with V2 of the Java SDK, see the [Amazon DynamoDB Encryption Client Developer Guide](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/ddb-java-migrate.html).

# Changes in automatic Amazon SQS request batching from version 1 to version 2
<a name="migration-sqs-auto-batching"></a>

This topic details the changes in automatic request batching for Amazon SQS between version 1 and version 2 of the AWS SDK for Java.

## High-level changes
<a name="migration-sqs-auto-batching-high-level-changes"></a>

The AWS SDK for Java 1.x performs client-side buffering using a separate `[AmazonSQSBufferedAsyncClient](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/sqs/buffered/AmazonSQSBufferedAsyncClient.html)` class that requires explicit initialization for request batching. 

The AWS SDK for Java 2.x simplifies and enhances buffering functionality with the `[SqsAsyncBatchManager](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html)`. The implementation of this interface provides automatic request batching capabilities directly integrated with the standard `[SqsAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsAsyncClient.html)`. To learn about v2's `SqsAsyncBatchManager`, see the [Use automatic request batching for Amazon SQS with the AWS SDK for Java 2.x](sqs-auto-batch.md) topic in this guide.


| Change | v1 | v2 | 
| --- | --- | --- | 
|    Maven dependencies  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.7821</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-sqs</artifactId><br />    </dependency><br /></dependencies><br /></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.31.152</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>sqs</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| Package names | com.amazonaws.services.sqs.buffered | software.amazon.awssdk.services.sqs.batchmanager | 
| Class names |  `[AmazonSQSBufferedAsyncClient](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/sqs/buffered/AmazonSQSBufferedAsyncClient.html)`  | [SqsAsyncBatchManager](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html) | 

1 [Latest version](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom). 2 [Latest version](https://central.sonatype.com/artifact/software.amazon.awssdk/bom).

## Using automatic SQS request batching
<a name="migration-sqs-auto-batching-using"></a>


| Change | v1 | v2 | 
| --- | --- | --- | 
| Create a batch manager |  <pre>AmazonSQSAsync sqsAsync = new AmazonSQSAsyncClient();<br />AmazonSQSAsync bufferedSqs = new <br />            AmazonSQSBufferedAsyncClient(sqsAsync);</pre>  |  <pre>SqsAsyncClient asyncClient = SqsAsyncClient.create();<br />SqsAsyncBatchManager sqsAsyncBatchManager = <br />            asyncClient.batchManager();</pre>  | 
| Create a batch manager with custom configuration |  <pre>AmazonSQSAsync sqsAsync = new AmazonSQSAsyncClient();<br /><br />QueueBufferConfig queueBufferConfig = new QueueBufferConfig()<br />        .withMaxBatchOpenMs(200)<br />        .withMaxBatchSize(10)<br />        .withMinReceiveWaitTimeMs(1000)<br />        .withVisibilityTimeoutSeconds(20)<br />        .withReceiveMessageAttributeNames(messageAttributeValues);<br /><br />AmazonSQSAsync bufferedSqs = <br />        new AmazonSQSBufferedAsyncClient(sqsAsync, queueBufferConfig);</pre>  |  <pre>BatchOverrideConfiguration batchOverrideConfiguration = <br />    BatchOverrideConfiguration.builder()<br />        .sendRequestFrequency(Duration.ofMillis(200))<br />        .maxBatchSize(10)<br />        .receiveMessageMinWaitDuration(Duration.ofMillis(1000))<br />        .receiveMessageVisibilityTimeout(Duration.ofSeconds(20))<br />        .receiveMessageSystemAttributeNames(messageSystemAttributeNames)<br />        .receiveMessageAttributeNames(messageAttributeValues)<br />        .build();<br /><br />SqsAsyncBatchManager sqsAsyncBatchManager = SqsAsyncBatchManager.builder()<br />        .overrideConfiguration(batchOverrideConfiguration)<br />        .client(SqsAsyncClient.create())<br />        .scheduledExecutor(Executors.newScheduledThreadPool(8))<br />        .build();</pre>  | 
| Send messages |  <pre>Future<SendMessageResult> sendResultFuture = <br />        bufferedSqs.sendMessageAsync(new SendMessageRequest()<br />                .withQueueUrl(queueUrl)<br />                .withMessageBody(body));</pre>  |  <pre>CompletableFuture<SendMessageResponse> sendCompletableFuture = <br />        sqsAsyncBatchManager.sendMessage(<br />                SendMessageRequest.builder()<br />                        .queueUrl(queueUrl)<br />                        .messageBody(body)<br />                        .build());</pre>  | 
| Delete messages |  <pre>Future<DeleteMessageResult> deletResultFuture =<br />        bufferedSqs.deleteMessageAsync(new DeleteMessageRequest()<br />                .withQueueUrl(queueUrl));</pre>  |  <pre>CompletableFuture<DeleteMessageResponse> deleteResultCompletableFuture<br />        = sqsAsyncBatchManager.deleteMessage(<br />                DeleteMessageRequest.builder()<br />                        .queueUrl(queueUrl)<br />                        .build());</pre>  | 
| Change visibility of messages |  <pre>Future<ChangeMessageVisibilityResult> changeVisibilityResultFuture =<br />        bufferedSqs.changeMessageVisibilityAsync<br />                (new ChangeMessageVisibilityRequest()<br />                        .withQueueUrl(queueUrl)<br />                        .withVisibilityTimeout(20));</pre>  |  <pre>CompletableFuture<ChangeMessageVisibilityResponse> changeResponseCompletableFuture<br />        = sqsAsyncBatchManager.changeMessageVisibility(<br />                ChangeMessageVisibilityRequest.builder()<br />                        .queueUrl(queueUrl)<br />                        .visibilityTimeout(20)<br />                        .build());</pre>  | 
| Receive messages |  <pre>ReceiveMessageResult receiveResult =<br />        bufferedSqs.receiveMessage(<br />                new ReceiveMessageRequest()<br />                        .withQueueUrl(queueUrl));</pre>  |  <pre>CompletableFuture<ReceiveMessageResponse> <br />        responseCompletableFuture = sqsAsyncBatchManager.receiveMessage(<br />                ReceiveMessageRequest.builder()<br />                        .queueUrl(queueUrl)<br />                        .build());</pre>  | 

## Asynchronous return type differences
<a name="migration-sqs-auto-batching-asyc-return-type"></a>


| Change | v1 | v2 | 
| --- | --- | --- | 
| Return type | Future<ResultType> | CompletableFuture<ResponseType> | 
| Callback mechanism | Requires an AsyncHandler with separate onSuccess and onError methods | Uses CompletableFuture APIs provided by the JDK, such as whenComplete(), thenCompose(), thenApply() | 
| Exception handling | Uses AsyncHandler\$1onError() method | Uses CompletableFuture APIs provided by the JDK, such as exceptionally(), handle(), or whenComplete() | 
| Cancellation | Basic support through Future.cancel() | Cancelling a parent CompletableFuture automatically cancels all dependent futures in the chain | 

## Asynchronous completion handling differences
<a name="migration-sqs-auto-batching-asyc-completion-handling"></a>


| Change | v1 | v2 | 
| --- | --- | --- | 
| Response handler implementation |  <pre>Future<ReceiveMessageResult> future = bufferedSqs.receiveMessageAsync(<br />        receiveRequest,<br />        new AsyncHandler<ReceiveMessageRequest, ReceiveMessageResult>() {<br />            @Override<br />            public void onSuccess(ReceiveMessageRequest request, <br />                              ReceiveMessageResult result) {<br />                List<Message> messages = result.getMessages();<br />                System.out.println("Received " + messages.size() + " messages");<br />                for (Message message : messages) {<br />                    System.out.println("Message ID: " + message.getMessageId());<br />                    System.out.println("Body: " + message.getBody());<br />                }<br />            }<br /><br />            @Override<br />            public void onError(Exception e) {<br />                System.err.println("Error receiving messages: " + e.getMessage());<br />                e.printStackTrace();<br />            }<br />        }<br />);</pre>  |  <pre>CompletableFuture<ReceiveMessageResponse> completableFuture = sqsAsyncBatchManager<br />               .receiveMessage(ReceiveMessageRequest.builder()<br />               .queueUrl(queueUrl).build())<br />        .whenComplete((receiveMessageResponse, throwable) -> {<br />            if (throwable != null) {<br />                System.err.println("Error receiving messages: " + throwable.getMessage());<br />                throwable.printStackTrace();<br />            } else {<br />                List<Message> messages = receiveMessageResponse.messages();<br />                System.out.println("Received " + messages.size() + " messages");<br />                for (Message message : messages) {<br />                    System.out.println("Message ID: " + message.messageId());<br />                    System.out.println("Body: " + message.body());<br />                }<br />            }<br />        });</pre>  | 

## Key configuration parameters
<a name="migration-sqs-auto-batching-params"></a>


****  

| Parameter | v1 | v2 | 
| --- | --- | --- | 
| Maximum batch size | maxBatchSize (default 10 requests per batch) | maxBatchSize (default 10 requests per batch) | 
| Batch wait time | maxBatchOpenMs (default 200 ms) | sendRequestFrequency (default 200 ms) | 
| Visibility timeout | visibilityTimeoutSeconds (-1 for queue default) | receiveMessageVisibilityTimeout (queue default) | 
| Minimum wait time | longPollWaitTimeoutSeconds (20s when longPoll is true) | receiveMessageMinWaitDuration (default 50 ms) | 
| Message attributes | Set using ReceiveMessageRequest | receiveMessageAttributeNames (none by default) | 
| System attributes | Set using ReceiveMessageRequest | receiveMessageSystemAttributeNames (none by default) | 
| Long polling | longPoll (default is true) | Not supported to avoid open connections waiting until the server sends the messages | 
| Maximum wait time for long polling | longPollWaitTimeoutSeconds (default 20s) | Not supported to avoid open connections waiting until the server sends the messages | 
| Maximum number of prefetched receive batches stored client-side | maxDoneReceiveBatches (10 batches) | Not supported because it is handled internally | 
| Maximum number of active outbound batches processed simultaneously | maxInflightOutboundBatches (default 5 batches) | Not supported because it is handled internally | 
| Maximum number of active receive batches processed simultaneously | maxInflightReceiveBatches (default 10 batches) | Not supported because it is handled internally | 

# Use the SDK for Java 1.x and 2.x side-by-side
<a name="migration-side-by-side"></a>

You can use both versions of the AWS SDK for Java in your projects.

The following shows an example of the `pom.xml` file for a project that uses Amazon S3 from version 1.x and DynamoDB from version 2.27.21.

**Example of POM**  
This example shows a `pom.xml` file entry for a project that uses both 1.x and 2.x versions of the SDK.  

```
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-bom</artifactId>
            <version>1.12.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
          <groupId>software.amazon.awssdk</groupId>
          <artifactId>bom</artifactId>
          <version>2.27.21</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk-s3</artifactId>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>dynamodb</artifactId>
    </dependency>
</dependencies>
```