> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://learning.postman.com/llms.txt.

# Use Java SDKs generated in Postman

This guide provides instructions for using Java SDKs generated by Postman SDK Generator. It covers how to import the SDK into your project, run example code, and best practices for using the SDK effectively in your applications.

## SDK structure

The Java SDK includes the following key files:

* `[SdkName].java` — Main SDK client, instantiated with `[SdkName]Config`.
* `services/` — Service classes with both sync and async methods.
* `models/` — Data models (POJOs with Lombok builders, enums, typed exceptions) with Jackson serialization.
* `config/` — Configuration classes for auth, retry, and SDK client settings.
* `pom.xml` — Specifies dependencies (OkHttp, Jackson, Lombok).

The following is an example of the typical structure of a generated Java SDK:

## Example usage

Each generated SDK includes an `examples/` directory with a working project demonstrating SDK usage.

The example includes the following features:

* SDK initialization with config builder pattern
* Synchronous API calls
* Working with model builders
* Exception handling

#### Location

`examples/src/main/java/Main.java`

#### Run the example

```bash
cd examples
./run.sh
```

Or manually:

```bash
cd path/to/your-sdk
mvn clean install
cd examples
mvn clean install
mvn exec:java
```

#### Example code structure

```java
import com.example.sdk.Sdk;
import com.example.sdk.config.SdkConfig;
import com.example.sdk.config.ApiKeyAuthConfig;
import com.example.sdk.models.User;

public class Main {
    public static void main(String[] args) {
        // Initialize the SDK
        SdkConfig config = SdkConfig.builder()
            .apiKeyAuthConfig(
                ApiKeyAuthConfig.builder()
                    .apiKey("your-api-key")
                    .build()
            )
            .build();

        Sdk sdk = new Sdk(config);

        try {
            // Call an API endpoint
            User user = sdk.usersService.getUser("123");
            System.out.println("User: " + user);
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}
```

## Import the Java SDK locally

You can import the generated SDK using Maven, project file path, or Gradle. Below are instructions for each method.

### Import using a Maven local repository

To import the generated SDK using a local Maven repository, do the following:

1. Install SDK to local Maven repository.

   ```bash
   cd path/to/your-sdk
   mvn clean install
   ```

2. Add dependency to your project's `pom.xml`.

   ```xml
   <dependency>
       <groupId>com.example</groupId>
       <artifactId>your-sdk</artifactId>
       <version>1.0.0</version>
   </dependency>
   ```

3. Use the SDK in your code.

```java
import com.example.sdk.Sdk;
import com.example.sdk.config.SdkConfig;

SdkConfig config = SdkConfig.builder().build();
Sdk sdk = new Sdk(config);
```

### Import using the project file path

To import the generated SDK using the project file path, do the following:

1. Add SDK as a module in your project's `pom.xml`.

   ```xml
   <modules>
       <module>../path/to/your-sdk</module>
       <module>your-app</module>
   </modules>
   ```

2. Reference as dependency.

   ```xml
   <dependency>
       <groupId>com.example</groupId>
       <artifactId>your-sdk</artifactId>
       <version>${project.version}</version>
   </dependency>
   ```

### Import using Gradle

To import the generated SDK using Gradle, first install it to your local Maven repository:

```bash
cd path/to/your-sdk
mvn clean install
```

Then, add the dependency to your `build.gradle` file:

```gradle
dependencies {
    implementation group: 'com.example', name: 'your-sdk', version: '1.0.0'
}
```

Alternatively, if you want to reference the SDK as a JAR file, first build the fat JAR:

```bash
cd path/to/your-sdk
mvn compile assembly:single
```

Then, add the JAR to your `build.gradle`:

```gradle
dependencies {
    implementation files('../path/to/your-sdk/target/your-sdk-1.0.0-jar-with-dependencies.jar')
}
```

## Publish

To publish your generated Java SDK, see [Publish Java SDKs generated in Postman](/docs/sdk-generator/publish/java-manual/).

## Advanced usage

You can further customize the SDK by modifying the generated code, adding new features, or integrating it with your existing codebase. Here are some advanced topics to explore.

### Authentication

The SDK supports various authentication methods. You can configure authentication when initializing the SDK client.

The SDK includes authentication support based on the security schemes defined in your API specification. The following examples show the possible authentication methods.

#### API Key

```java
SdkConfig config = SdkConfig.builder()
    .apiKeyAuthConfig(
        ApiKeyAuthConfig.builder()
            .apiKey("your-api-key")
            .build()
    )
    .build();

Sdk sdk = new Sdk(config);
```

#### Bearer Token

```java
SdkConfig config = SdkConfig.builder()
    .accessToken("your-bearer-token")
    .build();

Sdk sdk = new Sdk(config);
```

#### Basic Auth

```java
SdkConfig config = SdkConfig.builder()
    .basicAuthConfig(
        BasicAuthConfig.builder()
            .username("your-username")
            .password("your-password")
            .build()
    )
    .build();

Sdk sdk = new Sdk(config);
```

#### OAuth 2.0

```java
SdkConfig config = SdkConfig.builder()
    .clientId("your-client-id")
    .clientSecret("your-client-secret")
    .build();

Sdk sdk = new Sdk(config);

// SDK automatically handles token refresh
User user = sdk.usersService.getUser("123");
```

To update the credentials after initialization, run one of the following. The `setApiKey`, `setAccessToken`, and `setBasicAuthCredentials` methods are each only generated when the corresponding auth type is in the specification.

```java
sdk.setApiKey("new-api-key");
sdk.setAccessToken("new-token");
sdk.setBasicAuthCredentials("new-username", "new-password");
```

### Synchronous and asynchronous calls

Every service method has a sync variant (`methodName`) and an async variant (`methodNameAsync`). Sync methods return the type directly (for example, `Pet`), while
async methods return `CompletableFuture<T>` (for example, `CompletableFuture<Pet>`).
For void methods, async returns `CompletableFuture<Void>`.

```java
import java.util.concurrent.CompletableFuture;

// Synchronous — blocks until the response is returned
Pet pet = sdk.petService.getPetById(123);
System.out.println("Pet: " + pet.getName());

// Asynchronous — returns a CompletableFuture
CompletableFuture<Pet> futurePet = sdk.petService.getPetByIdAsync(123);

// Option 1: Non-blocking with callbacks
futurePet
    .thenAccept(p -> System.out.println("Pet: " + p.getName()))
    .exceptionally(e -> {
        System.err.println("Error: " + e.getMessage());
        return null;
    });

// Option 2: Blocking wait when needed
Pet pet = futurePet.get();
```

### Environment management

The SDK supports multiple environments (for example, production, staging) with different base URLs.

```java
// Use environment enum
sdk.setEnvironment(Environment.PRODUCTION);

// Or set custom base URL
sdk.setBaseUrl("https://custom.api.example.com");
```

### Hierarchical configuration

Java supports all four levels of configuration: SDK (through `SdkConfig` or `sdk.setEnvironment()/sdk.setBaseUrl()`), and service, method, and request levels (through `RequestConfig`). Each level overrides the previous, with request being most specific.

```java
import com.example.sdk.Sdk;
import com.example.sdk.config.SdkConfig;
import com.example.sdk.config.RequestConfig;
import com.example.sdk.http.Environment;

// 1. SDK level — default for everything
SdkConfig config = SdkConfig.builder()
    .baseUrl("https://api.example.com")
    .timeout(10000)
    .build();

Sdk sdk = new Sdk(config);

// 2. Service level — override for all methods in usersService
sdk.usersService.setConfig(
    RequestConfig.builder()
        .timeout(15000L)
        .build()
);

// 3. Method level — override for getUser only
sdk.usersService.setGetUserConfig(
    RequestConfig.builder()
        .baseUrl("https://legacy-api.example.com")
        .build()
);

// 4. Request level — override for this single call
User user = sdk.usersService.getUser("123",
    RequestConfig.builder()
        .timeout(30000L)
        .build()
);
```

### Error handling

The SDK raises custom exceptions for API errors, which include details about the error message, status code, and response body. You can catch these exceptions to handle errors gracefully in your application.

To handle errors, do the following:

```java
import com.example.sdk.exceptions.APIError;

try {
    User user = sdk.usersService.getUser("123");
    System.out.println(user);
} catch (APIError e) {
    System.err.println("API error: " + e.getMessage());
    System.err.println("Status code: " + e.getStatus());
    System.err.println("Response: " + e.getResponse());
} catch (Exception e) {
    System.err.println("Unexpected error: " + e.getMessage());
}
```

To handle specific error codes, do the following:

```java
try {
    sdk.usersService.deleteUser("123");
} catch (APIError e) {
    switch (e.getStatus()) {
        case 404:
            System.out.println("User not found");
            break;
        case 403:
            System.out.println("Permission denied");
            break;
        default:
            System.out.println("API error: " + e.getMessage());
    }
}
```

When the API specification defines error response models, the SDK generates typed exception classes (for example, `NotFoundErrorException`) that extend `APIError` and include the deserialized error model. The exception's `getMessage()` and `getStatus()` work directly, but to access specification-defined error fields, use `getError()`.

```java
import com.example.sdk.models.NotFoundErrorException;

try {
    sdk.usersService.getUser("123");
} catch (NotFoundErrorException e) {
    // message and status available directly from APIError
    System.out.println("Status: " + e.getStatus());
    System.out.println("Message: " + e.getMessage());

    // spec-defined error model fields require getError()
    NotFoundError error = e.getError();
    System.out.println("Detail: " + error.getDetail());
    System.out.println("Request ID: " + error.getRequestId());
} catch (APIError e) {
    // fallback for unmapped error responses
    System.out.println("API error: " + e.getStatus() + " " + e.getMessage());
}
```

### Timeouts and retries

To set a global timeout, do the following:

```java
SdkConfig config = SdkConfig.builder()
    .timeout(10000) // 10 seconds in milliseconds (default: 10000)
    .build();

Sdk sdk = new Sdk(config);
```

To pass the retry configuration through `SdkConfig`, do the following:

```java
RetryConfig retryConfig = RetryConfig.builder()
    .maxRetries(3)
    .initialDelay(150)       // milliseconds between retries (default: 150)
    .maxDelay(5000)          // max delay cap in milliseconds (default: 5000)
    .backoffFactor(2.0)      // exponential backoff multiplier
    .jitter(50)              // random jitter in milliseconds (default: 50)
    .build();

SdkConfig config = SdkConfig.builder()
    .retryConfig(retryConfig)
    .build();

Sdk sdk = new Sdk(config);
```

### Validation

The SDK generates validators that enforce OpenAPI constraints at runtime. These include `minLength`, `maxLength`, `pattern`, `min`, `max`, `uniqueItems`, and more.

Validation happens automatically when making API calls. The SDK validates parameters before sending the request. If validation fails, a `ValidationException` is thrown with a list of `Violation` objects describing what went wrong. You don't need to call validators manually. They're built into the service methods.

```java
import com.example.sdk.validation.exceptions.ValidationException;

try {
    // If the spec defines constraints (e.g. minLength: 3 for username),
    // the SDK validates before sending the request
    sdk.usersService.createUser(user);
} catch (ValidationException e) {
    // getMessage() returns a formatted summary of all violations
    System.err.println(e.getMessage());
    // Output: "Validation failed with the following violations:
    //          username: must be at least 3 characters long
    //          age: must be greater than or equal to 0"

    // Access individual violations for programmatic handling
    for (Violation violation : e.getViolations()) {
        System.err.println(violation.getPath() + ": " + violation.getMessage());
    }
} catch (APIError e) {
    System.err.println("API error: " + e.getMessage());
}
```

The list of supported constraints can also be grouped by type like this:

* String - `minLength`, `maxLength`, `pattern` (regex)
* Numeric - `min`, `max` (inclusive or exclusive)
* List/array - `minItems`, `maxItems`, `uniqueItems`
* Required fields - Validated automatically, based on the specification.

### Optional and nullable field handling

The SDK uses `JsonNullable<T>` wrappers for optional fields, providing clear distinction between undefined, null, and present values. This is important for users building request models. Omitting an optional field versus explicitly setting it to null produces different JSON payloads.

```java

// Example 1: Creating an object with all field types
ModelWithOptionalNullableDefaultValues model =
    ModelWithOptionalNullableDefaultValues.builder()
        .requiredString("requiredString")           // Required Non-Nullable
        .requiredInteger(8L)                        // Required Non-Nullable
        .requiredNullableString("not null")         // Required Nullable
        .requiredNullableInteger(null)              // Required Nullable (can be null)
        .optionalString("optionalString")           // Optional Non-Nullable
        .optionalInteger(9L)                        // Optional Non-Nullable
        .optionalNullableString("optional")         // Optional Nullable
        .optionalNullableInteger(null)              // Optional Nullable (can be null)
        .build();

// Example 2: Optional fields omitted entirely
ModelWithOptionalNullableDefaultValues minimalModel =
    ModelWithOptionalNullableDefaultValues.builder()
        .requiredString("requiredString")
        .requiredInteger(8L)
        .requiredNullableString(null)               // Still required, but can be null
        .requiredNullableInteger(null)              // Still required, but can be null
        // Optional fields omitted - they will be omitted from JSON when serialized and sent to API
        .build();

// Example 3: Optional fields with mixed values
ModelWithOptionalNullableDefaultValues mixedModel =
    ModelWithOptionalNullableDefaultValues.builder()
        .requiredString("requiredString")
        .requiredInteger(8L)
        .requiredNullableString("not null")
        .requiredNullableInteger(null)
        .optionalString("present")                  // Optional non-nullable with value
        .optionalNullableString(null)               // Optional nullable set to null
        // optionalInteger and optionalNullableInteger omitted
        .build();

// What the server receives for Example 1 (all fields set):
// {
//   "requiredString": "requiredString",
//   "requiredInteger": 8,
//   "requiredNullableString": "not null",
//   "requiredNullableInteger": null,
//   "optionalString": "optionalString",
//   "optionalInteger": 9,
//   "optionalNullableString": "optional",
//   "optionalNullableInteger": null
// }

// What the server receives for Example 2 (minimal model):
// {
//   "requiredString": "requiredString",
//   "requiredInteger": 8,
//   "requiredNullableString": null,
//   "requiredNullableInteger": null
//   // Note: optional fields are completely omitted from JSON
// }

// What the server receives for Example 3 (mixed model):
// {
//   "requiredString": "requiredString",
//   "requiredInteger": 8,
//   "requiredNullableString": "not null",
//   "requiredNullableInteger": null,
//   "optionalString": "present",
//   "optionalNullableString": null
//   // Note: optionalInteger and optionalNullableInteger are omitted
// }
```

## Additional resources

Consider the following resources for using and customizing your Java SDK:

* SDK documentation — Check the `documentation/` directory in your SDK.
* Javadoc — Generate with `mvn javadoc:javadoc`.
* Example usage — Refer to the `examples/` directory for a working code sample demonstrating basic SDK usage.
* Dependencies — The SDK uses the following dependencies:
  * OkHttp: An HTTP client.
  * Jackson: JSON serialization and `jackson-databind-nullable`, a dependency used for optional nullable field handling.
  * Lombok: Reduce boilerplate code.