diff --git a/org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/json/adapters/MessageTypeAdapter.java b/org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/json/adapters/MessageTypeAdapter.java index bffdecb1e..5a1e797b1 100644 --- a/org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/json/adapters/MessageTypeAdapter.java +++ b/org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/json/adapters/MessageTypeAdapter.java @@ -246,6 +246,20 @@ protected Object parseParams(JsonReader in, String method) throws IOException, J } Type[] parameterTypes = getParameterTypes(method); if (parameterTypes.length == 1) { + if (next == JsonToken.BEGIN_ARRAY) { + /* JsonRPC 2.0: ยง4.2 Parameter Structures. + Wrapping: + "some-value" -> ["some-value"] + ["some-array"] -> [["some-array"]] + By-pass: + {type: "some_obj"} -> {type: "some_obj"} + */ + // Unwrap by removing the the outermost array. + in.beginArray(); + var singleParameter = fromJson(in, parameterTypes[0]); + in.endArray(); + return singleParameter; + } return fromJson(in, parameterTypes[0]); } if (parameterTypes.length > 1 && next == JsonToken.BEGIN_ARRAY) { diff --git a/org.eclipse.lsp4j.jsonrpc/src/test/java/org/eclipse/lsp4j/jsonrpc/test/json/MessageJsonHandlerTest.java b/org.eclipse.lsp4j.jsonrpc/src/test/java/org/eclipse/lsp4j/jsonrpc/test/json/MessageJsonHandlerTest.java index 5d648b1f7..d585a3693 100644 --- a/org.eclipse.lsp4j.jsonrpc/src/test/java/org/eclipse/lsp4j/jsonrpc/test/json/MessageJsonHandlerTest.java +++ b/org.eclipse.lsp4j.jsonrpc/src/test/java/org/eclipse/lsp4j/jsonrpc/test/json/MessageJsonHandlerTest.java @@ -11,6 +11,9 @@ ******************************************************************************/ package org.eclipse.lsp4j.jsonrpc.test.json; +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -780,4 +783,66 @@ public void testNotification_AllOrders() { Assert.assertEquals("dummy://mymodel.mydsl", ((Location)params).uri); }); } + + + @Test + public void testParamUnwrap_JsonRpc2_0() { + MessageJsonHandler handler = createSimpleRequestHandler(String.class, Boolean.class); + + var request = new RequestMessage(); + request.setId(1); + request.setMethod(handler.getMethodProvider().resolveMethod(null)); + request.setParams(new boolean[] { true }); // fake wrapped primitive [true] for JsonRpc 2.0 + + RequestMessage message = (RequestMessage) handler.parseMessage(request.toString()); + + // Check parse - unwrap primitive + assertEquals(true, message.getParams()); + + } + + @Test + public void testArrayParamUnwrap_JsonRpc2_0() { + MessageJsonHandler handler = createSimpleRequestHandler(String.class, new TypeToken>() { + }.getType()); + + var request = "{\n" + + " \"jsonrpc\": \"2.0\",\n" + + " \"id\": 1,\n" + + " \"method\": \"testMethod\",\n" + + " \"params\": [\n" + + " [\n" + + " true\n" + + " ]\n" + + " ]\n" + + "}"; + RequestMessage message = (RequestMessage) handler.parseMessage(request); + + // Check parse - unwrap array + assertEquals(List.of(true), message.getParams()); + + } + + @Test + public void testMultiParamUnwrap_JsonRpc2_0() { + MessageJsonHandler handler = createSimpleRequestHandler(String.class, Boolean.class, String.class); + + var request = new RequestMessage(); + request.setId(1); + request.setMethod(handler.getMethodProvider().resolveMethod(null)); + request.setParams(List.of(true, "string")); // fake wrapped array [true, string] for JsonRpc 2.0 + + RequestMessage message = (RequestMessage) handler.parseMessage(request.toString()); + + // Check parse - unwrap array + assertEquals(request.getParams(), message.getParams()); + + } + + private static MessageJsonHandler createSimpleRequestHandler(Class returnType, Type... paramType) { + JsonRpcMethod requestMethod = JsonRpcMethod.request("testMethod", returnType, paramType); + MessageJsonHandler handler = new MessageJsonHandler(Map.of(requestMethod.getMethodName(), requestMethod)); + handler.setMethodProvider((id) -> requestMethod.getMethodName()); + return handler; + } }