Migration step-by-step instructions with example
This section provides a step-by-step guide to migrate your application that currently uses the SDK for Java v1.x to the SDK for Java 2.x. The first part presents an overview of the steps followed by a detailed example of a migration.
The steps that are covered here describe a migration of a normal use case, where the application calls AWS services using model-driven service clients. If you need to migrate code that uses higher level APIs such as S3 Transfer Manager or CloudFront presigning, refer to the section under What's different between the AWS SDK for Java 1.x and 2.x table of contents.
The approach described here is a suggestion. You may use other techniques and leverage your IDE's code editing features to reach the same result.
Overview of steps
1. Begin by adding the SDK for Java 2.x BOM
By adding the Maven BOM (Bill of Materials) element for the SDK for Java 2.x to your POM file, you ensure that all of the v2 dependency you need are from the same version. Your POM can contain both v1 and v2 dependencies. This allows you to incrementally migrate your code rather than change it all at once.
<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>
2.24.3
</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
You can find the latest
version
2. Search files for v1 class import statements
By scanning the files in your application for SERVICE_IDs used in v1 imports, you'll
find the unique SERVICE_IDs used. A SERVICE_ID is a short, unique name for an AWS service.
For example cognitoidentity
is the SERVICE_ID for Amazon Cognito Identity.
3. Determine the v2 Maven dependencies from the v1 import statements
After you find all unique v1 SERVICE_IDs, you can determine the corresponding Maven artifact for the v2 dependency by referring to Package name to Maven artifactId mappings.
4. Add v2 dependency elements to the POM file
Update the Maven POM file with dependency elements determined in step 3.
5. In the Java files, incrementally change over the v1 classes to v2 classes
As you replace v1 classes with v2 classes, make the necessary changes to support the v2 API such as using builders instead of constructors and using fluent getters and setters.
6. Remove v1 Maven dependencies from the POM and v1 imports from files
After you migrate your code to use v2 classes, remove any leftover v1 imports from files and all dependencies from your build file.
7. Refactor the code to use v2 API enhancements
After the code successfully compiles and passes tests, you can take advantage of v2 enhancements such as using a different HTTP client or paginators to simplify code. This is an optional step.
Example migration
In this example, we migrate an application that uses the SDK for Java v1 and accesses several AWS services. We work through the following v1 method in detail in step 5. This is one method in a class that contains eight methods and there are 32 classes in the application.
Only the v1 SDK imports are listed below from the Java file.
import com.amazonaws.ClientConfiguration; import com.amazonaws.regions.Region; import com.amazonaws.regions.RegionUtils; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.AmazonEC2Exception; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.DescribeInstancesRequest; import com.amazonaws.services.ec2.model.DescribeInstancesResult; import com.amazonaws.services.ec2.model.Instance; import com.amazonaws.services.ec2.model.InstanceStateName; import com.amazonaws.services.ec2.model.Reservation; import com.amazonaws.services.ec2.model.Tag; import com.amazonaws.services.ec2.model.TerminateInstancesRequest; ... private static List<Instance> getRunningInstances(AmazonEC2Client ec2, List<String> instanceIds) { List<Instance> runningInstances = new ArrayList<>(); try { DescribeInstancesRequest request = new DescribeInstancesRequest() .withInstanceIds(instanceIds); DescribeInstancesResult result; do { // DescribeInstancesResponse is a paginated response, so use tokens with multiple requests. result = ec2.describeInstances(request); request.setNextToken(result.getNextToken()); // Prepare request for next page. for (final Reservation r : result.getReservations()) { for (final Instance instance : r.getInstances()) { LOGGER.info("Examining instanceId: "+ instance.getInstanceId()); // if instance is in a running state, add it to runningInstances list. if (RUNNING_STATES.contains(instance.getState().getName())) { runningInstances.add(instance); } } } } while (result.getNextToken() != null); } catch (final AmazonEC2Exception exception) { // if instance isn't found, assume its terminated and continue. if (exception.getErrorCode().equals(NOT_FOUND_ERROR_CODE)) { LOGGER.info("Instance probably terminated; moving on."); } else { throw exception; } } return runningInstances; }
1. Add v2 Maven BOM
Add the Maven BOM for the SDK for Java 2.x to the POM along side any other dependencies in the
dependencyManagement
section. If your POM file has the BOM for v1 of the SDK,
leave it for now. It will be removed at a later step.
<dependencyManagement> <dependencies> <dependency> <groupId>org.example</groupId> <!--Existing dependency in POM. --> <artifactId>bom</artifactId> <version>1.3.4</version> <type>pom</type> <scope>import</scope> </dependency> ... <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-bom</artifactId> <!--Existing v1 BOM dependency. --> <version>1.11.1000</version> <type>pom</type> <scope>import</scope> </dependency> ... <dependency> <groupId>software.amazon.awssdk</groupId> <!--Add v2 BOM dependency. --> <artifactId>bom</artifactId> <version>
2.24.3
</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
2. Search files for v1 class import statements
Search the application's code for unique occurrences of import
com.amazonaws.services
. This helps us determine the v1 dependencies used by the
project. If your application has a Maven POM file with v1 dependencies listed, you can use
this information instead.
For this example we use the ripgrep
(rg)
From the root of your code base, execute the following ripgrep
command.
After ripgrep
finds the import statements, they are piped to the
cut
, sort
, and uniq
commands to isolate the
SERVICE_IDs.
rg --no-filename 'import\s+com\.amazonaws\.services' | cut -d '.' -f 4 | sort | uniq
For this application, the following SERVICE_IDs are logged to the console.
autoscaling cloudformation ec2 identitymanagement
This indicates that there was at least one occurrence of each of the following package
names used in import
statements. Four our purposes, the individual class names
don't matter. We just need to find the SERVICE_IDs that are used.
com.amazonaws.services.autoscaling.* com.amazonaws.services.cloudformation.* com.amazonaws.services.ec2.* com.amazonaws.services.identitymanagement.*
3. Determine the v2 Maven dependencies from the v1 import statements
The SERVICE_IDs for v1 that we isolated from Step 2—for example
autoscaling
and cloudformation
—can be mapped to the same
v2 SERVICE_ID for the most part. Since the v2 Maven artifactId matches the SERVICE_ID in
most cases, you have the information you need to add dependency blocks to your POM
file.
The following table shows how we can determine the v2 dependencies.
v1 SERVICE_ID maps to ... package name |
v2 SERVICE_ID maps to ... package name |
v2 Maven dependency |
---|---|---|
ec2
|
ec2
|
|
autoscaling
|
autoscaling
|
|
cloudformation
|
cloudformation
|
|
identitymanagement*
|
iam*
|
|
* The identitymanagement
to iam
mapping is an exception where
the SERVICE_ID differs between versions. Refer to the Package name to Maven artifactId
mappings for exceptions if Maven or Gradle
cannot resolve the v2 dependency.
4. Add v2 dependency elements to the POM file
In step 3, we determined the four dependency blocks that need to be added to the POM file. We don't need to add a version because we have specified the BOM in step 1. After the imports are added, our POM file has the following dependency elements.
... <dependencies> ... <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>autoscaling</artifactId> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>iam</artifactId> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>cloudformation</artifactId> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>ec2</artifactId> </dependency> ... </dependencies> ...
5. In the Java files, incrementally change over the v1 classes to v2 classes
In the method that we are migrating, we see
-
An EC2 service client from
com.amazonaws.services.ec2.AmazonEC2Client
. -
Several EC2 model classes used. For example
DescribeInstancesRequest
andDescribeInstancesResult
.
import com.amazonaws.ClientConfiguration; import com.amazonaws.regions.Region; import com.amazonaws.regions.RegionUtils; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.AmazonEC2Exception; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.DescribeInstancesRequest; import com.amazonaws.services.ec2.model.DescribeInstancesResult; import com.amazonaws.services.ec2.model.Instance; import com.amazonaws.services.ec2.model.InstanceStateName; import com.amazonaws.services.ec2.model.Reservation; import com.amazonaws.services.ec2.model.Tag; import com.amazonaws.services.ec2.model.TerminateInstancesRequest; ... private static List<Instance> getRunningInstances(AmazonEC2Client ec2, List<String> instanceIds) List<Instance> runningInstances = new ArrayList<>(); try { DescribeInstancesRequest request = new DescribeInstancesRequest() .withInstanceIds(instanceIds); DescribeInstancesResult result; do { // DescribeInstancesResponse is a paginated response, so use tokens with multiple re result = ec2.describeInstances(request); request.setNextToken(result.getNextToken()); // Prepare request for next page. for (final Reservation r : result.getReservations()) { for (final Instance instance : r.getInstances()) { LOGGER.info("Examining instanceId: "+ instance.getInstanceId()); // if instance is in a running state, add it to runningInstances list. if (RUNNING_STATES.contains(instance.getState().getName())) { runningInstances.add(instance); } } } } while (result.getNextToken() != null); } catch (final AmazonEC2Exception exception) { // if instance isn't found, assume its terminated and continue. if (exception.getErrorCode().equals(NOT_FOUND_ERROR_CODE)) { LOGGER.info("Instance probably terminated; moving on."); } else { throw exception; } } return runningInstances; } ...
Our goal is to replace all v1 imports with v2 imports. We proceed one class at a time.
a. Replace import statement or class name
We see that the first parameter to the describeRunningInstances
method is a v1 AmazonEC2Client
instance. Do one of the following:
-
Replace the import for
com.amazonaws.services.ec2.AmazonEC2Client
withsoftware.amazon.awssdk.services.ec2.Ec2Client
and changeAmazonEC2Client
toEc2Client
. -
Change the parameter type to
Ec2Client
and let the IDE prompt us for the correct import. Our IDE will prompt us to import the v2 class because the client names differ—AmazonEC2Client
andEc2Client
. This approach does not work if the class name is the same in both versions.
b. Replace v1 model classes with v2 equivalents
After the change to the v2 Ec2Client
, if we use an IDE, we see
compilation errors in the following statement.
result = ec2.describeInstances(request);
The compilation error results from using an instance of v1's
DescribeInstancesRequest
as a parameter to the v2 Ec2Client
describeInstances
method. To fix, make the following replacement or import
statements.
replace | with |
---|---|
|
|
c. Change v1 constructors to v2 builders.
We still see compilation errors because there are no constructors on v2 classes. To fix, make the following change.
change | to |
---|---|
|
|
d. Replace v1 *Result
response objects with v2 *Response
equivalents
A consistent difference between v1 and v2 is that all response objects in v2 end with *Response
instead of *Result. Replace the v1
DescribeInstancesResult
import to the v2 import,
DescribeInstancesResponse
.
d. Make API changes
The following statement needs a few changes.
request.setNextToken(result.getNextToken());
In v2, setter methods do not use the
set
or with prefix
. Getter methods prefixed with
get
are also gone in the SDK for Java 2.x
Model classes, such as the request
instance, are immutable in v2, so we
need to create a new DescribeInstancesRequest
with a builder.
In v2, the statement becomes the following.
request = DescribeInstancesRequest.builder() .nextToken(result.nextToken()) .build();
d. Repeat until method compiles with v2 classes
Continue with the rest of the code. Replace v1 imports with v2 imports and fix the
compilation errors. Refer to the v2 API Reference
After we migrate this single method, we have the following v2 code.
import com.amazonaws.ClientConfiguration; import com.amazonaws.regions.Region; import com.amazonaws.regions.RegionUtils; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.AmazonEC2Exception; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.InstanceStateName; import com.amazonaws.services.ec2.model.Tag; import com.amazonaws.services.ec2.model.TerminateInstancesRequest; import software.amazon.awssdk.services.ec2.Ec2Client; import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse; import software.amazon.awssdk.services.ec2.model.Ec2Exception; import software.amazon.awssdk.services.ec2.model.Instance; import software.amazon.awssdk.services.ec2.model.Reservation; ... private static List<Instance> getRunningInstances(Ec2Client ec2, List<String> instanceIds) { List<Instance> runningInstances = new ArrayList<>(); try { DescribeInstancesRequest request = DescribeInstancesRequest.builder() .instanceIds(instanceIds) .build(); DescribeInstancesResponse result; do { // DescribeInstancesResponse is a paginated response, so use tokens with multiple re result = ec2.describeInstances(request); request = DescribeInstancesRequest.builder() // Prepare request for next page. .nextToken(result.nextToken()) .build(); for (final Reservation r : result.reservations()) { for (final Instance instance : r.instances()) { // if instance is in a running state, add it to runningInstances list. if (RUNNING_STATES.contains(instance.state().nameAsString())) { runningInstances.add(instance); } } } } while (result.nextToken() != null); } catch (final Ec2Exception exception) { // if instance isn't found, assume its terminated and continue. if (exception.awsErrorDetails().errorCode().equals(NOT_FOUND_ERROR_CODE)) { LOGGER.info("Instance probably terminated; moving on."); } else { throw exception; } } return runningInstances; } ...
Because we are migrating a single method in a Java file with eight methods, we have a mix of v1 and v2 imports as we work through the file. We added the last six import statements as we performed the steps.
After we migrate all the code, there will be no more v1 import statements.
6. Remove v1 Maven dependencies from the POM and v1 imports from files
After we migrate all v1 code in the file, we have the following v2 SDK import statements.
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.regions.ServiceMetadata; import software.amazon.awssdk.services.ec2.Ec2Client; import software.amazon.awssdk.services.ec2.model.CreateTagsRequest; import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse; import software.amazon.awssdk.services.ec2.model.Ec2Exception; import software.amazon.awssdk.services.ec2.model.Instance; import software.amazon.awssdk.services.ec2.model.InstanceStateName; import software.amazon.awssdk.services.ec2.model.Reservation; import software.amazon.awssdk.services.ec2.model.Tag; import software.amazon.awssdk.services.ec2.model.TerminateInstancesRequest;
After we migrate all files in our application, we no
longer need the v1 dependencies in our POM file. Remove the v1 BOM from the
dependencyManagement
section, if using, and all v1 dependency blocks.
7. Refactor the code to use v2 API enhancements
For the snippet we have been migrating, we can optionally use a v2 paginator and let the SDK manage the token-based requests for more data.
We can replace the entire do
clause with the following.
DescribeInstancesIterable responses = ec2.describeInstancesPaginator(request); responses.reservations().stream() .forEach(reservation -> reservation.instances() .forEach(instance -> { if (RUNNING_STATES.contains(instance.state().nameAsString())) { runningInstances.put(instance.instanceId(), instance); } }));
Package name to Maven artifactId mappings
When you migrate your Maven or Gradle project from v1 of the SDK for Java to v2, you need to figure out which dependencies to add to your build file. The approach described in the Migration step-by-step instructions with example (step 3) uses the package names in import statements as a starting point to determine the dependencies (as artifactIds) to add to your build file.
You can use the information in this topic to map the v1 package names to v2 artifactIds.
Common naming convention used in package names and Maven artifactIds
The following table shows the common naming convention that the SDKs use for a given
SERVICE_ID. A SERVICE_ID is a unique identifier for an AWS service. For example, the
SERVICE_ID for the Amazon S3 service is s3
and cognitoidentity
is the
SERVICE_ID for Amazon Cognito Identity.
v1 package name (import statement) | v1 artifactId | v2 artifactId | v2 package name (import statement) |
---|---|---|---|
com.amazonaws.services.SERVICE_ID | aws-java-sdk-SERVICE_ID | SERVICE_ID | software.amazon.awssdk.services.SERVICE_ID |
Example
for Amazon Cognito Identity (SERVICE_ID:
cognitoidentity ) |
|||
com.amazonaws.services.cognitoidentity | aws-java-sdk-cognitoidentity | cognitoidentity | software.amazon.awssdk.services.cognitoidentity |
SERVICE_ID differences
Within v1
In some cases the SERVICE_ID differs between the package name and in the artifactId for
the same service. For example, the CloudWatch Metrics row of the following table shows that
metrics
is the SERVICE_ID in the package name but
cloudwatchmetrics
is the artifactId's SERVICE_ID.
Within v2
There are no differences in the SERVICE_ID used in package names and artifactIds.
Between v1 and v2
For the majority of services, the SERVICE_ID in v2 is the same as v1's SERVICE_ID in both
package names and artifactIds. An example of this is the cognitoedentity
SERVICE_ID as shown in the previous table. However, some SERVICE_IDs differ between the SDKs
as shown in the following table.
A boldface SERVICE_ID in either of the v1 columns indicates that it's different from the SERVICE_ID used in v2.
Service name | v1 package name | v1 artifactId | v2 artifactId | v2 package name |
---|---|---|---|---|
All package names begin with |
All artifactIds are enclosed in tags as shown in the first row. |
All artifactIds are enclosed in tags as shown in the first row. |
All package names begin with |
|
API Gateway | com.amazonaws.services.apigateway | <artifactId>aws-java-sdk-api-gateway</artifactId> | <artifactId>apigateway</artifactId> | software.amazon.awssdk.services.apigateway |
App Registry | appregistry | appregistry | servicecatalogappregistry | servicecatalogappregistry |
Application Discovery | applicationdiscovery | discovery | applicationdiscovery | applicationdiscovery |
Augmented AI Runtime | augmentedairuntime | augmentedairuntime | sagemakera2iruntime | sagemakera2iruntime |
Certificate Manager | certificatemanager | acm | acm | acm |
CloudControl API | cloudcontrolapi | cloudcontrolapi | cloudcontrol | cloudcontrol |
CloudSearch | cloudsearchv2 | cloudsearch | cloudsearch | cloudsearch |
CloudSearch Domain | cloudsearchdomain | cloudsearch | cloudsearchdomain | cloudsearchdomain |
CloudWatch Events | cloudwatchevents | events | cloudwatchevents | cloudwatchevents |
CloudWatch Evidently | cloudwatchevidently | cloudwatchevidently | evidently | evidently |
CloudWatch Logs | logs | logs | cloudwatchlogs | cloudwatchlogs |
CloudWatch Metrics | metrics | cloudwatchmetrics | cloudwatch | cloudwatch |
CloudWatch Rum | cloudwatchrum | cloudwatchrum | rum | rum |
Cognito Identity Provider | cognitoidp | cognitoidp | cognitoidentityprovider | cognitoidentityprovider |
Connect Campaign | connectcampaign | connectcampaign | connectcampaigns | connectcampaigns |
Connect Wisdom | connectwisdom | connectwisdom | wisdom | wisdom |
Database Migration Service | databasemigrationservice | dms | databasemigration | databasemigration |
DataZone | datazone | datazoneexternal | datazone | datazone |
DynamoDB | dynamodbv2 | dynamodb | dynamodb | dynamodb |
Elastic File System | elasticfilesystem | efs | efs | efs |
Elastic Map Reduce | elasticmapreduce | emr | emr | emr |
Glue DataBrew | gluedatabrew | gluedatabrew | databrew | databrew |
IAM Roles Anywhere | iamrolesanywhere | iamrolesanywhere | rolesanywhere | rolesanywhere |
Identity Management | identitymanagement | iam | iam | iam |
IoT Data | iotdata | iot | iotdataplane | iotdataplane |
Kinesis Analytics | kinesisanalytics | kinesis | kinesisanalytics | kinesisanalytics |
Kinesis Firehose | kinesisfirehose | kinesis | firehose | firehose |
Kinesis Video Signaling Channels | kinesisvideosignalingchannels | kinesisvideosignalingchannels | kinesisvideosignaling | kinesisvideosignaling |
Lex | lexruntime | lex | lexruntime | lexruntime |
Lookout For Vision | lookoutforvision | lookoutforvision | lookoutvision | lookoutvision |
Mainframe Modernization | mainframemodernization | mainframemodernization | m2 | m2 |
Marketplace Metering | marketplacemetering | marketplacemeteringservice | marketplacemetering | marketplacemetering |
Managed Grafana | managedgrafana | managedgrafana | grafana | grafana |
Mechanical Turk | mturk | mechanicalturkrequester | mturk | mturk |
Migration Hub Strategy Recommendations | migrationhubstrategyrecommendations | migrationhubstrategyrecommendations | migrationhubstrategy | migrationhubstrategy |
Nimble Studio | nimblestudio | nimblestudio | nimble | nimble |
Private 5G | private5g | private5g | privatenetworks | privatenetworks |
Prometheus | prometheus | prometheus | amp | amp |
Recycle Bin | recyclebin | recyclebin | rbin | rbin |
Redshift Data API | redshiftdataapi | redshiftdataapi | redshiftdata | redshiftdata |
Route 53 | route53domains | route53 | route53domains | route53domains |
Sage Maker Edge Manager | sagemakeredgemanager | sagemakeredgemanager | sagemakeredge | sagemakeredge |
Security Token | securitytoken | sts | sts | sts |
Server Migration | servermigration | servermigration | sms | sms |
Simple Email | simpleemail | ses | ses | ses |
Simple Email V2 | simpleemailv2 | sesv2 | sesv2 | sesv2 |
Simple Systems Management | simplesystemsmanagement | ssm | ssm | ssm |
Simple Workflow | simpleworkflow | simpleworkflow | swf | swf |
Step Functions | stepfunctions | stepfunctions | sfn | sfn |