Skip to content

Commit 9d28aab

Browse files
brunoborgesCopilot
andcommitted
refactor: Convert DefaultExecutorProvider to enum singleton
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>
1 parent d761586 commit 9d28aab

5 files changed

Lines changed: 26 additions & 34 deletions

File tree

.vscode/mcp.json

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/main/java/com/github/copilot/sdk/CopilotClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public CopilotClient(CopilotClientOptions options) {
157157
}
158158

159159
Executor providedExecutor = this.options.getExecutor();
160-
this.executor = providedExecutor != null ? providedExecutor : DefaultExecutorProvider.create();
160+
this.executor = providedExecutor != null ? providedExecutor : DefaultExecutorProvider.INSTANCE.get();
161161
this.ownedExecutor = providedExecutor == null && this.executor instanceof ExecutorService executorService
162162
? executorService
163163
: null;

src/main/java/com/github/copilot/sdk/DefaultExecutorProvider.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
import java.util.concurrent.Executor;
88
import java.util.concurrent.ForkJoinPool;
99

10-
final class DefaultExecutorProvider {
10+
enum DefaultExecutorProvider {
11+
INSTANCE;
1112

12-
private DefaultExecutorProvider() {
13-
}
13+
private final Executor executor = ForkJoinPool.commonPool();
1414

15-
static Executor create() {
16-
return ForkJoinPool.commonPool();
15+
Executor get() {
16+
return executor;
1717
}
1818
}

src/main/java25/com/github/copilot/sdk/DefaultExecutorProvider.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
import java.util.concurrent.Executor;
88
import java.util.concurrent.Executors;
99

10-
final class DefaultExecutorProvider {
10+
enum DefaultExecutorProvider {
11+
INSTANCE;
1112

12-
private DefaultExecutorProvider() {
13-
}
13+
private final Executor executor = Executors.newVirtualThreadPerTaskExecutor();
1414

15-
static Executor create() {
16-
return Executors.newVirtualThreadPerTaskExecutor();
15+
Executor get() {
16+
return executor;
1717
}
1818
}

src/test/java/com/github/copilot/sdk/DefaultExecutorProviderTest.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
package com.github.copilot.sdk;
66

7+
import static org.junit.jupiter.api.Assertions.assertEquals;
78
import static org.junit.jupiter.api.Assertions.assertNotNull;
8-
import static org.junit.jupiter.api.Assertions.assertNull;
99
import static org.junit.jupiter.api.Assertions.assertTrue;
1010

1111
import java.io.IOException;
12+
import java.lang.reflect.Field;
1213
import java.lang.reflect.Method;
1314
import java.net.URL;
1415
import java.net.URLClassLoader;
@@ -17,6 +18,7 @@
1718
import java.util.concurrent.CompletableFuture;
1819
import java.util.concurrent.Executor;
1920
import java.util.concurrent.ExecutorService;
21+
import java.util.concurrent.ForkJoinPool;
2022
import java.util.concurrent.TimeUnit;
2123
import java.util.jar.Attributes;
2224
import java.util.jar.JarEntry;
@@ -28,12 +30,10 @@
2830
class DefaultExecutorProviderTest {
2931

3032
@Test
31-
void baseProviderUsesCompletableFutureDefaultExecutor() {
32-
if (Runtime.version().feature() >= 25) {
33-
return;
34-
}
35-
36-
assertNull(DefaultExecutorProvider.create());
33+
void testBaseImplementationReturnsForkJoinPool() {
34+
Executor executor = DefaultExecutorProvider.INSTANCE.get();
35+
assertNotNull(executor);
36+
assertEquals(ForkJoinPool.commonPool(), executor);
3737
}
3838

3939
@Test
@@ -54,10 +54,14 @@ void multiReleaseProviderUsesVirtualThreadsOnJdk25() throws Exception {
5454

5555
try (var loader = new URLClassLoader(new URL[]{jar.toUri().toURL()}, null)) {
5656
Class<?> provider = Class.forName("com.github.copilot.sdk.DefaultExecutorProvider", true, loader);
57-
Method create = provider.getDeclaredMethod("create");
58-
create.setAccessible(true);
59-
60-
Object result = create.invoke(null);
57+
Field instanceField = provider.getDeclaredField("INSTANCE");
58+
instanceField.setAccessible(true);
59+
Object instance = instanceField.get(null);
60+
61+
Method getMethod = provider.getDeclaredMethod("get");
62+
getMethod.setAccessible(true);
63+
Object result = getMethod.invoke(instance);
64+
6165
assertNotNull(result, "JDK 25 multi-release provider must create a default executor");
6266
assertTrue(result instanceof Executor, "Default provider must return an Executor");
6367

0 commit comments

Comments
 (0)