diff --git a/org.eclipse.lsp4e.test/META-INF/MANIFEST.MF b/org.eclipse.lsp4e.test/META-INF/MANIFEST.MF
index c70633892..7a360a319 100644
--- a/org.eclipse.lsp4e.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.lsp4e.test/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Tests for language server bundle (Incubation)
Bundle-SymbolicName: org.eclipse.lsp4e.test;singleton:=true
-Bundle-Version: 0.16.1.qualifier
+Bundle-Version: 0.16.2.qualifier
Fragment-Host: org.eclipse.lsp4e
Bundle-Vendor: Eclipse LSP4E
Bundle-RequiredExecutionEnvironment: JavaSE-21
diff --git a/org.eclipse.lsp4e.test/pom.xml b/org.eclipse.lsp4e.test/pom.xml
index ef54b04de..349e83c39 100644
--- a/org.eclipse.lsp4e.test/pom.xml
+++ b/org.eclipse.lsp4e.test/pom.xml
@@ -8,7 +8,7 @@
org.eclipse.lsp4e.test
eclipse-test-plugin
- 0.16.1-SNAPSHOT
+ 0.16.2-SNAPSHOT
diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/commands/DynamicRegistrationTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/commands/DynamicRegistrationTest.java
index d89ff7141..af2e90765 100644
--- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/commands/DynamicRegistrationTest.java
+++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/commands/DynamicRegistrationTest.java
@@ -45,8 +45,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import com.google.gson.Gson;
-
public class DynamicRegistrationTest extends AbstractTestWithProject {
private static final String WORKSPACE_EXECUTE_COMMAND = "workspace/executeCommand";
@@ -143,7 +141,7 @@ private UUID registerWatchedFiles() throws Exception {
final var watcher = new org.eclipse.lsp4j.FileSystemWatcher(
org.eclipse.lsp4j.jsonrpc.messages.Either.forLeft("**/*.txt"), null);
options.setWatchers(List.of(watcher));
- registration.setRegisterOptions(new Gson().toJsonTree(options));
+ registration.setRegisterOptions(options);
client.registerCapability(new RegistrationParams(List.of(registration))).get(1, TimeUnit.SECONDS);
return id;
}
@@ -165,7 +163,7 @@ private UUID registerCommands(String... command) throws Exception {
final var registration = new Registration();
registration.setId(id.toString());
registration.setMethod(WORKSPACE_EXECUTE_COMMAND);
- registration.setRegisterOptions(new Gson().toJsonTree(new ExecuteCommandOptions(List.of(command))));
+ registration.setRegisterOptions(new ExecuteCommandOptions(List.of(command)));
client.registerCapability(new RegistrationParams(List.of(registration))).get(1, TimeUnit.SECONDS);
return id;
}
diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/DynamicCompletionRegistrationTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/DynamicCompletionRegistrationTest.java
index 08f544b24..a751b94e1 100644
--- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/DynamicCompletionRegistrationTest.java
+++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/completion/DynamicCompletionRegistrationTest.java
@@ -41,8 +41,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import com.google.gson.Gson;
-
/**
* Verifies that dynamic registration of completion updates LSP4E server
* capabilities and enables content assist proposals.
@@ -82,7 +80,7 @@ public void testDynamicCompletionRegistrationProvidesProposalsAndTriggers() thro
registration.setMethod("textDocument/completion");
var opts = new CompletionOptions();
opts.setTriggerCharacters(List.of(".", "/", "#"));
- registration.setRegisterOptions(new Gson().toJsonTree(opts));
+ registration.setRegisterOptions(opts);
client.registerCapability(new RegistrationParams(List.of(registration))).get(2, TimeUnit.SECONDS);
// Compute proposals (manual invocation). Should return the mock item.
diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/internal/JsonUtilTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/internal/JsonUtilTest.java
new file mode 100644
index 000000000..22f2f400c
--- /dev/null
+++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/internal/JsonUtilTest.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2025 Contributors to the Eclipse Foundation.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * See git history
+ *******************************************************************************/
+package org.eclipse.lsp4e.test.internal;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.eclipse.lsp4e.internal.JsonUtil;
+import org.eclipse.lsp4j.FileSystemWatcher;
+import org.eclipse.lsp4j.WatchKind;
+import org.junit.jupiter.api.Test;
+
+public class JsonUtilTest {
+
+ @Test
+ void testRoundtrip() throws Exception {
+ // Setup an object which uses Either internally.
+ // This can only be properly de/serialized with Gson instance which knows about LSP4J types.
+ var original = new FileSystemWatcher();
+ original.setGlobPattern("**");
+ original.setKind(WatchKind.Create | WatchKind.Change | WatchKind.Delete);
+
+ String json = JsonUtil.LSP4J_GSON.toJson(original);
+ assertEquals("""
+ {"globPattern":"**","kind":7}""", json);
+
+ FileSystemWatcher copy = JsonUtil.LSP4J_GSON.fromJson(json, FileSystemWatcher.class);
+ assertEquals(original, copy);
+ }
+
+}
diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java
index de24efc8b..f0430de08 100644
--- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java
+++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java
@@ -18,7 +18,7 @@
*******************************************************************************/
package org.eclipse.lsp4e;
-import static org.eclipse.lsp4e.internal.NullSafetyHelper.*;
+import static org.eclipse.lsp4e.internal.NullSafetyHelper.castNonNull;
import java.io.BufferedReader;
import java.io.File;
@@ -80,6 +80,7 @@
import org.eclipse.lsp4e.internal.ArrayUtil;
import org.eclipse.lsp4e.internal.CancellationUtil;
import org.eclipse.lsp4e.internal.FileBufferListenerAdapter;
+import org.eclipse.lsp4e.internal.JsonUtil;
import org.eclipse.lsp4e.internal.SupportedFeatures;
import org.eclipse.lsp4e.internal.files.FileSystemWatcherManager;
import org.eclipse.lsp4e.server.StreamConnectionProvider;
@@ -129,7 +130,6 @@
import com.google.common.base.Functions;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import com.google.gson.Gson;
import com.google.gson.JsonObject;
public class LanguageServerWrapper {
@@ -1173,7 +1173,7 @@ public void registerCapability(RegistrationParams params) {
break;
case "workspace/executeCommand": //$NON-NLS-1$
try {
- ExecuteCommandOptions executeCommandOptions = castNonNull(new Gson().fromJson((JsonObject) reg.getRegisterOptions(),
+ ExecuteCommandOptions executeCommandOptions = castNonNull(JsonUtil.LSP4J_GSON.fromJson((JsonObject) reg.getRegisterOptions(),
ExecuteCommandOptions.class));
List newCommands = executeCommandOptions.getCommands();
if (!newCommands.isEmpty()) {
@@ -1212,7 +1212,7 @@ public void registerCapability(RegistrationParams params) {
case "textDocument/completion": { //$NON-NLS-1$
CompletionOptions previous = serverCapabilities.getCompletionProvider();
try {
- final var completionOpts = new Gson().fromJson((JsonObject) reg.getRegisterOptions(),
+ final var completionOpts = JsonUtil.LSP4J_GSON.fromJson((JsonObject) reg.getRegisterOptions(),
CompletionOptions.class);
serverCapabilities.setCompletionProvider(completionOpts);
addRegistration(reg, () -> serverCapabilities.setCompletionProvider(previous));
@@ -1255,8 +1255,9 @@ public void registerCapability(RegistrationParams params) {
return null;
if (registerOptions instanceof DidChangeWatchedFilesRegistrationOptions direct)
return direct;
- if (registerOptions instanceof JsonObject jsonObject)
- return new Gson().fromJson(jsonObject, DidChangeWatchedFilesRegistrationOptions.class);
+ if (registerOptions instanceof JsonObject jsonObject) {
+ return JsonUtil.LSP4J_GSON.fromJson(jsonObject, DidChangeWatchedFilesRegistrationOptions.class);
+ }
return null;
}
diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/command/CommandExecutor.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/command/CommandExecutor.java
index 3ff684bda..c8414a1d5 100644
--- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/command/CommandExecutor.java
+++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/command/CommandExecutor.java
@@ -8,7 +8,8 @@
*******************************************************************************/
package org.eclipse.lsp4e.command;
-import static org.eclipse.lsp4e.command.LSPCommandHandler.*;
+import static org.eclipse.lsp4e.command.LSPCommandHandler.LSP_COMMAND_PARAMETER_ID;
+import static org.eclipse.lsp4e.command.LSPCommandHandler.LSP_PATH_PARAMETER_ID;
import java.net.URI;
import java.util.ArrayList;
@@ -33,6 +34,7 @@
import org.eclipse.lsp4e.LSPEclipseUtils;
import org.eclipse.lsp4e.LanguageServerPlugin;
import org.eclipse.lsp4e.command.internal.CommandEventParameter;
+import org.eclipse.lsp4e.internal.JsonUtil;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.WorkspaceEdit;
@@ -192,7 +194,7 @@ private static WorkspaceEdit createWorkspaceEdit(List