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.
Prerequisites
To follow this guide, you need:
- The Speakeasy CLI version
1.606.9or higher - Java 11 or higher
- An existing Java SDK generated by Speakeasy
- Access to your
.speakeasy/gen.yamlconfiguration file
Step 1: Enable async support in configuration
Enable the following flag in your .speakeasy/gen.yaml:
java:
asyncMode: enabledThen regenerate your SDK with compilation skipped:
speakeasy run --skip-compileThis 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
The async feature introduces new hook interfaces that work with CompletableFuture. You’ll need to add a new initialization method to your SDKHooks class.
Locate your SDKHooks file
Open ./src/main/java/<package>/hooks/SDKHooks.java in your Java SDK project.
Add the async initialize method
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)
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
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.
Option B: Full async implementation
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
Step 4: Compile the SDK
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.
Available async hook interfaces
The async support provides three hook interfaces that mirror the synchronous ones:
AsyncHook.BeforeRequest
import java.util.concurrent.CompletableFuture;
CompletableFuture<HttpRequest> beforeRequest(
Hook.BeforeRequestContext context,
HttpRequest request
);AsyncHook.AfterSuccess
import java.util.concurrent.CompletableFuture;
CompletableFuture<HttpResponse<Blob>> afterSuccess(
Hook.AfterSuccessContext context,
HttpResponse<Blob> response
);AsyncHook.AfterError
import java.util.concurrent.CompletableFuture;
CompletableFuture<HttpResponse<Blob>> afterError(
Hook.AfterErrorContext context,
HttpResponse<Blob> response,
Throwable error
);Best practices
- 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).
Troubleshooting
If you encounter these issues, refer to the troubleshooting instructions below:
Missing async initialize method
Ensure you’ve added the initialize(AsyncHooks hooks) method to your SDKHooks class.
Performance issues with HookAdapters
Consider migrating to Option B for I/O-bound hooks in high-throughput scenarios.
Next steps
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.
Last updated on