Skip to content
64 changes: 64 additions & 0 deletions src/main/java/com/stripe/StripeClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.stripe.net.Webhook.Signature;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import lombok.Builder;
import lombok.Getter;

/**
Expand Down Expand Up @@ -41,6 +42,62 @@ protected StripeResponseGetter getResponseGetter() {
return responseGetter;
}

/** Gets the current StripeContext from the client's configuration. Used in unit testing. */
protected String getContext() {
// TODO(major): add getOptions to the StripeResponseGetter interface? that would simplify this
if (!(responseGetter instanceof LiveStripeResponseGetter)) {
return null;
}

LiveStripeResponseGetter liveGetter = (LiveStripeResponseGetter) responseGetter;
StripeResponseGetterOptions options = liveGetter.getOptions();

return options.getStripeContext();
}

/**
* Creates a new StripeClient with the same configuration as this client but with a custom
* StripeContext. This method is useful for creating thread-safe clients with different contexts,
* such as when processing webhooks in parallel where each webhook has its own context.
*
* <p>The new client will share the same configuration (API key, timeouts, proxy settings, etc.)
* and HTTP client as this client, but will have the specified context. This allows for efficient
* parallel processing without reinitializing HTTP connections.
*
* @param context the custom stripe_context to use for the new client
* @return a new StripeClient with the custom context
* @throws IllegalStateException if this client doesn't use a LiveStripeResponseGetter
*/
public StripeClient withStripeContext(StripeContext context) {
// Convert StripeContext to String
String contextString = (context == null) ? null : context.toString();

StripeResponseGetter responseGetter = this.getResponseGetter();

// We can only create a new client for LiveStripeResponseGetter because it's the only class with
// `getOptions()`. If we add that method to the interface in a later major, we could remove this
// check.
if (!(responseGetter instanceof LiveStripeResponseGetter)) {
throw new IllegalStateException(
"Cannot create a client with custom context for non-Live response getters");
}

LiveStripeResponseGetter liveGetter = (LiveStripeResponseGetter) responseGetter;

// Create a new LiveStripeResponseGetter with updated context, reusing the HTTP client
LiveStripeResponseGetter newResponseGetter =
liveGetter.withNewOptions(
options -> {
ClientStripeResponseGetterOptions existingOptions =
(ClientStripeResponseGetterOptions) options;

return existingOptions.toBuilder().stripeContext(contextString).build();
});

// Create and return a new StripeClient with the new response getter
return new StripeClient(newResponseGetter);
}

/**
* Returns an StripeEvent instance using the provided JSON payload. Throws a JsonSyntaxException
* if the payload is not valid JSON, and a SignatureVerificationException if the signature
Expand Down Expand Up @@ -1033,6 +1090,8 @@ public com.stripe.service.WebhookEndpointService webhookEndpoints() {
}

// The end of the section generated from our OpenAPI spec
@SuppressWarnings("ObjectToString")
@Builder(toBuilder = true)
static class ClientStripeResponseGetterOptions extends StripeResponseGetterOptions {
// When adding setting here keep them in sync with settings in RequestOptions and
// in the RequestOptions.merge method
Expand Down Expand Up @@ -1412,4 +1471,9 @@ public StripeResponse rawRequest(
public StripeObject deserialize(String rawJson, ApiMode apiMode) throws StripeException {
return StripeObject.deserializeStripeObject(rawJson, this.getResponseGetter(), apiMode);
}

public StripeEventNotificationHandler notificationHandler(
String webhookSecret, StripeEventNotificationHandler.FallbackCallback fallbackCallback) {
return new StripeEventNotificationHandler(webhookSecret, this, fallbackCallback);
}
}
4 changes: 2 additions & 2 deletions src/main/java/com/stripe/StripeContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public StripeContext pop() {
/**
* Converts the context to a string by joining segments with '/'.
*
* @return string representation of the context segments joined by '/', `null` if there are no
* segments (useful for clearing context)
* @return string representation of the context segments joined by '/'. If there are no segments,
* returns an empty string (useful for clearing context).
*/
@Override
public String toString() {
Expand Down
Loading