Upgrade Java SDK V1 to V2
OSS Java SDK V2 is a rewrite of V1 (aliyun-sdk-oss). The changes are concentrated in package names and Maven coordinates, client creation, and API invocation patterns: clients are created through a static factory and require a region, and every operation accepts a typed request object. V2 uses V4 signatures by default and provides an asynchronous client. This topic describes the breaking changes that you must handle when migrating from V1 to V2 and provides an end-to-end migration process.
Assess the scope of changes
Before you migrate, assess the scope of changes to your existing code based on the following three categories: blocking items that surface at compile time, behavior changes that still compile, and optional new capabilities. The three tables in this section are the definitive list of V1/V2 differences. The remaining sections describe only the migration actions and do not repeat the differences.
Compile-time blocking items
These changes directly cause compilation failures. The compiler can locate them one by one, so the scope of changes is relatively certain.
|
Item |
V1 |
V2 |
Step |
|
Maven coordinates |
|
|
Step 1 |
|
Additional JAXB dependencies |
Manually required on Java 9 or later |
Not required |
Step 1 |
|
Java version requirement |
Java 7 or later |
Java 8 or later |
Migration preparation |
|
Package name |
|
|
Step 2 |
|
Client creation |
|
|
Step 3 |
|
Client configuration |
|
Chained builder methods |
Step 3 |
|
API input |
Multiple overloads with simple parameters for the same operation |
A single typed request object (such as |
Step 4 |
|
API output |
|
Result objects such as |
Step 4 |
|
Exception model |
|
Catch |
Step 5 |
|
Resource release |
|
Implements |
Step 3 |
The output type change is the only item that requires additional manual verification: a type mismatch causes a compile-time error, but whether fields are read correctly cannot be fully exposed at compile time. You must verify this item by item in Step 6 based on core paths.
Runtime behavior changes
These changes do not block compilation, but they change how requests are authenticated and which domain names they target. The consequences of missing a change appear only at runtime.
|
Item |
V1 |
V2 |
Step |
|
Signature algorithm |
V1 signatures by default; to use V4 signatures, explicitly set |
|
Step 3 |
|
Region and endpoint |
|
|
Step 3 |
Optional new capabilities
The following two capabilities are non-breaking additions. You can adopt them as needed; migration is complete without them.
|
Item |
V1 |
V2 |
Step |
|
Asynchronous capability |
No separate asynchronous client |
|
Step 3 (optional) |
|
List pagination |
Manually maintain a marker loop to pull pages |
Paginator interfaces, such as |
Step 4 (optional) |
Migration preparation
Confirm the following five items once before you start, so that you do not have to redo work midway due to missing environment or information.
Build environment: Confirm that the JDK version in your build and runtime environments meets the V2 requirement, which is Java 8 or later.
Region information: Confirm the region to which the bucket belongs.
regionis a required parameter in V2.Credential configuration: Both V1 and V2 read long-term credentials from the
OSS_ACCESS_KEY_IDandOSS_ACCESS_KEY_SECRETenvironment variables, and also readOSS_SESSION_TOKENin STS scenarios. The environment variable names are the same in both versions, so no deployment configuration changes are required. If your existing code uses credentials such asRAMRoleARN,ECSRAMRole, orOIDCRoleARN, V2 requires a custom credentials provider implemented together with thecredentials-javalibrary. Include this development effort when you estimate the workload.Call-site checklist: Identify every place in your existing code that calls the OSS SDK, and record the interfaces and features in use as the verification checklist for Step 6.
Test environment: Prepare a test environment in which you can run the migrated code, and complete verification before you release it.
Migration path: V1 and V2 have different package names, so they can coexist in the same project without class conflicts. Therefore, two migration paths are supported:
One-time full replacement (default): suitable for projects where OSS call sites are concentrated and regression verification can be completed in one pass. In Step 1, remove the V1 dependency directly, and the subsequent steps cover all call sites in the project.
Module-by-module canary migration: suitable for projects where call sites are scattered and cannot be regressed all at once. In Step 1, keep both the V1 and V2 dependencies temporarily and rewrite only the code in the current migration scope. Remove the V1 dependency after all modules are migrated.
Complete migration steps
Step 1: Update the Maven dependency
Replace the dependency coordinates in pom.xml. The V1 dependency is as follows:
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.18.4</version>
</dependency>
For the V2 dependency, replace <version> with the latest version number that you find on Maven Repository:
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibabacloud-oss-v2</artifactId>
<version><!-- Enter the latest version number --></version>
</dependency>
V1 additionally declares JAXB-related dependencies for Java 9 or later (javax.xml.bind:jaxb-api, javax.activation:activation, and org.glassfish.jaxb:jaxb-runtime). V2 no longer needs them, so you can remove them as well.
Step 2: Change package names and imports
Replace imports of com.aliyun.oss and its subpackages with the corresponding types under com.aliyun.sdk.service.oss2. The following table lists the mappings for commonly used packages:
|
V1 package or type |
V2 package or type |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Client configuration is provided directly as chained methods on |
V2 groups its model classes in the models package. When you replace imports in bulk, import com.aliyun.sdk.service.oss2.models.* first, and then add the missing types one by one based on the compilation errors.
Step 3: Change the client creation code
Determine the region and endpoint
region is required in all scenarios and must be the region in which the bucket resides. Whether to keep endpoint depends on the access scenario. The default path is to set only region and not pass endpoint, so that the access domain name is derived from region.
|
Access scenario |
**Is |
Switch method to set |
|
Default public access (recommended) |
No; derived from |
None |
|
Custom domain name |
Yes; specify the custom domain name |
|
|
Internal endpoint |
Yes; specify the internal endpoint |
|
|
Transfer acceleration endpoint |
Yes; specify the transfer acceleration endpoint |
|
Replace the client creation code
V1 requires you to construct a credentials provider and a client configuration object, and to declare V4 signatures explicitly. The following V1 example uses the OSSClientBuilder.create() chained form. Existing code that uses new OSSClientBuilder().build(endpoint, ak, sk) also converges to the V2 form after migration. In the example code, replace <region-id> with the region in which the bucket resides, such as cn-hangzhou, and replace <endpoint> with the access domain name of the bucket. V1 requires this parameter.
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");
String region = "<region-id>";
String endpoint = "<endpoint>";
DefaultCredentialProvider provider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// V1 requires V4 signatures to be declared explicitly
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.credentialsProvider(provider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.endpoint(endpoint)
.build();
// Perform OSS operations...
ossClient.shutdown();
V2 creates the client through a static factory. region is required and V4 signatures are used by default. Specify endpoint only in the scenarios listed in the preceding table. OSSClient implements AutoCloseable, so try-with-resources releases resources automatically:
import com.aliyun.sdk.service.oss2.OSSClient;
import com.aliyun.sdk.service.oss2.credentials.CredentialsProvider;
import com.aliyun.sdk.service.oss2.credentials.EnvironmentVariableCredentialsProvider;
CredentialsProvider provider = new EnvironmentVariableCredentialsProvider();
try (OSSClient client = OSSClient.newBuilder()
.credentialsProvider(provider)
.region("<region-id>")
.build()) {
// Perform OSS operations...
}
Replace credentials provider type names according to the mappings in Step 2. The V2 example above uses EnvironmentVariableCredentialsProvider to read credentials directly from environment variables. The credential source is the same as the V1 example, which reads environment variables first and then wraps them in DefaultCredentialProvider. To pass an AccessKey explicitly from code, use StaticCredentialsProvider instead.
Creating and destroying a client is expensive. Reuse a single instance in high-frequency scenarios.
If you reuse a V2 client with the singleton pattern, you cannot rely on try-with-resources. You must call close() explicitly before the application exits. Otherwise, resources leak.
Migrate client configurations and the retry policy
V1 sets parameters such as timeouts, retries, and proxies on a ClientConfiguration or ClientBuilderConfiguration object. V2 raises these parameters to chained methods on OSSClient.newBuilder(), such as connectTimeout, readWriteTimeout, retryMaxAttempts, retryer, proxyHost, useCName, useInternalEndpoint, useAccelerateEndpoint, disableSsl, and usePathStyle. For the full list of configurations, see the client configuration content of the V2 SDK documentation.
Retries are an optional tuning item. V2 uses StandardRetryer by default, with a maximum of 3 attempts, a maximum backoff time of 20 seconds, a base delay of 0.2 seconds, and the FullJitter backoff algorithm. To adjust the policy, build a custom retryer by using StandardRetryer.newBuilder() and pass it to retryer(...). To disable retries, pass NopRetryer.
Optional: Switch to the asynchronous client
If your workload needs to execute multiple independent operations concurrently, switch to the asynchronous client. Operations return CompletableFuture:
import com.aliyun.sdk.service.oss2.OSSAsyncClient;
import com.aliyun.sdk.service.oss2.credentials.EnvironmentVariableCredentialsProvider;
import com.aliyun.sdk.service.oss2.models.*;
import java.util.concurrent.CompletableFuture;
try (OSSAsyncClient client = OSSAsyncClient.newBuilder()
.credentialsProvider(new EnvironmentVariableCredentialsProvider())
.region("<region-id>")
.build()) {
CompletableFuture<ListBucketsResult> future = client.listBucketsAsync(
ListBucketsRequest.newBuilder().build());
future.thenAccept(result -> {
for (BucketSummary info : result.buckets()) {
System.out.printf("bucket: name:%s, region:%s%n", info.name(), info.region());
}
});
future.join();
}
Step 4: Change the API input and output forms
V2 consolidates the input of every operation into a request object and the output into a result object. This section uses listing buckets to demonstrate the general migration pattern. Migrate other operations in the same way.
V1:
List<Bucket> buckets = ossClient.listBuckets();
for (Bucket bucket : buckets) {
System.out.println(bucket.getName());
}
V2:
import com.aliyun.sdk.service.oss2.models.*;
ListBucketsResult result = client.listBuckets(
ListBucketsRequest.newBuilder().build());
for (BucketSummary info : result.buckets()) {
System.out.printf("bucket: name:%s, region:%s, storageClass:%s%n",
info.name(), info.region(), info.storageClass());
}
Note the following three differences when you rewrite the code. First, input: even if an operation takes no parameters, you must construct a request object by using XxxRequest.newBuilder().build(). Second, output: read result fields by using accessor methods that are named after the fields (result.buckets(), info.name()) instead of the V1 getXxx() getters. Third, pagination: V1 requires you to maintain a marker loop to pull pages manually, whereas V2 provides paginator interfaces. For example, client.listBucketsPaginator(...) returns ListBucketsIterable, which you can iterate over directly to get all pages:
import com.aliyun.sdk.service.oss2.paginator.ListBucketsIterable;
ListBucketsIterable paginator = client.listBucketsPaginator(
ListBucketsRequest.newBuilder().build());
for (ListBucketsResult page : paginator) {
for (BucketSummary info : page.buckets()) {
System.out.println(info.name());
}
}
Step 5: Change the exception handling logic
V1 requires you to catch server-side and client-side exceptions separately. Both extend RuntimeException:
try {
ossClient.putObject(...);
} catch (OSSException oe) {
// The request reached the server but was rejected: insufficient permissions, invalid parameters, resource not found, and so on
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
} catch (ClientException ce) {
// Client-side issues: network unavailable, request timeout, certificate validation failure, and so on
System.out.println("Error Message: " + ce.getMessage());
} finally {
ossClient.shutdown();
}
In V2, catch the error uniformly with catch (Exception e), use ServiceException.asCause(e) to determine whether it is a server-side error, and if so read information such as requestId() and errorCode(); otherwise handle it as a client-side error:
import com.aliyun.sdk.service.oss2.exceptions.ServiceException;
try {
client.putObject(...);
} catch (Exception e) {
ServiceException se = ServiceException.asCause(e);
if (se != null) {
System.out.printf("ServiceException: requestId:%s, errorCode:%s%n",
se.requestId(), se.errorCode());
} else {
System.out.printf("error:%n%s", e);
}
}
Existing error code branches based on OSSException.getErrorCode() (such as SignatureDoesNotMatch, AccessDenied, and NoSuchKey) can be moved directly to ServiceException.errorCode(). The error code values remain the same. When you use the asynchronous client, exceptions are obtained through the CompletableFuture.exceptionally() callback, and server-side information is also extracted through ServiceException.asCause(e).
Step 6: Test and verify
Verify the migration results in the order shown in the following table. Proceed to the next item only after the current item meets its pass criteria.
Verification item |
Method |
Pass criteria |
Compilation verification |
Compile the project and search for remaining V1 code patterns |
The build succeeds, and no |
Core-path field verification |
In the test environment, cover the call-site checklist recorded during migration preparation, and focus on whether result fields are read correctly in core paths such as upload, download, list, and delete |
Result fields are read correctly in all paths. Note
The return type change is a risk that compilation cannot fully expose. Verify it item by item manually. |
Authentication and domain verification |
Confirm that every client sets |
Requests pass authentication with V4 signatures, and the domain and switch settings match the scenario decision table in Step 3 |
Asynchronous path verification |
If you introduced the asynchronous client, trigger both the normal completion path and the exception path |
|
Canary observation |
Perform a canary release and observe the error code distribution and the number of retries |
Confirm that no anomalies occur, and then switch all traffic |
Rollback
If a problem is found during the canary period, you can roll back by using the coexistence capability of the two versions: restore the V1 dependency in pom.xml, and revert the imports, client creation, API calls, and exception handling code that were rewritten in the current batch. The rollback scope matches the scope of the current batch.
References
For the installation, client configuration, access credentials, and sample code of V2, see OSS Java SDK V2.
For the installation, client configuration, and exception handling of V1, see OSS Java SDK V1.