diff --git a/src/main/java/com/stripe/StripeClient.java b/src/main/java/com/stripe/StripeClient.java
index d5f2fb79f22..b5bc7665771 100644
--- a/src/main/java/com/stripe/StripeClient.java
+++ b/src/main/java/com/stripe/StripeClient.java
@@ -1223,6 +1223,11 @@ public StripeClientBuilder setStripeContext(String context) {
return this;
}
+ public StripeClientBuilder setStripeContext(StripeContext context) {
+ this.stripeContext = context == null ? null : context.toString();
+ return this;
+ }
+
public String getStripeContext() {
return this.stripeContext;
}
diff --git a/src/main/java/com/stripe/StripeContext.java b/src/main/java/com/stripe/StripeContext.java
new file mode 100644
index 00000000000..cd7b15b19e8
--- /dev/null
+++ b/src/main/java/com/stripe/StripeContext.java
@@ -0,0 +1,98 @@
+package com.stripe;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import lombok.EqualsAndHashCode;
+
+/**
+ * The StripeContext class provides an immutable container for interacting with the `Stripe-Context`
+ * header.
+ *
+ *
You can use it whenever you're initializing a `StripeClient` or sending `stripe_context` with
+ * a request. It's also found in the `EventNotification.context` property.
+ */
+@EqualsAndHashCode
+public final class StripeContext {
+ private final List segments;
+
+ /** Creates a new StripeContext with no segments. */
+ public StripeContext() {
+ this(null);
+ }
+
+ /**
+ * Creates a new StripeContext with the specified segments.
+ *
+ * @param segments the list of context segments
+ */
+ public StripeContext(List segments) {
+ this.segments =
+ segments == null
+ ? Collections.emptyList()
+ : Collections.unmodifiableList(new ArrayList<>(segments));
+ }
+
+ /**
+ * Returns a new StripeContext with the given segment added to the end.
+ *
+ * @param segment the segment to add
+ * @return a new StripeContext instance with the segment appended
+ */
+ public StripeContext push(String segment) {
+ List newSegments = new ArrayList<>(this.segments);
+ newSegments.add(segment);
+ return new StripeContext(newSegments);
+ }
+
+ /**
+ * Returns a new StripeContext with the last segment removed.
+ *
+ * @return a new StripeContext instance with the last segment removed
+ */
+ public StripeContext pop() {
+ if (segments.isEmpty()) {
+ throw new IllegalStateException("Cannot pop from an empty StripeContext");
+ }
+
+ List newSegments = new ArrayList<>(this.segments);
+ newSegments.remove(newSegments.size() - 1);
+ return new StripeContext(newSegments);
+ }
+
+ /**
+ * 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)
+ */
+ @Override
+ public String toString() {
+ return String.join("/", segments);
+ }
+
+ /**
+ * Parse a context string into a StripeContext instance.
+ *
+ * @param contextStr string to parse (segments separated by '/')
+ * @return StripeContext instance with segments from the string
+ */
+ public static StripeContext parse(String contextStr) {
+ if (contextStr == null || contextStr.isEmpty()) {
+ return new StripeContext();
+ }
+
+ List segments = Arrays.asList(contextStr.split("/"));
+ return new StripeContext(segments);
+ }
+
+ /**
+ * Returns an unmodifiable list of the current segments.
+ *
+ * @return the list of segments
+ */
+ public List getSegments() {
+ return segments;
+ }
+}
diff --git a/src/main/java/com/stripe/model/StripeContextDeserializer.java b/src/main/java/com/stripe/model/StripeContextDeserializer.java
new file mode 100644
index 00000000000..3f9c21d5943
--- /dev/null
+++ b/src/main/java/com/stripe/model/StripeContextDeserializer.java
@@ -0,0 +1,26 @@
+package com.stripe.model;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.stripe.StripeContext;
+import java.lang.reflect.Type;
+
+public class StripeContextDeserializer implements JsonDeserializer {
+
+ @Override
+ public StripeContext deserialize(
+ JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException {
+ if (json == null || json.isJsonNull()) {
+ return null;
+ }
+
+ String contextString = json.getAsString().trim();
+ if (contextString.isEmpty()) {
+ return null;
+ }
+ return StripeContext.parse(contextString);
+ }
+}
diff --git a/src/main/java/com/stripe/model/v2/EventNotification.java b/src/main/java/com/stripe/model/v2/EventNotification.java
index 33866cf95e7..796a1ad0eb5 100644
--- a/src/main/java/com/stripe/model/v2/EventNotification.java
+++ b/src/main/java/com/stripe/model/v2/EventNotification.java
@@ -3,6 +3,7 @@
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;
import com.stripe.StripeClient;
+import com.stripe.StripeContext;
import com.stripe.exception.StripeException;
import com.stripe.model.StripeObject;
import com.stripe.model.v2.Event.RelatedObject;
@@ -71,7 +72,7 @@ public static class Reason {
/** [Optional] Authentication context needed to fetch the event or related object. */
@SerializedName("context")
- public String context;
+ public StripeContext context;
/** [Optional] Reason for the event. */
@SerializedName("reason")
@@ -98,6 +99,7 @@ public static EventNotification fromJson(String payload, StripeClient client) {
EventNotification e = ApiResource.GSON.fromJson(payload, cls);
e.client = client;
+
return e;
}
@@ -105,7 +107,9 @@ private RawRequestOptions getRequestOptions() {
if (context == null) {
return null;
}
- return new RawRequestOptions.RawRequestOptionsBuilder().setStripeContext(context).build();
+ return new RawRequestOptions.RawRequestOptionsBuilder()
+ .setStripeContext(context.toString())
+ .build();
}
/* retrieves the full payload for an event. Protected because individual push classes use it, but type it correctly */
diff --git a/src/main/java/com/stripe/net/ApiResource.java b/src/main/java/com/stripe/net/ApiResource.java
index 214803bcca7..d23ce045463 100644
--- a/src/main/java/com/stripe/net/ApiResource.java
+++ b/src/main/java/com/stripe/net/ApiResource.java
@@ -1,6 +1,7 @@
package com.stripe.net;
import com.google.gson.*;
+import com.stripe.StripeContext;
import com.stripe.exception.InvalidRequestException;
import com.stripe.model.*;
import com.stripe.model.v2.EventTypeAdapterFactory;
@@ -54,6 +55,7 @@ private static Gson createGson(boolean shouldSetResponseGetter) {
.registerTypeAdapter(EphemeralKey.class, new EphemeralKeyDeserializer())
.registerTypeAdapter(Event.Data.class, new EventDataDeserializer())
.registerTypeAdapter(Event.Request.class, new EventRequestDeserializer())
+ .registerTypeAdapter(StripeContext.class, new StripeContextDeserializer())
.registerTypeAdapter(ExpandableField.class, new ExpandableFieldDeserializer())
.registerTypeAdapter(Instant.class, new InstantDeserializer())
.registerTypeAdapterFactory(new EventTypeAdapterFactory())
diff --git a/src/main/java/com/stripe/net/RawRequestOptions.java b/src/main/java/com/stripe/net/RawRequestOptions.java
index abad1823552..ba0384c338e 100644
--- a/src/main/java/com/stripe/net/RawRequestOptions.java
+++ b/src/main/java/com/stripe/net/RawRequestOptions.java
@@ -1,5 +1,6 @@
package com.stripe.net;
+import com.stripe.StripeContext;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.util.Map;
@@ -81,6 +82,12 @@ public RawRequestOptionsBuilder setStripeContext(String stripeContext) {
return this;
}
+ @Override
+ public RawRequestOptionsBuilder setStripeContext(StripeContext stripeContext) {
+ super.setStripeContext(stripeContext);
+ return this;
+ }
+
@Override
public RawRequestOptionsBuilder setStripeAccount(String stripeAccount) {
super.setStripeAccount(stripeAccount);
diff --git a/src/main/java/com/stripe/net/RequestOptions.java b/src/main/java/com/stripe/net/RequestOptions.java
index db1e836db32..42c910777a2 100644
--- a/src/main/java/com/stripe/net/RequestOptions.java
+++ b/src/main/java/com/stripe/net/RequestOptions.java
@@ -235,6 +235,17 @@ public RequestOptionsBuilder setStripeContext(String context) {
return this;
}
+ public RequestOptionsBuilder setStripeContext(com.stripe.StripeContext context) {
+ this.stripeContext = context != null ? context.toString() : null;
+ return this;
+ }
+
+ /**
+ * Empties the current builder value for StripeContext, which will defer to the client options.
+ *
+ * To send no context at all, call `setContext(new StripeContext())`or set the context to an
+ * empty string.
+ */
public RequestOptionsBuilder clearStripeContext() {
this.stripeContext = null;
return this;
@@ -472,15 +483,28 @@ static RequestOptions merge(StripeResponseGetterOptions clientOptions, RequestOp
clientOptions.getProxyCredential() // proxyCredential
);
}
+
+ // callers need to be able to explicitly unset context per-request
+ // an empty StripeContext serializes to a "", so check for that and empty context out if it's
+ // there.
+ String stripeContext;
+ if (options.getStripeContext() != null) {
+ String requestContext = options.getStripeContext().trim();
+ if (requestContext.isEmpty()) {
+ stripeContext = null;
+ } else {
+ stripeContext = requestContext;
+ }
+ } else {
+ stripeContext = clientOptions.getStripeContext();
+ }
return new RequestOptions(
options.getAuthenticator() != null
? options.getAuthenticator()
: clientOptions.getAuthenticator(),
options.getClientId() != null ? options.getClientId() : clientOptions.getClientId(),
options.getIdempotencyKey(),
- options.getStripeContext() != null
- ? options.getStripeContext()
- : clientOptions.getStripeContext(),
+ stripeContext,
options.getStripeAccount() != null
? options.getStripeAccount()
: clientOptions.getStripeAccount(),
diff --git a/src/test/java/com/stripe/StripeClientTest.java b/src/test/java/com/stripe/StripeClientTest.java
index f8c18ce31a7..4a95f3eaec2 100644
--- a/src/test/java/com/stripe/StripeClientTest.java
+++ b/src/test/java/com/stripe/StripeClientTest.java
@@ -248,7 +248,7 @@ public void parsesEventNotificationWithRelatedObject()
assertEquals("evt_234", eventNotification.getId());
assertEquals("v1.billing.meter.error_report_triggered", eventNotification.getType());
assertEquals(Instant.parse("2022-02-15T00:27:45.330Z"), eventNotification.created);
- assertEquals("org_123", eventNotification.context);
+ assertEquals("org_123", eventNotification.getContext().toString());
assertInstanceOf(V1BillingMeterErrorReportTriggeredEventNotification.class, eventNotification);
assertEquals("request", eventNotification.getReason().getType());
assertEquals("abc123", eventNotification.getReason().getRequest().getId());
diff --git a/src/test/java/com/stripe/StripeContextIntegrationTest.java b/src/test/java/com/stripe/StripeContextIntegrationTest.java
new file mode 100644
index 00000000000..a6ed855e9a3
--- /dev/null
+++ b/src/test/java/com/stripe/StripeContextIntegrationTest.java
@@ -0,0 +1,156 @@
+package com.stripe;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.stripe.model.v2.EventNotification;
+import com.stripe.net.RawRequestOptions;
+import com.stripe.net.RequestOptions;
+import java.util.Arrays;
+import org.junit.jupiter.api.Test;
+
+public class StripeContextIntegrationTest {
+
+ @Test
+ public void testRequestOptionsWithStringContext() {
+ RequestOptions options = RequestOptions.builder().setStripeContext("a/b/c").build();
+
+ assertEquals("a/b/c", options.getStripeContext());
+ }
+
+ @Test
+ public void testRawRequestOptionsWithStringContext() {
+ RawRequestOptions options = RawRequestOptions.builder().setStripeContext("a/b/c").build();
+
+ assertEquals("a/b/c", options.getStripeContext());
+ }
+
+ @Test
+ public void testRequestOptionsWithContextObject() {
+ StripeContext context = new StripeContext(Arrays.asList("a", "b", "c"));
+ RequestOptions options = RequestOptions.builder().setStripeContext(context).build();
+
+ assertEquals("a/b/c", options.getStripeContext());
+ }
+
+ @Test
+ public void testRequestOptionsWithNullContext() {
+ RequestOptions options = RequestOptions.builder().setStripeContext(new StripeContext()).build();
+
+ assertEquals("", options.getStripeContext());
+ }
+
+ @Test
+ public void testStripeClientBuilderWithStringContext() {
+ StripeClient.StripeClientBuilder builder =
+ StripeClient.builder().setApiKey("sk_test_123").setStripeContext("a/b/c");
+
+ assertEquals("a/b/c", builder.getStripeContext());
+ }
+
+ @Test
+ public void testStripeClientBuilderWithContextObject() {
+ StripeContext context = new StripeContext(Arrays.asList("a", "b", "c"));
+ StripeClient.StripeClientBuilder builder =
+ StripeClient.builder().setApiKey("sk_test_123").setStripeContext(context);
+
+ assertEquals("a/b/c", builder.getStripeContext());
+ }
+
+ @Test
+ public void testStripeClientBuilderWithNullContext() {
+ StripeClient.StripeClientBuilder builder =
+ StripeClient.builder().setApiKey("sk_test_123").setStripeContext((StripeContext) null);
+
+ assertNull(builder.getStripeContext());
+ }
+
+ @Test
+ public void testStripeClientBuilderEmptyContextOverwrites() {
+ StripeClient.StripeClientBuilder builder =
+ StripeClient.builder()
+ .setApiKey("sk_test_123")
+ .setStripeContext("ctx_123")
+ .setStripeContext(new StripeContext());
+
+ assertEquals("", builder.getStripeContext());
+ }
+
+ @Test
+ public void testStripeClientBuilderWithEmptyContext() {
+ StripeClient.StripeClientBuilder builder =
+ StripeClient.builder().setApiKey("sk_test_123").setStripeContext(new StripeContext());
+
+ assertEquals("", builder.getStripeContext());
+ }
+
+ @Test
+ public void testEventNotificationParsing() {
+ String payload =
+ "{\"id\":\"evt_123\",\"type\":\"test.event\",\"created\":\"2023-01-01T00:00:00Z\",\"livemode\":false,\"context\":\"a/b/c\"}";
+ StripeClient client = new StripeClient("sk_test_123");
+
+ EventNotification notification = EventNotification.fromJson(payload, client);
+
+ assertNotNull(notification.context);
+ assertEquals(Arrays.asList("a", "b", "c"), notification.context.getSegments());
+ assertEquals("a/b/c", notification.context.toString());
+ }
+
+ @Test
+ public void testEventNotificationNoContext() {
+ String payload =
+ "{\"id\":\"evt_123\",\"type\":\"test.event\",\"created\":\"2023-01-01T00:00:00Z\",\"livemode\":false}";
+ StripeClient client = new StripeClient("sk_test_123");
+
+ EventNotification notification = EventNotification.fromJson(payload, client);
+
+ assertNull(notification.getContext());
+ }
+
+ @Test
+ public void testEventNotificationEmptyContext() {
+ String payload =
+ "{\"id\":\"evt_123\",\"type\":\"test.event\",\"created\":\"2023-01-01T00:00:00Z\",\"livemode\":false,\"context\":\"\"}";
+ StripeClient client = new StripeClient("sk_test_123");
+
+ EventNotification notification = EventNotification.fromJson(payload, client);
+
+ assertNull(notification.getContext());
+ }
+
+ @Test
+ public void testEventNotificationNullContext() {
+ String payload =
+ "{\"id\":\"evt_123\",\"type\":\"test.event\",\"created\":\"2023-01-01T00:00:00Z\",\"livemode\":false,\"context\":null}";
+ StripeClient client = new StripeClient("sk_test_123");
+
+ EventNotification notification = EventNotification.fromJson(payload, client);
+
+ assertNull(notification.getContext());
+ }
+
+ @Test
+ public void testContextBuilderPattern() {
+ // Test the builder pattern works well with StripeContext
+ StripeContext baseContext = StripeContext.parse("workspace_123");
+
+ RequestOptions options =
+ RequestOptions.builder()
+ .setApiKey("sk_test_123")
+ .setStripeContext(baseContext.push("account_456"))
+ .build();
+
+ assertEquals("workspace_123/account_456", options.getStripeContext());
+ }
+
+ @Test
+ public void testContextCompatibility() {
+ // Test that both string and StripeContext work equivalently
+ RequestOptions stringOptions = RequestOptions.builder().setStripeContext("a/b/c").build();
+
+ StripeContext context = new StripeContext(Arrays.asList("a", "b", "c"));
+ RequestOptions contextOptions = RequestOptions.builder().setStripeContext(context).build();
+
+ assertEquals(stringOptions.getStripeContext(), contextOptions.getStripeContext());
+ }
+}
diff --git a/src/test/java/com/stripe/StripeContextTest.java b/src/test/java/com/stripe/StripeContextTest.java
new file mode 100644
index 00000000000..e4b4a2dec1c
--- /dev/null
+++ b/src/test/java/com/stripe/StripeContextTest.java
@@ -0,0 +1,173 @@
+package com.stripe;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+public class StripeContextTest {
+
+ @Test
+ public void testDefaultConstructor() {
+ StripeContext context = new StripeContext();
+ assertEquals(Collections.emptyList(), context.getSegments());
+ }
+
+ @Test
+ public void testConstructorWithSegments() {
+ List segments = Arrays.asList("a", "b", "c");
+ StripeContext context = new StripeContext(segments);
+ assertEquals(segments, context.getSegments());
+ }
+
+ @Test
+ public void testConstructorWithNullSegments() {
+ StripeContext context = new StripeContext(null);
+ assertEquals(Collections.emptyList(), context.getSegments());
+ }
+
+ @Test
+ public void testPush() {
+ StripeContext context = new StripeContext(Arrays.asList("a", "b"));
+ StripeContext newContext = context.push("c");
+
+ // Original context unchanged
+ assertEquals(Arrays.asList("a", "b"), context.getSegments());
+ // New context has added segment
+ assertEquals(Arrays.asList("a", "b", "c"), newContext.getSegments());
+ // Different objects
+ assertNotSame(context, newContext);
+ }
+
+ @Test
+ public void testPopWithSegments() {
+ StripeContext context = new StripeContext(Arrays.asList("a", "b", "c"));
+ StripeContext newContext = context.pop();
+
+ // Original context unchanged
+ assertEquals(Arrays.asList("a", "b", "c"), context.getSegments());
+ // New context has removed last segment
+ assertEquals(Arrays.asList("a", "b"), newContext.getSegments());
+ // Different objects
+ assertNotSame(context, newContext);
+ }
+
+ @Test
+ public void testPopEmpty() {
+ StripeContext context = new StripeContext();
+ assertThrows(IllegalStateException.class, () -> context.pop());
+ }
+
+ @Test
+ public void testToStringEmpty() {
+ StripeContext context = new StripeContext();
+ // useful for clearing context
+ assertEquals("", context.toString());
+ }
+
+ @Test
+ public void testToStringSingleSegment() {
+ StripeContext context = new StripeContext(Arrays.asList("a"));
+ assertEquals("a", context.toString());
+ }
+
+ @Test
+ public void testToStringMultipleSegments() {
+ StripeContext context = new StripeContext(Arrays.asList("a", "b", "c"));
+ assertEquals("a/b/c", context.toString());
+ }
+
+ @Test
+ public void testParseEmptyString() {
+ StripeContext context = StripeContext.parse("");
+ assertEquals(Collections.emptyList(), context.getSegments());
+ }
+
+ @Test
+ public void testParseNull() {
+ StripeContext context = StripeContext.parse(null);
+ assertEquals(Collections.emptyList(), context.getSegments());
+ }
+
+ @Test
+ public void testParseSingleSegment() {
+ StripeContext context = StripeContext.parse("a");
+ assertEquals(Arrays.asList("a"), context.getSegments());
+ }
+
+ @Test
+ public void testParseMultipleSegments() {
+ StripeContext context = StripeContext.parse("a/b/c");
+ assertEquals(Arrays.asList("a", "b", "c"), context.getSegments());
+ }
+
+ @Test
+ public void testEquals() {
+ StripeContext context1 = new StripeContext(Arrays.asList("a", "b"));
+ StripeContext context2 = new StripeContext(Arrays.asList("a", "b"));
+ StripeContext context3 = new StripeContext(Arrays.asList("a", "c"));
+
+ assertEquals(context1, context2);
+ assertNotEquals(context1, context3);
+ assertNotEquals(context1, "a/b");
+ assertNotEquals(context1, null);
+ }
+
+ @Test
+ public void testHashCode() {
+ StripeContext context1 = new StripeContext(Arrays.asList("a", "b"));
+ StripeContext context2 = new StripeContext(Arrays.asList("a", "b"));
+
+ assertEquals(context1.hashCode(), context2.hashCode());
+ }
+
+ @Test
+ public void testImmutableSegments() {
+ List originalSegments = Arrays.asList("a", "b");
+ StripeContext context = new StripeContext(originalSegments);
+
+ // Getting segments should return an unmodifiable list
+ List segments = context.getSegments();
+ assertThrows(UnsupportedOperationException.class, () -> segments.add("c"));
+ }
+
+ @Test
+ public void testContextManipulationPattern() {
+ // Common usage: start with base context, add child contexts
+ StripeContext base = StripeContext.parse("workspace_123");
+ StripeContext child = base.push("account_456");
+ StripeContext grandchild = child.push("customer_789");
+
+ assertEquals("workspace_123", base.toString());
+ assertEquals("workspace_123/account_456", child.toString());
+ assertEquals("workspace_123/account_456/customer_789", grandchild.toString());
+
+ // Go back up the hierarchy
+ StripeContext backToChild = grandchild.pop();
+ StripeContext backToBase = backToChild.pop();
+
+ assertEquals("workspace_123/account_456", backToChild.toString());
+ assertEquals("workspace_123", backToBase.toString());
+ }
+
+ @Test
+ public void testContextImmutability() {
+ StripeContext original = new StripeContext(Arrays.asList("a", "b"));
+
+ // Multiple operations on the same context
+ StripeContext pushed = original.push("c");
+ StripeContext popped = original.pop();
+
+ // Original remains unchanged
+ assertEquals(Arrays.asList("a", "b"), original.getSegments());
+ assertEquals(Arrays.asList("a", "b", "c"), pushed.getSegments());
+ assertEquals(Arrays.asList("a"), popped.getSegments());
+
+ // All are different objects
+ assertNotSame(original, pushed);
+ assertNotSame(original, popped);
+ assertNotSame(pushed, popped);
+ }
+}
diff --git a/src/test/java/com/stripe/net/RequestOptionsTest.java b/src/test/java/com/stripe/net/RequestOptionsTest.java
index 156ee92a1e3..605ab6e7481 100644
--- a/src/test/java/com/stripe/net/RequestOptionsTest.java
+++ b/src/test/java/com/stripe/net/RequestOptionsTest.java
@@ -2,6 +2,7 @@
import static org.junit.jupiter.api.Assertions.*;
+import com.stripe.StripeContext;
import com.stripe.net.RequestOptions.RequestOptionsBuilder;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
@@ -169,6 +170,57 @@ public void mergeOverwritesClientOptions() {
assertEquals("5", merged.getStripeContext());
}
+ @Test
+ public void clientContextIsUsedWhenRequestNull() {
+ StripeResponseGetterOptions clientOptions =
+ TestStripeResponseGetterOptions.builder().setStripeContext("a/b/c").build();
+
+ RequestOptions requestOptions =
+ RequestOptions.builder().setStripeContext((StripeContext) null).build();
+
+ RequestOptions merged = RequestOptions.merge(clientOptions, requestOptions);
+
+ assertEquals("a/b/c", merged.getStripeContext());
+ }
+
+ @Test
+ public void requestContextPrioritizedIfRequestSetNullString() {
+ StripeResponseGetterOptions clientOptions =
+ TestStripeResponseGetterOptions.builder().setStripeContext("a/b/c").build();
+
+ RequestOptions requestOptions =
+ RequestOptions.builder().setStripeContext((String) null).build();
+
+ RequestOptions merged = RequestOptions.merge(clientOptions, requestOptions);
+
+ assertEquals("a/b/c", merged.getStripeContext());
+ }
+
+ @Test
+ public void mergeRequestOptionsWithEmptyContextOverwritesClientContext() {
+ StripeResponseGetterOptions clientOptions =
+ TestStripeResponseGetterOptions.builder().setStripeContext("a/b/c").build();
+
+ RequestOptions requestOptions =
+ RequestOptions.builder().setStripeContext(new StripeContext()).build();
+
+ RequestOptions merged = RequestOptions.merge(clientOptions, requestOptions);
+
+ assertNull(merged.getStripeContext());
+ }
+
+ @Test
+ public void requestContextPrioritized() {
+ StripeResponseGetterOptions clientOptions =
+ TestStripeResponseGetterOptions.builder().setStripeContext("a/b/c").build();
+
+ RequestOptions requestOptions = RequestOptions.builder().setStripeContext("d/e/f").build();
+
+ RequestOptions merged = RequestOptions.merge(clientOptions, requestOptions);
+
+ assertEquals("d/e/f", merged.getStripeContext());
+ }
+
@Test
public void mergeFallsBackToClientOptions() {
Proxy clientProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8080));