Skip to content
Platform Status

Java SDK Async Migration Guide

Who is this guide for?

The migration steps detailed below are only necessary for Java SDKs generated before version 1.606.9 that are opting into async support.

To follow this guide, you need:

  • The Speakeasy CLI version 1.606.9 or higher
  • Java 11 or higher
  • An existing Java SDK generated by Speakeasy
  • Access to your .speakeasy/gen.yaml configuration file

Step 1: Enable async support in configuration

Section titled “Step 1: Enable async support in configuration”

Enable the following flag in your .speakeasy/gen.yaml:

java:
asyncMode: enabled

Then regenerate your SDK with compilation skipped:

Terminal window
speakeasy run --skip-compile

This generates the async hooks and adapters necessary for Step 2. We skip compilation because the generator doesn’t touch the SDKHooks file, and async SDK initialization requires an additional method that we need to add manually to that file.

Step 2: Add async hook registration method

Section titled “Step 2: Add async hook registration method”

The async feature introduces new hook interfaces that work with CompletableFuture. You’ll need to add a new initialization method to your SDKHooks class.

Open ./src/main/java/<package>/hooks/SDKHooks.java in your Java SDK project.

Add this method to your SDKHooks class (org.openapis.openapi is a placeholder for your package):

// replace org.openapis.openapi with your actual package
public static void initialize(org.openapis.openapi.utils.AsyncHooks hooks) {
// register async hooks here
}

Your SDKHooks class should now look like this:

package org.openapis.openapi.hooks;
public final class SDKHooks {
public static void initialize(org.openapis.openapi.utils.Hooks hooks) {
// register synchronous hooks here
}
public static void initialize(org.openapis.openapi.utils.AsyncHooks hooks) {
// register async hooks here
}
}

Step 3: Migrate existing hooks (if applicable)

Section titled “Step 3: Migrate existing hooks (if applicable)”

If you don’t have existing hooks, skip to Step 4. If you do have hooks, choose one of the following migration options:

Hook Parity

Ensure hook parity across sync and async variants. Hooks are not automatically applied across both - you need to register them separately for each variant.

Option A: Quick migration with HookAdapters

Section titled “Option A: Quick migration with HookAdapters”

Use HookAdapters to automatically convert your existing synchronous hooks to async:

package org.openapis.openapi.hooks;
import org.openapis.openapi.utils.Hook;
import org.openapis.openapi.utils.HookAdapters;
import java.util.concurrent.CompletableFuture;
public final class SDKHooks {
// Your existing hook
static Hook.BeforeRequest AUTH_AND_TRACING_HOOK = new AuthAndTracingBeforeRequest(
myTokenProvider
);
public static void initialize(org.openapis.openapi.utils.Hooks hooks) {
// Keep existing synchronous hook registration
hooks.registerBeforeRequest(AUTH_AND_TRACING_HOOK);
}
public static void initialize(org.openapis.openapi.utils.AsyncHooks hooks) {
// Convert synchronous hook to async using adapter
hooks.registerBeforeRequest(HookAdapters.toAsync(AUTH_AND_TRACING_HOOK));
}
}

Use this option for:

  • A quick migration with minimal code changes
  • CPU-bound hooks
  • Low-to-moderate throughput applications

Performance Consideration

HookAdapters uses the global ForkJoinPool, which may become a bottleneck for I/O-bound hooks in high-throughput applications.

Reimplement your hooks using async APIs and non-blocking operations:

package org.openapis.openapi.hooks;
import org.openapis.openapi.utils.AsyncHook;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Logger;
public final class SDKHooks {
private static final Logger logger = Logger.getLogger(SDKHooks.class.getName());
// Async version of your hook with error handling
static AsyncHook.BeforeRequest ASYNC_AUTH_HOOK = (context, request) -> {
return authService.getTokenAsync() // Use async API
.thenApply(token -> request.toBuilder()
.addHeader("Authorization", "Bearer " + token)
.build())
.exceptionally(throwable -> {
// Handle auth failures gracefully
logger.warning("Auth token retrieval failed: " + throwable.getMessage());
return request; // Return original request
});
};
public static void initialize(org.openapis.openapi.utils.Hooks hooks) {
// Keep existing synchronous hooks if needed
}
public static void initialize(org.openapis.openapi.utils.AsyncHooks hooks) {
// Register native async hooks
hooks.registerBeforeRequest(ASYNC_AUTH_HOOK);
}
}

Use this option for:

  • High-throughput applications
  • I/O-bound operations (such as HTTP calls and database queries)
  • Meeting maximum performance requirements

After making the configuration and code changes, run the following command again to compile and verify that the changes are correct:

speakeasy run

🚀 Ready to Generate?

Run speakeasy run to compile your SDK with async support!

Then test your application to ensure the async functionality works as expected.

The async support provides three hook interfaces that mirror the synchronous ones:

import java.util.concurrent.CompletableFuture;
CompletableFuture<HttpRequest> beforeRequest(
Hook.BeforeRequestContext context,
HttpRequest request
);
import java.util.concurrent.CompletableFuture;
CompletableFuture<HttpResponse<Blob>> afterSuccess(
Hook.AfterSuccessContext context,
HttpResponse<Blob> response
);
import java.util.concurrent.CompletableFuture;
CompletableFuture<HttpResponse<Blob>> afterError(
Hook.AfterErrorContext context,
HttpResponse<Blob> response,
Throwable error
);
  • Choose the right migration option based on your application’s throughput requirements and hook complexity.
  • Test thoroughly after migration to ensure the async behavior meets your expectations.
  • Monitor performance to validate that async support provides the expected benefits.
  • Use appropriate async APIs in Option B implementations (such as async HTTP clients and reactive database drivers).

If you encounter these issues, refer to the troubleshooting instructions below:

Ensure you’ve added the initialize(AsyncHooks hooks) method to your SDKHooks class.

Consider migrating to Option B for I/O-bound hooks in high-throughput scenarios.

After a successful migration, your Java SDK will support both synchronous and asynchronous operations, allowing you to leverage non-blocking I/O for improved performance in concurrent applications.

Related Documentation

For more information on Java SDK configuration and features, check out the Java SDK documentation.