feat: Add automatic JDK 25 virtual thread support and simplify executor handling#227
feat: Add automatic JDK 25 virtual thread support and simplify executor handling#227brunoborges wants to merge 3 commits into
Conversation
…or handling This commit adds automatic virtual thread support on JDK 25+ via multi-release JAR and eliminates executor null-checking code smell throughout the SDK. **Key Changes:** 1. **Multi-Release JAR Support for Virtual Threads** - Added `DefaultExecutorProvider` with Java 17 base (returns ForkJoinPool.commonPool()) - Added Java 25 multi-release version (returns virtual thread executor) - Updated Maven build to compile Java 25 version into META-INF/versions/25 - Updated workflows to build with JDK 25 for proper multi-release JAR generation 2. **Eliminated Executor Null Checks** - Removed redundant ternary checks in CopilotClient (lines 189, 330) - Simplified constructor logic for executor initialization - Executor field is now guaranteed non-null 3. **Documentation Updates** - Removed manual virtual thread instructions from README quick start - Updated requirements to explain automatic JDK 25+ virtual thread usage - Simplified smoke test workflow (no longer modifies sample code) 4. **Test Coverage** - Added DefaultExecutorProviderTest with multi-release JAR validation - Fixed JaCoCo to exclude multi-release classes from coverage - All 1005 tests pass **Benefits:** - Cleaner, more maintainable code without null checks - Automatic virtual thread adoption on JDK 25+ (no user action required) - Backward compatible with Java 17+ - SDK manages executor lifecycle properly Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Since executor is now guaranteed to be non-null, removed redundant null checks on lines 442 and 530 before calling session.setExecutor(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a multi-release JAR mechanism to automatically select a virtual-thread-based default executor on JDK 25+, while simplifying executor handling in CopilotClient and updating docs/CI to reflect the new default behavior.
Changes:
- Add
DefaultExecutorProviderwith a JDK 25 multi-release implementation returning a virtual-thread-per-task executor. - Simplify
CopilotClientto always use a non-null executor and introduce shutdown handling for SDK-owned executors. - Update Maven/CI configuration and documentation to build/publish with JDK 25 and document automatic virtual thread usage.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/com/github/copilot/sdk/CopilotClient.java | Centralizes executor selection and introduces executor lifecycle management. |
| src/main/java/com/github/copilot/sdk/DefaultExecutorProvider.java | Provides the default executor implementation for non-JDK25 runtimes. |
| src/main/java25/com/github/copilot/sdk/DefaultExecutorProvider.java | Multi-release JDK 25 implementation that uses virtual threads. |
| src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java | Updates executor-related Javadoc to describe the new default strategy and ownership. |
| src/test/java/com/github/copilot/sdk/DefaultExecutorProviderTest.java | Adds validation for multi-release behavior and virtual-thread execution on JDK 25. |
| pom.xml | Adds a JDK 25 profile to compile multi-release classes and sets multi-release manifest entry; adjusts JaCoCo excludes. |
| README.md | Updates requirements and removes manual “enable virtual threads” quick start instructions. |
| src/site/markdown/index.md | Syncs documentation requirements with the new automatic virtual-thread default on JDK 25+. |
| .github/workflows/build-test.yml | Runs the main CI test job on JDK 25 to exercise multi-release build output. |
| .github/workflows/run-smoke-test.yml | Updates JDK 25 smoke-test instructions to rely on SDK defaults (no manual edits). |
| .github/workflows/publish-snapshot.yml | Switches snapshot publishing to build with JDK 25. |
| .github/workflows/publish-maven.yml | Switches release publishing to build with JDK 25. |
Copilot's findings
- Files reviewed: 12/12 changed files
- Comments generated: 2
| this.ownedExecutor = providedExecutor == null && this.executor instanceof ExecutorService executorService | ||
| ? executorService | ||
| : null; |
| if (Runtime.version().feature() >= 25) { | ||
| return; | ||
| } | ||
|
|
||
| assertNull(DefaultExecutorProvider.create()); |
|
Hi @brunoborges This PR is a surprise and was not a part of my migration plan https://github.com/github/copilot-sdk-partners/issues/80 . I'll try to get it in, but I must prioritize completing that plan and hitting the GA deadline. |
Changed from utility class pattern to enum singleton pattern. This ensures the executor is created once and reused across all CopilotClient instances, which is especially beneficial for the virtual thread executor on JDK 25+. Benefits: - Single virtual thread executor shared across all clients (more efficient) - Thread-safe lazy initialization (enum guarantee) - Prevents instantiation without needing private constructor Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
AI prompted risk assessment. PR #227 Risk AssessmentTitle: feat: Add automatic JDK 25 virtual thread support and simplify executor handling Commit Breakdown
High-Risk Issues1. CI workflows now require JDK 25 to buildAll four workflow files (build-test.yml,
2.
|
| Issue | Detail |
|---|---|
| No Java 17 test matrix | SDK promises Java 17+ but CI only builds/tests on 25 |
| Smoke test simplification | Removed the JDK 25 virtual thread setup instructions from the smoke test, relying entirely on multi-release JAR working correctly — which is untested on 17 in CI |
| README simplification | Quick start no longer shows how to manually configure an executor, reducing user control visibility |
Low-Risk / Positive
- Commits 2 & 3 remove legitimate code smell (null-check ternaries)
- The multi-release JAR approach is architecturally sound in principle
- Javadoc updates in
CopilotClientOptionsare accurate and helpful - JaCoCo exclusion for
META-INF/versions/**is correct
Verdict
Recommend: DO NOT MERGE as-is before GA. Key reasons:
- Potential correctness bug: Shared singleton executor gets shut down by the first client that closes, breaking subsequent clients.
- CI no longer tests on Java 17, the minimum supported version.
- Unrelated change (
.vscode/mcp.jsondeletion) bundled in. - Insufficient test coverage for the multi-release behavior on the actual target (Java 17 running without virtual threads).
If the feature is desired for GA, it needs at minimum:
- Fix the shared-executor-shutdown bug (don't assign
ownedExecutorwhen using the singleton) - Restore Java 17 in the CI test matrix (or add a matrix entry)
- Remove the unrelated
.vscode/mcp.jsondeletion - Add a Java 17 integration test that proves the non-virtual-thread path works in a packaged JAR
|
I agree with the observations in the risk assessment. Also, the PR must be reworked to take into account the drift from For these reasons, and the directive from @patniko that we need to have all the changes in by COB PDT 2026-05-29, I judge this can safely be deferred until after GA. |
|
Please re-open or create a new PR after GA. |
This PR adds automatic virtual thread support on JDK 25+ and eliminates executor null-checking code smell throughout the SDK.
Summary
Addresses two code smell issues identified in executor handling:
CopilotClient(lines 189, 330)Changes
Multi-Release JAR for Virtual Threads
DefaultExecutorProviderwith platform-specific implementationsMulti-Release: trueCode Simplification
Eliminated redundant ternary null checks by ensuring executor is never null.
Documentation
Testing
DefaultExecutorProviderTestwith multi-release JAR validationBenefits