Skip to content

Commit a4242f3

Browse files
authored
Merge branch 'master' into eamsden/skip-yield-on-version-enabled-comment
2 parents cb5054c + 80e6a1c commit a4242f3

33 files changed

Lines changed: 252 additions & 108 deletions

File tree

.github/workflows/ci.yml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ jobs:
191191
- name: Set up Java
192192
uses: actions/setup-java@v5
193193
with:
194-
java-version: "11"
194+
java-version: "23"
195195
distribution: "temurin"
196196

197197
- name: Set up Gradle
@@ -200,6 +200,30 @@ jobs:
200200
- name: Run copyright and code format checks
201201
run: ./gradlew --no-daemon spotlessCheck
202202

203+
javadoc:
204+
name: Javadoc
205+
runs-on: ubuntu-latest
206+
timeout-minutes: 20
207+
steps:
208+
- name: Checkout repo
209+
uses: actions/checkout@v5
210+
with:
211+
fetch-depth: 0
212+
submodules: recursive
213+
ref: ${{ github.event.pull_request.head.sha }}
214+
215+
- name: Set up Java
216+
uses: actions/setup-java@v5
217+
with:
218+
java-version: "23"
219+
distribution: "temurin"
220+
221+
- name: Set up Gradle
222+
uses: gradle/actions/setup-gradle@v5
223+
224+
- name: Run javadoc
225+
run: ./gradlew --no-daemon javadoc
226+
203227
build_native_images:
204228
name: Build native test server
205229
uses: ./.github/workflows/build-native-image.yml

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ src/main/idls/*
1818
.settings
1919
.vscode/
2020
*/bin
21-
/.claude
21+
/.claude
22+
mise.local.toml
23+
**/.factorypath

gradle/java.gradle

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@ subprojects {
3232

3333
javadoc {
3434
options.encoding = 'UTF-8'
35-
if (JavaVersion.current().isJava8Compatible()) {
36-
options.addStringOption('Xdoclint:none', '-quiet')
37-
}
35+
options.addStringOption('Xdoclint:reference', '-quiet')
36+
options.addBooleanOption('Werror', true)
3837
if (JavaVersion.current().isJava9Compatible()) {
3938
options.addBooleanOption('html5', true)
4039
}

releases/v1.34.0

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# **💥 BREAKING CHANGES**
2+
3+
## Nexus Failure Serialization
4+
5+
The Java SDK now uses Temporal `Failure` protos for Nexus operation and handler task
6+
failures, instead of the legacy `UnsuccessfulOperationError`/`HandlerError` format.
7+
This allows `OperationException` and `HandlerException` to carry their own message and
8+
stack trace independently of their cause.
9+
10+
The SDK automatically falls back to the legacy format when the server does not support
11+
the new format. However, if your code inspects the raw structure of Nexus failures
12+
(e.g. via custom interceptors or failure converters), you may need to update it to
13+
handle the new format. (#2773)
14+
15+
# **Highlights**
16+
17+
## Spring Boot 4 and Jackson 3 Support
18+
19+
Spring Boot 4 is now supported. The Spring Boot autoconfigure module was updated for
20+
Spring Boot 4 API changes (e.g. updated class references in `MetricsScopeAutoConfiguration`
21+
and `OpenTracingAutoConfiguration`). No code changes are needed in application code. (#2787)
22+
23+
Jackson 3 is now optionally supported via a multi-release JAR. To opt in, call
24+
`JacksonJsonPayloadConverter.setDefaultAsJackson3(true, jacksonCompatMode)` at startup.
25+
Jackson 3 and Jackson 2 converters are wire-compatible. Jackson 3 is an optional
26+
dependency and is not pulled in automatically. (#2783)
27+
28+
Plugin beans (`WorkflowServiceStubsPlugin`, `WorkflowClientPlugin`, `ScheduleClientPlugin`,
29+
`WorkerPlugin`) defined in the Spring context are now automatically discovered and wired
30+
into the Temporal client and worker configuration. Plugins support `@Order` and `@Priority`
31+
annotations for consistent ordering. (#2766)
32+
33+
## Upgrade-on-ContinueAsNew
34+
35+
PINNED workflows can now upgrade to the latest worker deployment version on
36+
continue-as-new by setting `initialVersioningBehavior` to `AUTO_UPGRADE` in
37+
`ContinueAsNewOptions`. A new `WorkflowInfo.isTargetWorkerDeploymentVersionChanged()`
38+
method lets workflows detect when the target worker deployment version has changed,
39+
enabling explicit upgrade decisions. (#2811)
40+
41+
## Local Timeout for Activity Heartbeats
42+
43+
Activity heartbeat timeouts are now enforced locally by the SDK, matching the behavior
44+
of the Core-based SDKs. Previously, only the server enforced heartbeat timeouts; the
45+
local check reduces the time it takes for a stale activity to be detected and retried.
46+
This feature applies to heartbeat timeouts only, not overall activity timeouts. (#2804)
47+
48+
## Nexus Caller Timeouts
49+
50+
`ScheduleToStartTimeout` and `StartToCloseTimeout` are now supported for Nexus
51+
operations, in addition to the existing `ScheduleToCloseTimeout`. The test server was
52+
updated to enforce all three timeout types and compute the `OPERATION_TIMEOUT` header
53+
correctly. (#2760)
54+
55+
# **Bugfixes**
56+
57+
## ContextClassLoader Propagation for Poll Tasks
58+
59+
When `PollerBehaviorAutoscaling` is enabled, poll tasks run asynchronously on a
60+
common `ForkJoinPool`, whose threads use the system class loader by default. This
61+
caused class-loading failures in frameworks like Spring Boot that rely on a custom
62+
context class loader (e.g. `LaunchedClassLoader`). The SDK now captures and propagates
63+
the context class loader from the thread that created the `WorkerFactory` to all
64+
worker threads. (#2808)
65+
66+
## Workflow Slot Not Marked Used for Async Pollers
67+
68+
When `PollerBehaviorAutoscaling` was enabled, `AsyncWorkflowPollTask` was not calling
69+
`markSlotUsed` on the `SlotSupplier` after receiving a task. This caused the
70+
`WORKER_TASK_SLOTS_AVAILABLE` metric to report an incorrectly high value. (#2803)
71+
72+
## Validate `WorkerDeploymentOptions` at Build Time
73+
74+
`WorkerDeploymentOptions.build()` now rejects configurations where
75+
`defaultVersioningBehavior` is set to anything other than `UNSPECIFIED` when
76+
`useVersioning` is `false`. Previously such configurations were silently accepted but
77+
then rejected by the server at workflow task completion, causing workflows to get stuck.
78+
(#2807)
79+
80+
## Fix Exception Swallowing on `Workflow.getVersion()`
81+
82+
A bug where exceptions thrown by a workflow could be swallowed and replaced by a
83+
worker-shutdown error when `Workflow.getVersion()` was called is now fixed for all
84+
new workflows. Existing workflows replay correctly without any changes. (#2819)
85+
86+
# What's Changed
87+
88+
2026-02-26 - 9799bd00 - Add missing apostrophe to WorkflowException message (#2776)
89+
2026-02-27 - ef194239 - Add headers to cancel nexus task (#2798)
90+
2026-03-10 - 20fb8520 - Nexus caller timeouts (#2760)
91+
2026-03-10 - dbd648bd - Update Nexus failure conversion (#2773)
92+
2026-03-11 - 6ba0947f - Fix async poller workflow slot used (#2803)
93+
2026-03-13 - 53449bb5 - Introduce local timeout for activity heartbeats (#2804)
94+
2026-03-16 - 9356745c - Replace docker instructions for running a local server with CLI instructions. (#2806)
95+
2026-03-17 - 95169659 - Cancel timer when Workflow.await condition is satisfied (#2799)
96+
2026-03-17 - fb2defd9 - Fix time skipping for dotnet SDK (#2805)
97+
2026-03-19 - 02182b93 - Support plugins in spring-boot-autoconfigure (#2766)
98+
2026-03-23 - a714cc10 - Allow poller scale-down on timeout when server supports autoscaling (#2812)
99+
2026-03-24 - b9c186d1 - Add note about Rosetta for old protoc-gen-rpc-java (#2815)
100+
2026-03-25 - c195cd1d - Add Spring Boot 4 support (#2787)
101+
2026-03-25 - fcb4e841 - Add opt-in Jackson 3 support via multi-release JAR (#2783)
102+
2026-03-27 - 0e1a7a25 - Validate deployment options and test worker with versioning off and custom build ID (#2807)
103+
2026-03-27 - da5e8a17 - Add upgrade-on-CAN support (#2811)
104+
2026-03-30 - b9b0f6b5 - Fix ContextClassLoader propagation for poll tasks (#2808)
105+
2026-03-31 - 5d969b87 - `tryUseSdkFlag(SdkFlag.SKIP_YIELD_ON_VERSION)` so that we default to enabling `SKIP_YIELD_ON_VERSION` when calling `getVersion()` (#2819)
106+
2026-03-31 - fb87ce6c - Update Temporal Cloud-API to v0.12.0 (#2814)

temporal-envconfig/src/main/java/io/temporal/envconfig/ClientConfig.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,16 @@ public static ClientConfig getDefaultInstance() {
4444
private static String getDefaultConfigFilePath() {
4545
String userDir = System.getProperty("user.home");
4646
if (userDir == null || userDir.isEmpty()) {
47-
throw new RuntimeException("failed getting user home directory");
47+
return null;
4848
}
4949
return getDefaultConfigFilePath(userDir, System.getProperty("os.name"), System.getenv());
5050
}
5151

5252
static String getDefaultConfigFilePath(
5353
String userDir, String osName, Map<String, String> environment) {
54+
if (userDir == null || userDir.isEmpty()) {
55+
return null;
56+
}
5457
if (osName != null) {
5558
String osNameLower = osName.toLowerCase();
5659
if (osNameLower.contains("mac")) {
@@ -60,7 +63,7 @@ static String getDefaultConfigFilePath(
6063
if (osNameLower.contains("win")) {
6164
String appData = environment != null ? environment.get("APPDATA") : null;
6265
if (appData == null || appData.isEmpty()) {
63-
throw new RuntimeException("%APPDATA% is not defined");
66+
return null;
6467
}
6568
return Paths.get(appData, "temporalio", "temporal.toml").toString();
6669
}
@@ -122,6 +125,10 @@ public static ClientConfig load(LoadClientConfigOptions options) throws IOExcept
122125
if (file == null || file.isEmpty()) {
123126
file = getDefaultConfigFilePath();
124127
}
128+
// No config dir available — return default empty config
129+
if (file == null) {
130+
return getDefaultInstance();
131+
}
125132
try {
126133
ClientConfigToml.TomlClientConfig result = reader.readValue(new File(file));
127134
return new ClientConfig(ClientConfigToml.getClientProfiles(result));
@@ -172,7 +179,7 @@ public static ClientConfig fromToml(byte[] tomlData, ClientConfigFromTomlOptions
172179
*
173180
* @param config the client config to convert
174181
* @return the TOML data as bytes
175-
* @apiNote The output will not be identical to the input if the config was loaded from a file
182+
* <p>Note: The output will not be identical to the input if the config was loaded from a file
176183
* because comments and formatting are not preserved.
177184
*/
178185
public static byte[] toTomlAsBytes(ClientConfig config) throws IOException {

temporal-envconfig/src/test/java/io/temporal/envconfig/ClientConfigProfileTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,22 @@ public void defaultConfigFilePath() {
325325
ClientConfig.getDefaultConfigFilePath("/home/test", "Linux", Collections.emptyMap()));
326326
}
327327

328+
@Test
329+
public void loadDefaultConfigMissingHomeDir() throws IOException {
330+
String original = System.getProperty("user.home");
331+
try {
332+
System.setProperty("user.home", "");
333+
ClientConfig config =
334+
ClientConfig.load(
335+
LoadClientConfigOptions.newBuilder().setEnvOverrides(Collections.emptyMap()).build());
336+
Assert.assertEquals(ClientConfig.getDefaultInstance(), config);
337+
} finally {
338+
if (original != null) {
339+
System.setProperty("user.home", original);
340+
}
341+
}
342+
}
343+
328344
@Test
329345
public void parseToml() throws IOException {
330346
String toml =

temporal-remote-data-encoder/src/main/java/io/temporal/payload/codec/AbstractRemoteDataEncoderCodec.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
/**
1212
* Performs encoding/decoding of the payloads via the Remote Data Encoder (RDE) available over http.
1313
*
14-
* <p>
15-
*
1614
* <h2>Remote Data Encoder Http Server specification</h2>
1715
*
1816
* <p>RDE Server must:

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ public interface ActivityInfo {
126126
/**
127127
* Return the priority of the activity task.
128128
*
129-
* @apiNote If unset or on an older server version, this method will return {@link
130-
* Priority#getDefaultInstance()}.
129+
* <p>Note: If unset or on an older server version, this method will return {@link
130+
* Priority#getDefaultInstance()}.
131131
*/
132132
@Experimental
133133
@Nonnull

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@
4242
* When <code>CImpl</code> instance is registered with the {@link io.temporal.worker.Worker} the
4343
* following activities are registered:
4444
*
45-
* <p>
46-
*
4745
* <ul>
4846
* <li>B_a
4947
* <li>B_b

temporal-sdk/src/main/java/io/temporal/client/WorkflowClient.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,8 @@ static WorkflowClient newInstance(WorkflowServiceStubs service, WorkflowClientOp
158158
* @param workflowId Workflow id.
159159
* @param runId Run id of the workflow execution.
160160
* @return Stub that implements workflowInterface and can be used to signal, update, or query it.
161-
* @deprecated Use {@link #newWorkflowStub(Class, WorkflowTargetOptions)} instead.
162-
* @apiNote This method is deprecated because the returned stub does not properly account for the
163-
* runId.
161+
* @deprecated Use {@link #newWorkflowStub(Class, WorkflowTargetOptions)} instead. This method is
162+
* deprecated because the returned stub does not properly account for the runId.
164163
*/
165164
@Deprecated
166165
<T> T newWorkflowStub(Class<T> workflowInterface, String workflowId, Optional<String> runId);
@@ -205,9 +204,8 @@ static WorkflowClient newInstance(WorkflowServiceStubs service, WorkflowClientOp
205204
* workflowId is assumed.
206205
* @param workflowType type of the workflow. Optional as it is used for error reporting only.
207206
* @return Stub that can be used to start workflow and later to signal or query it.
208-
* @deprecated Use {@link #newUntypedWorkflowStub(WorkflowTargetOptions, Optional)} instead.
209-
* @apiNote This method is deprecated because the returned stub does not properly account for the
210-
* runId.
207+
* @deprecated Use {@link #newUntypedWorkflowStub(WorkflowTargetOptions, Optional)} instead. This
208+
* method is deprecated because the returned stub does not properly account for the runId.
211209
*/
212210
@Deprecated
213211
WorkflowStub newUntypedWorkflowStub(
@@ -220,9 +218,8 @@ WorkflowStub newUntypedWorkflowStub(
220218
* @param execution workflow id and optional run id for execution
221219
* @param workflowType type of the workflow. Optional as it is used for error reporting only.
222220
* @return Stub that can be used to start workflow and later to signal or query it.
223-
* @deprecated Use {@link #newUntypedWorkflowStub(WorkflowTargetOptions, Optional)} instead.
224-
* @apiNote This method is deprecated because the returned stub does not properly account for the
225-
* runId.
221+
* @deprecated Use {@link #newUntypedWorkflowStub(WorkflowTargetOptions, Optional)} instead. This
222+
* method is deprecated because the returned stub does not properly account for the runId.
226223
*/
227224
WorkflowStub newUntypedWorkflowStub(WorkflowExecution execution, Optional<String> workflowType);
228225

0 commit comments

Comments
 (0)