Use Java SDKs generated in Postman

View as Markdown

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:

your-sdk
README.md
pom.xml
.gitignore
LICENSE
.env.example
.devcontainer
.idea
src
examples
documentation

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

examples/src/main/java/Main.java

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.

    $cd path/to/your-sdk
    $mvn clean install
  2. Add dependency to your project’s pom.xml.

    1<dependency>
    2 <groupId>com.example</groupId>
    3 <artifactId>your-sdk</artifactId>
    4 <version>1.0.0</version>
    5</dependency>
  3. Use the SDK in your code.

1import com.example.sdk.Sdk;
2import com.example.sdk.config.SdkConfig;
3
4SdkConfig config = SdkConfig.builder().build();
5Sdk 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.

    1<modules>
    2 <module>../path/to/your-sdk</module>
    3 <module>your-app</module>
    4</modules>
  2. Reference as dependency.

    1<dependency>
    2 <groupId>com.example</groupId>
    3 <artifactId>your-sdk</artifactId>
    4 <version>${project.version}</version>
    5</dependency>

Import using Gradle

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

$cd path/to/your-sdk
$mvn clean install

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

1dependencies {
2 implementation group: 'com.example', name: 'your-sdk', version: '1.0.0'
3}

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

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

Then, add the JAR to your build.gradle:

1dependencies {
2 implementation files('../path/to/your-sdk/target/your-sdk-1.0.0-jar-with-dependencies.jar')
3}

Publish to Maven Central

To share your generated Java SDK with the community, you can publish it to Maven Central. This allows other developers to easily add it as a dependency in their Maven or Gradle projects. Follow the steps below to publish your SDK to Maven Central.

Prerequisites

To publish your SDK to Maven Central, you need the following:

  • Sonatype Central Portal account (central.sonatype.com)
  • GPG key for signing artifacts
  • Namespace (group ID) verified on the Central Portal

Initial setup

To set up your environment for publishing to Maven Central, do the following:

  1. Create account and verify your namespace:

    • Register at central.sonatype.com.
    • Verify your namespace (group ID, for example, com.example) through DNS or GitHub verification.
    • Verification is typically automated and completes within minutes.
  2. Generate a GPG key.

    $gpg --gen-key
    $gpg --list-keys
    $gpg --keyserver keys.openpgp.org --send-keys YOUR_KEY_ID
  3. Configure Maven settings.xml. Add the following to ~/.m2/settings.xml:

    1<settings>
    2<servers>
    3 <server>
    4 <id>central</id>
    5 <username>your-central-portal-token-username</username>
    6 <password>your-central-portal-token-password</password>
    7 </server>
    8</servers>
    9<profiles>
    10 <profile>
    11 <id>central</id>
    12 <activation>
    13 <activeByDefault>true</activeByDefault>
    14 </activation>
    15 <properties>
    16 <gpg.executable>gpg</gpg.executable>
    17 <gpg.passphrase>your-gpg-passphrase</gpg.passphrase>
    18 </properties>
    19 </profile>
    20</profiles>
    21</settings>

Configure pom.xml

Add the following to your SDK’s pom.xml:

1<project>
2 <!-- Basic information -->
3 <groupId>com.example</groupId>
4 <artifactId>your-sdk</artifactId>
5 <version>1.0.0</version>
6 <packaging>jar</packaging>
7
8 <name>Your SDK</name>
9 <description>SDK for Your API</description>
10 <url>https://github.com/your-org/your-sdk</url>
11
12 <!-- License -->
13 <licenses>
14 <license>
15 <name>MIT License</name>
16 <url>https://opensource.org/licenses/MIT</url>
17 </license>
18 </licenses>
19
20 <!-- Developers -->
21 <developers>
22 <developer>
23 <name>Your Name</name>
24 <email>your@email.com</email>
25 <organization>Your Organization</organization>
26 </developer>
27 </developers>
28
29 <!-- SCM -->
30 <scm>
31 <connection>scm:git:git://github.com/your-org/your-sdk.git</connection>
32 <developerConnection>scm:git:ssh://github.com/your-org/your-sdk.git</developerConnection>
33 <url>https://github.com/your-org/your-sdk</url>
34 </scm>
35
36 <build>
37 <plugins>
38 <!-- Maven Source Plugin -->
39 <plugin>
40 <groupId>org.apache.maven.plugins</groupId>
41 <artifactId>maven-source-plugin</artifactId>
42 <version>3.3.1</version>
43 <executions>
44 <execution>
45 <id>attach-sources</id>
46 <goals>
47 <goal>jar-no-fork</goal>
48 </goals>
49 </execution>
50 </executions>
51 </plugin>
52
53 <!-- Maven Javadoc Plugin -->
54 <plugin>
55 <groupId>org.apache.maven.plugins</groupId>
56 <artifactId>maven-javadoc-plugin</artifactId>
57 <version>3.6.3</version>
58 <executions>
59 <execution>
60 <id>attach-javadocs</id>
61 <goals>
62 <goal>jar</goal>
63 </goals>
64 </execution>
65 </executions>
66 </plugin>
67
68 <!-- Maven GPG Plugin -->
69 <plugin>
70 <groupId>org.apache.maven.plugins</groupId>
71 <artifactId>maven-gpg-plugin</artifactId>
72 <version>3.2.7</version>
73 <executions>
74 <execution>
75 <id>sign-artifacts</id>
76 <phase>verify</phase>
77 <goals>
78 <goal>sign</goal>
79 </goals>
80 </execution>
81 </executions>
82 </plugin>
83
84 <!-- Central Publishing Maven Plugin -->
85 <plugin>
86 <groupId>org.sonatype.central</groupId>
87 <artifactId>central-publishing-maven-plugin</artifactId>
88 <version>0.6.0</version>
89 <extensions>true</extensions>
90 <configuration>
91 <publishingServerId>central</publishingServerId>
92 <autoPublish>true</autoPublish>
93 </configuration>
94 </plugin>
95 </plugins>
96 </build>
97</project>

Publish your Java SDK to Maven Central

  1. Deploy to Maven Central.

    $mvn clean deploy

    With autoPublish set to true, artifacts are automatically published after validation. If set to false, you can manually publish from the Central Portal UI at central.sonatype.com.

  2. Verify the publication. After deployment, verify that your artifacts are available in the staging repository on the Central Portal, for example, https://repo1.maven.org/maven2/com/example/your-sdk/. Once verified, they’re released to Maven Central within 30 minutes.

Publish updates

To publish updates to your SDK, do the following:

$# Update version in pom.xml
$mvn versions:set -DnewVersion=1.0.1
$mvn versions:commit
$
$# Deploy
$mvn clean deploy

Best practices for publishing Java SDKs

Use the following best practices when publishing your Java SDK to Maven Central:

  • Use semantic versioning.
  • Sign all artifacts with GPG.
  • Include source and javadoc JARs.
  • Provide comprehensive documentation.
  • Tag releases in Git.
  • Consider using the Maven Release Plugin for automated releases.

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.

1SdkConfig config = SdkConfig.builder()
2 .apiKeyAuthConfig(
3 ApiKeyAuthConfig.builder()
4 .apiKey("your-api-key")
5 .build()
6 )
7 .build();
8
9Sdk sdk = new Sdk(config);

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.

1sdk.setApiKey("new-api-key");
2sdk.setAccessToken("new-token");
3sdk.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>.

1import java.util.concurrent.CompletableFuture;
2
3// Synchronous — blocks until the response is returned
4Pet pet = sdk.petService.getPetById(123);
5System.out.println("Pet: " + pet.getName());
6
7// Asynchronous — returns a CompletableFuture
8CompletableFuture<Pet> futurePet = sdk.petService.getPetByIdAsync(123);
9
10// Option 1: Non-blocking with callbacks
11futurePet
12 .thenAccept(p -> System.out.println("Pet: " + p.getName()))
13 .exceptionally(e -> {
14 System.err.println("Error: " + e.getMessage());
15 return null;
16 });
17
18// Option 2: Blocking wait when needed
19Pet pet = futurePet.get();

Environment management

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

1// Use environment enum
2sdk.setEnvironment(Environment.PRODUCTION);
3
4// Or set custom base URL
5sdk.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.

1import com.example.sdk.Sdk;
2import com.example.sdk.config.SdkConfig;
3import com.example.sdk.config.RequestConfig;
4import com.example.sdk.http.Environment;
5
6// 1. SDK level — default for everything
7SdkConfig config = SdkConfig.builder()
8 .baseUrl("https://api.example.com")
9 .timeout(10000)
10 .build();
11
12Sdk sdk = new Sdk(config);
13
14// 2. Service level — override for all methods in usersService
15sdk.usersService.setConfig(
16 RequestConfig.builder()
17 .timeout(15000L)
18 .build()
19);
20
21// 3. Method level — override for getUser only
22sdk.usersService.setGetUserConfig(
23 RequestConfig.builder()
24 .baseUrl("https://legacy-api.example.com")
25 .build()
26);
27
28// 4. Request level — override for this single call
29User user = sdk.usersService.getUser("123",
30 RequestConfig.builder()
31 .timeout(30000L)
32 .build()
33);

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:

1import com.example.sdk.exceptions.ApiError;
2
3try {
4 User user = sdk.usersService.getUser("123");
5 System.out.println(user);
6} catch (ApiError e) {
7 System.err.println("API error: " + e.getMessage());
8 System.err.println("Status code: " + e.getStatus());
9 System.err.println("Response: " + e.getResponse());
10} catch (Exception e) {
11 System.err.println("Unexpected error: " + e.getMessage());
12}

To handle specific error codes, do the following:

1try {
2 sdk.usersService.deleteUser("123");
3} catch (ApiError e) {
4 switch (e.getStatus()) {
5 case 404:
6 System.out.println("User not found");
7 break;
8 case 403:
9 System.out.println("Permission denied");
10 break;
11 default:
12 System.out.println("API error: " + e.getMessage());
13 }
14}

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().

1import com.example.sdk.models.NotFoundErrorException;
2
3try {
4 sdk.usersService.getUser("123");
5} catch (NotFoundErrorException e) {
6 // message and status available directly from ApiError
7 System.out.println("Status: " + e.getStatus());
8 System.out.println("Message: " + e.getMessage());
9
10 // spec-defined error model fields require getError()
11 NotFoundError error = e.getError();
12 System.out.println("Detail: " + error.getDetail());
13 System.out.println("Request ID: " + error.getRequestId());
14} catch (ApiError e) {
15 // fallback for unmapped error responses
16 System.out.println("API error: " + e.getStatus() + " " + e.getMessage());
17}

Timeouts and retries

To set a global timeout, do the following:

1SdkConfig config = SdkConfig.builder()
2 .timeout(10000) // 10 seconds in milliseconds (default: 10000)
3 .build();
4
5Sdk sdk = new Sdk(config);

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

1RetryConfig retryConfig = RetryConfig.builder()
2 .maxRetries(3)
3 .initialDelay(150) // milliseconds between retries (default: 150)
4 .maxDelay(5000) // max delay cap in milliseconds (default: 5000)
5 .backoffFactor(2.0) // exponential backoff multiplier
6 .jitter(50) // random jitter in milliseconds (default: 50)
7 .build();
8
9SdkConfig config = SdkConfig.builder()
10 .retryConfig(retryConfig)
11 .build();
12
13Sdk 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.

1import com.example.sdk.validation.exceptions.ValidationException;
2
3try {
4 // If the spec defines constraints (e.g. minLength: 3 for username),
5 // the SDK validates before sending the request
6 sdk.usersService.createUser(user);
7} catch (ValidationException e) {
8 // getMessage() returns a formatted summary of all violations
9 System.err.println(e.getMessage());
10 // Output: "Validation failed with the following violations:
11 // username: must be at least 3 characters long
12 // age: must be greater than or equal to 0"
13
14 // Access individual violations for programmatic handling
15 for (Violation violation : e.getViolations()) {
16 System.err.println(violation.getPath() + ": " + violation.getMessage());
17 }
18} catch (ApiError e) {
19 System.err.println("API error: " + e.getMessage());
20}

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.

1// Example 1: Creating an object with all field types
2ModelWithOptionalNullableDefaultValues model =
3 ModelWithOptionalNullableDefaultValues.builder()
4 .requiredString("requiredString") // Required Non-Nullable
5 .requiredInteger(8L) // Required Non-Nullable
6 .requiredNullableString("not null") // Required Nullable
7 .requiredNullableInteger(null) // Required Nullable (can be null)
8 .optionalString("optionalString") // Optional Non-Nullable
9 .optionalInteger(9L) // Optional Non-Nullable
10 .optionalNullableString("optional") // Optional Nullable
11 .optionalNullableInteger(null) // Optional Nullable (can be null)
12 .build();
13
14// Example 2: Optional fields omitted entirely
15ModelWithOptionalNullableDefaultValues minimalModel =
16 ModelWithOptionalNullableDefaultValues.builder()
17 .requiredString("requiredString")
18 .requiredInteger(8L)
19 .requiredNullableString(null) // Still required, but can be null
20 .requiredNullableInteger(null) // Still required, but can be null
21 // Optional fields omitted - they will be omitted from JSON when serialized and sent to API
22 .build();
23
24// Example 3: Optional fields with mixed values
25ModelWithOptionalNullableDefaultValues mixedModel =
26 ModelWithOptionalNullableDefaultValues.builder()
27 .requiredString("requiredString")
28 .requiredInteger(8L)
29 .requiredNullableString("not null")
30 .requiredNullableInteger(null)
31 .optionalString("present") // Optional non-nullable with value
32 .optionalNullableString(null) // Optional nullable set to null
33 // optionalInteger and optionalNullableInteger omitted
34 .build();
35
36// What the server receives for Example 1 (all fields set):
37// {
38// "requiredString": "requiredString",
39// "requiredInteger": 8,
40// "requiredNullableString": "not null",
41// "requiredNullableInteger": null,
42// "optionalString": "optionalString",
43// "optionalInteger": 9,
44// "optionalNullableString": "optional",
45// "optionalNullableInteger": null
46// }
47
48// What the server receives for Example 2 (minimal model):
49// {
50// "requiredString": "requiredString",
51// "requiredInteger": 8,
52// "requiredNullableString": null,
53// "requiredNullableInteger": null
54// // Note: optional fields are completely omitted from JSON
55// }
56
57// What the server receives for Example 3 (mixed model):
58// {
59// "requiredString": "requiredString",
60// "requiredInteger": 8,
61// "requiredNullableString": "not null",
62// "requiredNullableInteger": null,
63// "optionalString": "present",
64// "optionalNullableString": null
65// // Note: optionalInteger and optionalNullableInteger are omitted
66// }

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: HTTP client
    • Jackson: JSON serialization and jackson-databind-nullable, a dependency used for optional nullable field handling
    • Lombok: Reduce boilerplate code