Speakeasy Logo
Skip to Content

Java SDK Async Migration Guide

Prerequisites

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

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:

speakeasy run --skip-compile

This generates the async hooks and adapters necessary for Step 2. We skip compilation because the SDKHooks file is not touched by the generator, and async SDK initialization requires an additional method that needs to be added 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:

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)); } }

When to use this option:

  • Quick migration with minimal code changes
  • CPU-bound hooks
  • Low to moderate 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); } }

When to use this option:

  • High-throughput applications
  • I/O-bound operations (HTTP calls, database queries, etc.)
  • Maximum performance requirements

Step 4: Compile the SDK

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

Then test your application to ensure 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 async behavior meets your expectations
  • Monitor performance to validate that async support provides the expected benefits
  • Use appropriate async APIs in Option B implementations (async HTTP clients, reactive database drivers, etc.)

Troubleshooting

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

Last updated on