# Java SDK Async Migration Guide

<Callout type="info" title="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.
</Callout>

## Prerequisites

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

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

```yaml
java:
  asyncMode: enabled
```

Then regenerate your SDK with compilation skipped:

```bash
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

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):

```java
// 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:

```java
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:

<Callout type="warning" title="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.
</Callout>

### Option A: Quick migration with HookAdapters

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

```java
package org.openapis.openapi.hooks;

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

<Callout type="warning" title="Performance Consideration">
  HookAdapters uses the global ForkJoinPool, which may become a bottleneck for I/O-bound hooks in high-throughput applications.
</Callout>

### Option B: Full async implementation

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

```java
package org.openapis.openapi.hooks;

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

<Callout type="success" title="🚀 Ready to Generate?">
  Run `speakeasy run` to compile your SDK with async support!
</Callout>

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

```java

CompletableFuture<HttpRequest> beforeRequest(
    Hook.BeforeRequestContext context,
    HttpRequest request
);
```

### AsyncHook.AfterSuccess

```java

CompletableFuture<HttpResponse<Blob>> afterSuccess(
    Hook.AfterSuccessContext context,
    HttpResponse<Blob> response
);
```

### AsyncHook.AfterError

```java

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.

<Callout title="Related Documentation">
  For more information on Java SDK configuration and features, check out the [Java SDK documentation](/docs/languages/java/methodology-java).
</Callout>
