

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