Skip to content

Commit 87b07f5

Browse files
authored
Fix UnsupportedOperationException when merging ActivityOptions with immutable context propagators (#2749)
1 parent 9fae229 commit 87b07f5

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

temporal-sdk/src/main/java/io/temporal/activity/ActivityOptions.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.temporal.common.context.ContextPropagator;
77
import io.temporal.failure.CanceledFailure;
88
import java.time.Duration;
9+
import java.util.ArrayList;
910
import java.util.List;
1011

1112
/** Options used to configure how an activity is invoked. */
@@ -282,7 +283,9 @@ public Builder mergeActivityOptions(ActivityOptions override) {
282283
if (this.contextPropagators == null) {
283284
this.contextPropagators = override.contextPropagators;
284285
} else if (override.contextPropagators != null) {
285-
this.contextPropagators.addAll(override.contextPropagators);
286+
List<ContextPropagator> merged = new ArrayList<>(this.contextPropagators);
287+
merged.addAll(override.contextPropagators);
288+
this.contextPropagators = merged;
286289
}
287290
if (override.versioningIntent != VersioningIntent.VERSIONING_INTENT_UNSPECIFIED) {
288291
this.versioningIntent = override.versioningIntent;

temporal-sdk/src/test/java/io/temporal/activity/ActivityOptionsTest.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
import static org.junit.Assert.*;
44

5+
import io.temporal.api.common.v1.Payload;
56
import io.temporal.common.MethodRetry;
67
import io.temporal.common.RetryOptions;
8+
import io.temporal.common.context.ContextPropagator;
79
import io.temporal.testing.TestActivityEnvironment;
810
import io.temporal.workflow.shared.TestActivities.TestActivity;
911
import io.temporal.workflow.shared.TestActivities.TestActivityImpl;
1012
import java.lang.reflect.Method;
1113
import java.time.Duration;
14+
import java.util.Collections;
15+
import java.util.List;
1216
import java.util.Map;
1317
import org.junit.*;
1418
import org.junit.rules.Timeout;
@@ -62,6 +66,69 @@ public void testActivityOptionsMerge() {
6266
Assert.assertEquals(methodOps1, merged);
6367
}
6468

69+
@Test
70+
public void testActivityOptionsMergeWithImmutableContextPropagators() {
71+
// Local class to avoid code duplication
72+
class TestContextPropagator implements ContextPropagator {
73+
private final String name;
74+
75+
TestContextPropagator(String name) {
76+
this.name = name;
77+
}
78+
79+
@Override
80+
public String getName() {
81+
return name;
82+
}
83+
84+
@Override
85+
public Map<String, Payload> serializeContext(Object context) {
86+
return Collections.emptyMap();
87+
}
88+
89+
@Override
90+
public Object deserializeContext(Map<String, Payload> context) {
91+
return null;
92+
}
93+
94+
@Override
95+
public Object getCurrentContext() {
96+
return null;
97+
}
98+
99+
@Override
100+
public void setCurrentContext(Object context) {}
101+
}
102+
103+
ContextPropagator propagator1 = new TestContextPropagator("propagator1");
104+
ContextPropagator propagator2 = new TestContextPropagator("propagator2");
105+
106+
// Create options with immutable singleton lists
107+
// This tests the fix for https://github.com/temporalio/sdk-java/issues/2482
108+
ActivityOptions options1 =
109+
ActivityOptions.newBuilder()
110+
.setStartToCloseTimeout(Duration.ofSeconds(1))
111+
.setContextPropagators(Collections.singletonList(propagator1))
112+
.build();
113+
114+
ActivityOptions options2 =
115+
ActivityOptions.newBuilder()
116+
.setStartToCloseTimeout(Duration.ofSeconds(2))
117+
.setContextPropagators(Collections.singletonList(propagator2))
118+
.build();
119+
120+
// Merging should not throw UnsupportedOperationException
121+
ActivityOptions merged =
122+
ActivityOptions.newBuilder(options1).mergeActivityOptions(options2).build();
123+
124+
// Verify both context propagators are present in the merged result
125+
List<ContextPropagator> mergedPropagators = merged.getContextPropagators();
126+
assertNotNull(mergedPropagators);
127+
assertEquals(2, mergedPropagators.size());
128+
assertEquals("propagator1", mergedPropagators.get(0).getName());
129+
assertEquals("propagator2", mergedPropagators.get(1).getName());
130+
}
131+
65132
@Test
66133
public void testActivityOptionsDefaultInstance() {
67134
testEnv.registerActivitiesImplementations(new TestActivityImpl());

0 commit comments

Comments
 (0)