Skip to content

Commit

Permalink
Handle methods with Void return types properly
Browse files Browse the repository at this point in the history
The DAP part of LSP4J was being too strict and failing to parse
response objects for methods with Void return type. With
Java 17 (or some version since Java 11) turning on more strict
reflection rules, the "An illegal reflective access operation
has occurred" that used to be a warning is now an exception
like "Failed making constructor 'java.lang.Void#Void()' accessible"

This change makes the code work and compatible with how LSP4J
handles LSP Void return types.

Fixes #674
  • Loading branch information
jonahgraham committed Oct 18, 2022
1 parent eb1f411 commit 6fe45e8
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ private Message createMessage(String messageType, int seq, int request_seq, Stri
if (typeAdapter != null)
body = typeAdapter.fromJsonTree(jsonElement);
else
body = gson.fromJson(jsonElement, returnType);
body = fromJson(jsonElement, returnType);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.reflect.TypeToken;

public class DebugMessageJsonHandlerTest {
Expand Down Expand Up @@ -848,4 +849,78 @@ public void testParseSyntaxErrorRequest() {
Assert.assertNotNull(messageIssue.getCause());
}
}

private Object voidResponse(String body) {
Map<String, JsonRpcMethod> supportedMethods = new LinkedHashMap<>();
supportedMethods.put("foo", JsonRpcMethod.request("foo", new TypeToken<Void>() {
}.getType(), new TypeToken<Void>() {
}.getType()));
DebugMessageJsonHandler handler = new DebugMessageJsonHandler(supportedMethods);
handler.setMethodProvider((id) -> "foo");

String bodyField = "";
if (body != null) {
bodyField = ",body:" + body;
}

// Do a call which should have a Void type, and the other end returns no body
Message message = handler.parseMessage("{\"seq\":10," //
+ "\"type\":\"response\"," //
+ "\"request_seq\":4," //
+ "\"command\":\"foo\"," //
+ "\"success\":true"//
+ bodyField //
+ "}\n");
return ((ResponseMessage) message).getResult();
}

@Test
public void testVoidResponse_noBody() {
Assert.assertNull(voidResponse(null));
}

@Test
public void testVoidResponse_null() {
Assert.assertNull(voidResponse("null"));

}

@Test
public void testVoidResponse_primitive() {
Object result = voidResponse("true");
JsonPrimitive jsonPrimitive = (JsonPrimitive) result;
Assert.assertTrue(jsonPrimitive.getAsBoolean());
}

@Test
public void testVoidResponse_emptyArray() {
Object result = voidResponse("[]");
JsonArray jsonArray = (JsonArray) result;
Assert.assertTrue(jsonArray.isEmpty());
}

@Test
public void testVoidResponse_array() {
Object result = voidResponse("[1,2,3]");
JsonArray jsonArray = (JsonArray) result;
Assert.assertEquals(1, jsonArray.get(0).getAsInt());
Assert.assertEquals(2, jsonArray.get(1).getAsInt());
Assert.assertEquals(3, jsonArray.get(2).getAsInt());
}

@Test
public void testVoidResponse_emptryObject() {
Object result = voidResponse("{}");
Assert.assertTrue(result instanceof JsonObject);
JsonObject jsonObject = (JsonObject) result;
Assert.assertTrue(jsonObject.entrySet().isEmpty());
}

@Test
public void testVoidResponse_object() {
Object result = voidResponse("{\"allThreadsContinued\":false}");
Assert.assertTrue(result instanceof JsonObject);
JsonObject jsonObject = (JsonObject) result;
Assert.assertFalse(jsonObject.getAsJsonPrimitive("allThreadsContinued").getAsBoolean());
}
}

0 comments on commit 6fe45e8

Please sign in to comment.