This topic explains some of the key concepts for using the Oracle Cloud Infrastructure SDK for Java.

Synchronous Calls

To make synchronous calls, create an instance of the synchronous client. The general pattern for synchronous clients is that for a service named Example, there will be an interface named ExampleService, and the synchronous client implementation will be called ExampleServiceClient. Here's an example of creating an Object Storage client:

AuthenticationDetailsProvider provider = ...;
ObjectStorage clientWithDefaultClientConfig = new ObjectStorageClient(provider);

ClientConfiguration clientConfig = ...;
ObjectStorage clientWithExplicitClientConfig = new ObjectStorageClient(provider, clientConfig);

Synchronous calls will block until the response is available. All SDK APIs return a response object (regardless of whether or not the API sends any content back). The response object typically contains at least a request ID that you can use when contacting Oracle support for help on a particular request.

ObjectStorage client = ...;
GetBucketResponse response = client.getBucket(
String requestId = response.getOpcRequestId();
Bucket bucket = response.getBucket();

Asynchronous Calls

To make asynchronous calls, create an instance of the asynchronous client. The general pattern for asynchronous clients is that for a service named Example, there will be an interface named ExampleServiceAsync, and the asynchronous client implementation will be called ExampleServiceAsyncClient. Here's an example of creating an Object Storage client:

AuthenticationDetailsProvider provider = ...;
ObjectStorageAsync clientWithDefaultClientConfig = new ObjectStorageAsyncClient(provider);
ClientConfiguration clientConfig = ...;
ObjectStorageAsync clientWithExplicitClientConfig = new ObjectStorageAsyncClient(provider, clientConfig);

Asynchronous calls return immediately. You need to provide an AsyncHandler that will be invoked after the call completes either successfully or unsuccessfully:

ObjectStorageAsync client = ...;
AsyncHandler<GetBucketRequest, GetBucketResponse> handler = new AsyncHandler<GetBucketRequest, GetBucketResponse>() {
        public void onSuccess(GetBucketRequest request, GetBucketResponse response) {
            String requestId = response.getOpcRequestId();
            Bucket bucket = response.getBucket();

        public void onError(GetBucketRequest request, Throwable error) {
Future<GetBucketResponse> future = client.getBucket(

Polling with Waiters

The SDK offers waiters that allow your code to wait until a specific resource reaches a desired state. A waiter can be invoked in both a blocking or a non-blocking (with asychronous callback) manner, and will wait until either the desired state is reached or a timeout is exceeded. Waiters abstract the polling logic you would otherwise have to write into an easy-to-use single method call.

Waiters are obtained through the service client (client.getWaiters()). Both a Get<Resource>Request and the desired lifecycle state are passed in to the waiters.for<Resource> method. For example:

public static Instance waitForInstanceProvisioningToComplete(  ComputeClient computeClient, String instanceId) throws Exception {
    ComputeWaiters waiters = computeClient.getWaiters();
    GetInstanceResponse response = waiters.forInstance(
    return response.getInstance();

Each waiters.for<Resource> method has two versions:

  • One version uses the default polling values. For example:

    waiters.forInstance(GetInstanceRequest, LifecycleState)
  • The other version gives you full control over how long to wait and how much time between polling attempts. For example:

    waiters.forInstance(GetInstanceRequest, LifecycleState, TerminationStrategy, DelayStrategy)

Threading Model

A client becomes thread-safe when it is initialized. After setting its endpoint, you can safely use a client in multiple threads and concurrently call methods on it.

You can reuse a client on multiple requests, both across concurrent threads or within a single thread. Unless the environment's resources are constrained, you should only close the client immediately before it goes out of scope.


This guarantee applies only to the default JAX-RS implementation, Jersey. When using an alternate implementation, you must manage thread safety yourself. For more information, see Configuring the SDK

Uploading Large Objects

The Object Storage service supports multipart uploads to make large object uploads easier by splitting the large object into parts. The SDK for Java supports raw multipart upload operations for advanced use cases, as well as a higher level upload class that uses the multipart upload APIs. Managing Multipart Uploads provides links to the APIs used for multipart upload operations. Higher level multipart uploads are implemented using the UploadManager, which will: split a large object into parts for you, upload the parts in parallel, and then recombine and commit the parts as a single object in storage.

The UploadObject example shows how to use the UploadManager to automatically split an object into parts for upload to simplify interaction with the Object Storage service.


You can configure the SDK for Java to retry SDK operations that fail. The SDK allows you to specify the strategy to use for how retries are handled, including the number of times to retry, the condition under which the SDK should retry an operation, and when to stop retrying an operation. You can set these parameters at the client level and at the individual request level.

Retries are not currently supported for asynchronous clients

Delay Strategy

The delayStrategy parameter determines how long to wait between each retry call. There are two options for this parameter:

  • FixedTimeDelayStrategy (milliseconds) - Each retry is delayed by a specified number of milliseconds.
  • ExponentialBackoffDelayStrategy (milliseconds) - The delay time for subsequent retry calls increases by an exponential factor of 2 until it reaches the defined maximum delay (in milliseconds), with a base value of one millisecond.

The default delay strategy is set to ExponentialBackoffDelayStrategy with 30 seconds (30000 milliseconds) of delay.

Retry Condition

The retryCondition defines a function with an error argument that returns a boolean indicating whether to retry or not. The operation will be retried if this function returns true.

Termination Strategy

The terminationStrategy parameter defines when to terminate the retry attempts. This parameter supports the following options:

  • MaxTimeTerminationStrategy (milliseconds) - Defines total duration in milliseconds for which the retry attempts.
  • MaxAttemptsTerminationStrategy (attempts) - Defines the total number of retry attempts.

Retry Examples


This example shows how to configure and use retries with the SDK for Java:

 * Copyright (c) 2016, 2021, Oracle and/or its affiliates.  All rights reserved.
 * This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at or Apache License 2.0 as shown at You may choose either license.

 * This example demonstrates how to use the SDK retries.
 * Retry configuration may be set at
 * a) the SDK level (using {@link Retriers#setDefaultRetryConfiguration(RetryConfiguration)}
 * b) the client level (using {@link ClientConfiguration}
 * c) the request level (using {@link}
public class RetryExample {
    public static void main(String[] args) throws Exception {
        String configurationFilePath = "~/.oci/config";
        String profile = "DEFAULT";

        // Configuring the AuthenticationDetailsProvider. It's assuming there is a default OCI config file
        // "~/.oci/config", and a profile in that config with the name "DEFAULT". Make changes to the following
        // line if needed and use ConfigFileReader.parse(configurationFilePath, profile);

        final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parseDefault();

        final AuthenticationDetailsProvider provider =
                new ConfigFileAuthenticationDetailsProvider(configFile);

        // Set the default retry strategy for all operations to set retry attempts to 3
                        .terminationStrategy(new MaxAttemptsTerminationStrategy(3))

        // Override the default retry strategy for the identity client and update retry attempts to 4
        final Identity identityClient =
                new IdentityClient(
                                                        new MaxAttemptsTerminationStrategy(4))

        // Override the client's retry strategy for the list regions request and wait for 5ms between retrying
        final ListRegionsRequest listRegionsRequest =
                                        .terminationStrategy(new MaxAttemptsTerminationStrategy(2))
                                        .delayStrategy(new FixedTimeDelayStrategy(5L))
        final ListRegionsResponse listRegionsResponse =


Raw Requests

Raw requests are useful, and in some cases necessary. Typical use cases are: when using your own HTTP client, making a OCI-authenticated request to an alternate endpoint, and making a request to a OCI API that is not currently supported in the SDK. The SDK for Java exposes the DefaultRequestSigner class that you can use to create a RequestSigner instance for non-standard requests.

The Raw Request example on GitHub shows how to:

  • create an authentication provider and request signer
  • integrate with an HTTP client (Jersey in this example) to authenticate requests

Setting the Endpoints

Service endpoints can be set in three ways.

  • Call setEndpoint() on the service instance. This lets you specify a full host name (for example,
  • Call setRegion() on the service instance. This selects the appropriate host name for the service for the given region. However, if the service is not supported in the region you set, the SDK for Java returns an error.
  • Pass the region in the configuration file. For more information, see SDK and CLI Configuration File.

Note that a service instance cannot be used to communicate with different regions. If you need to make requests to different regions, create multiple service instances.

Forward Compatibility and enums

If you have conditional logic based on an enum, be sure that your code handles the UnknownEnumValue case to ensure forward compatibility. Some response fields are of type enum, but in the future, individual services may return values not covered by existing enums for that field. To address this possibility, every response field of type enum has an additional value named UnknownEnumValue. If a service returns a value that is not recognized by your version of the SDK, then the response field will be set to this value.

New Region Support

If you are using a version of the SDK released prior to the announcement of a new region, you can use a workaround to reach it.

A region is a localized geographic area. For more information on regions and how to identify them, see Regions and Availability Domains.

A realm is a set of regions that share entities. You can identify your realm by looking at the domain name at the end of the network address. For example, the realm for is

You must first call Region.register to register the new region, and then you can set the region by either using the configuration file or by calling the setRegion method.


Once a region is registered, the federation endpoint is no longer required while using instance principals. For an example, see Realm

For regions in the realm, you can pass new region names just as you would pass ones that are already defined in the Region enum for your SDK version.


For the following code samples, be sure to supply the appropriate endpoints for your region.

If you are using version 1.2.34 or later of the SDK for Java, you can pass the new region name as a string using one of the following methods:

  • To set the region on a previously created client:

  • To set a region when building a new client:

    Identity identityClient = IdentityClient.builder()
  • You can also pass the region in the configuration file. For more information, see SDK and CLI Configuration File.

Other Realms

For regions in realms other than, you can use the following workarounds to reach new regions with earlier versions of the SDK.

To specify the endpoint:
AuthenticationDetailsProvider provider =
        new ConfigFileAuthenticationDetailsProvider(configurationFilePath, profile);

IdentityClient client = IdentityClient.builder()
If you are authenticating via instance principals, you can set the endpoint and federationEndpoint via the following process:
InstancePrincipalsAuthenticationDetailsProvider provider = InstancePrincipalsAuthenticationDetailsProvider.builder()

IdentityClient identityClient = IdentityClient.builder()

Paginated Responses

Some APIs return paginated result sets, so you must check for additional items and if necessary, fetch the next page. You can do so manually or you can use an iterator.

Manually Fetching Pages

The Response objects contain a method to fetch the next page token. If the token is null, there are no more items. If it is not null, you can make an additional request, by setting the token on the Request object, to get the next page of responses.


Some APIs may return a token even if there are no additional results. Be sure to also check whether any items were returned and stop if there are none.

This example shows how to handle page tokens returned by the Object Storage API:

ObjectStorage client = ...;
ListBucketsRequest.Builder builder =
String nextPageToken = null;
do {;
    ListBucketsResponse listResponse = client.listBuckets(;
    List<Bucket> buckets = listResponse.getItems();
    // handle buckets
    nextPageToken = listResponse.getOpcNextPage();
} while (nextPageToken != null);

Using an Iterator

Instead of manually working with page tokens, you can use an iterator. Each service client exposes a getPaginators() method that returns a Paginator object. This object contains methods to return objects of type Iterable. We support two approaches to using iterable:

  • Response Iterator: You can iterate over the Response objects that are returned by the list operation. These are referred to as ResponseIterators, and their methods are suffixed with "ResponseIterator," for example, listUsersResponseIterator.
    Iterable<ListUsersResponse> responseIterator = identityClient.getPaginators().listUsersResponseIterator(request);
    for (ListUsersResponse response : responseIterator) {
        for (User user : response.getItems()) {
  • Record Iterator: You can iterate over the resources/records that are listed. These are referred to as RecordIterator, and their methods are suffixed with "RecordIterator," for example, listUsersRecordIterator.
    Iterable<User> recordIterator = identityClient.getPaginators().listUsersRecordIterator(request)
    for (User user : recordIterator) {

Client-Side Encyption

Client Side Encryption allows you to encrypt data on the client side before storing it locally or using it with other Oracle Cloud Infrastructure services.

To use client-side encryption, you must create a master encryption key (MEK) using the Key Management Service. This can be done using the CreateKey or ImportKey operations.

The MEK is used to generate a Data Encryption Key (DEK) to encrypt each payload. A encrypted copy of this DEK (encrypted under the MEK) and other pieces of metadata are included in the encrypted payload returned by the SDKs so that they can be used for decryption.

Java Prerequisites

The unlimited policy files for earlier releases are required only for JDK 8, 7, and 6 updates earlier than 8u161, 7u171, and 6u16. For those versions and later the policy files are included but not enabled by default.

Current versions of the JDK do not require these policy files. They are provided here for use with older versions of the JDK. JDK 9 and later ship with the unlimited policy files and use them by default.


The following code example shows how to encrypt a string:

// String encryption example
final byte[] plainText = "Hello World".getBytes();
String masterKeyId = "OCID....";
Map<String, String> context = Collections.singletonMap("Example", "value");
OciCrypto ociCrypto = new OciCrypto();
KmsMasterKey kmsMasterKey = new KmsMasterKey(authenticationProvider, Region.US_ASHBURN_1.getRegionId(), vaultId, masterKeyId);
KmsMasterKeyProvider kmsMasterKeyProvider = new KmsMasterKeyProvider(kmsMasterKey);
//  Encrypt the data and embed the master key ID in the header
final OciCryptoResult encryptResult = ociCrypto.encryptData(kmsMasterKeyProvider, plainText, context);
final byte[] cipherText = encryptResult.getResult();
//  Decrypt the data
final OciCryptoResult decryptResult = ociCrypto.decryptData(kmsMasterKeyProvider, cipherText);

The following example shows how to encrypt a file stream:

// Create Encryption file stream
FileInputStream in = new FileInputStream(srcFile);
OciCrypto ociCrypto = new OciCrypto();
KmsMasterKey kmsMasterKey = new KmsMasterKey(authenticationProvider, Region.US_ASHBURN_1.getRegionId(), vaultId, masterKeyId);
KmsMasterKeyProvider kmsMasterKeyProvider = new KmsMasterKeyProvider(kmsMasterKey);
OciCryptoInputStream encryptingStream = ociCrypto.createEncryptingStream(kmsMasterKeyProvider, in);
// Write the encrypted data to file
FileOutputStream out = new FileOutputStream(srcFile + ".encrypted");
IOUtils.copy(encryptingStream, out);
// For decryption, no need to pass key info
KmsMasterKeyProvider kmsMasterKeyProvider = new KmsMasterKeyProvider(authenticationProvider);
// Create the Decryption file stream.
in = new FileInputStream(srcFile + ".encrypted");
OciCryptoInputStream decryptingStream = ociCrypto.createDecryptingStream(kmsMasterKeyProvider, in);
// Return the plaintext data
out = new FileOutputStream(srcFile + ".decrypted");
IOUtils.copy(decryptingStream, out);

Exception Handling

When handling an exception, you can get more information about the HTTP request that caused it, such as the status code or timeout. You can also get the request ID when handling a BmcException by using the getOpcRequestId method.

This example shows a try-catch block that handles a BmcExceptionand prints the request ID.

ObjectStorage client = ...;
try {
    GetBucketResponse response = client.getBucket(
    String requestId = response.getOpcRequestId();
} catch (BmcException e) {
    String requestId = e.getOpcRequestId();

Exceptions in the SDK for Java are runtime exceptions (unchecked), so they do not show up in method signatures. All APIs can throw a BmcException.