Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap primitive and array parameter into an array as in JSON-RPC 2.0 #718

Merged
merged 1 commit into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

Expand Down Expand Up @@ -42,6 +43,7 @@
import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.internal.Primitives;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dhuebner Can you please have a look at #738 in relation to this new package dependency?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonahgraham
Sure, will do. Thanks!

import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
Expand Down Expand Up @@ -420,7 +422,7 @@ public void write(JsonWriter out, Message message) throws IOException {
if (params == null)
writeNullValue(out);
else
gson.toJson(params, params.getClass(), out);
handleParameter(out, params, requestMessage.getMethod());
} else if (message instanceof ResponseMessage) {
ResponseMessage responseMessage = (ResponseMessage) message;
out.name("id");
Expand All @@ -445,12 +447,24 @@ public void write(JsonWriter out, Message message) throws IOException {
if (params == null)
writeNullValue(out);
else
gson.toJson(params, params.getClass(), out);
handleParameter(out, params, notificationMessage.getMethod());
}

out.endObject();
}

protected void handleParameter(JsonWriter out, Object params, String method) {
boolean isSingleArray = (getParameterTypes(method).length == 1 && Collection.class.isInstance(params)
|| params.getClass().isArray());
boolean needsWrap = isSingleArray || params instanceof String || Primitives.isPrimitive(getClass())
|| Primitives.isWrapperType(params.getClass());
if (needsWrap) {
gson.toJson(List.of(params), List.class, out);
} else {
gson.toJson(params, params.getClass(), out);
}
}

protected void writeId(JsonWriter out, Either<String, Number> id) throws IOException {
if (id == null)
writeNullValue(out);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -786,59 +786,140 @@ public void testNotification_AllOrders() {


@Test
public void testParamUnwrap_JsonRpc2_0() {
MessageJsonHandler handler = createSimpleRequestHandler(String.class, Boolean.class);
public void testWrapPrimitive_JsonRpc2_0() {
MessageJsonHandler handler = createSimpleRequestHandler(String.class, String.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());

request.setParams("param");

// check primitive was wrapped into array
assertEquals("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"testMethod\",\"params\":[\"param\"]}", handler.serialize(request));
}

@Test
public void testUnwrapPrimitive_JsonRpc2_0() {
MessageJsonHandler handler = createSimpleRequestHandler(String.class, String.class);
var request = "{\n"
+ " \"jsonrpc\": \"2.0\",\n"
+ " \"id\": 1,\n"
+ " \"method\": \"testMethod\",\n"
+ " \"params\": [\n"
+ " \"param\"\n"
+ " ]\n"
+ "}";
// Check parse - unwrap primitive
assertEquals(true, message.getParams());

RequestMessage message = (RequestMessage) handler.parseMessage(request);
assertEquals("param", message.getParams());
}

@Test
public void testArrayParamUnwrap_JsonRpc2_0() {
public void testWrapArray_JsonRpc2_0() {
MessageJsonHandler handler = createSimpleRequestHandler(String.class, new TypeToken<List<Boolean>>() {
}.getType());

var request = new RequestMessage();
request.setId(1);
request.setMethod(handler.getMethodProvider().resolveMethod(null));
request.setParams(List.of(true,false));

// check primitive was wrapped into array
assertEquals("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"testMethod\",\"params\":[[true,false]]}", handler.serialize(request));

}

@Test
public void testUnwrapArray_JsonRpc2_0() {
MessageJsonHandler handler = createSimpleRequestHandler(String.class, new TypeToken<List<Boolean>>() {
}.getType());

var request = "{\n"
+ " \"jsonrpc\": \"2.0\",\n"
+ " \"id\": 1,\n"
+ " \"method\": \"testMethod\",\n"
+ " \"params\": [\n"
+ " [\n"
+ " true\n"
+ " true, false\n"
+ " ]\n"
+ " ]\n"
+ "}";
RequestMessage message = (RequestMessage) handler.parseMessage(request);

// Check parse - unwrap array
assertEquals(List.of(true), message.getParams());
assertEquals(List.of(true, false), message.getParams());

}

@Test
public void testWrapMultipleParams_JsonRpc2_0() {
MessageJsonHandler handler = createSimpleRequestHandler(String.class, Boolean.class, String.class);

var request = new RequestMessage();
request.setMethod(handler.getMethodProvider().resolveMethod(null));
request.setParams(List.of(true, "param2"));
// Check serialize - wrap primitive wrapper
assertEquals("{\"jsonrpc\":\"2.0\",\"id\":null,\"method\":\"testMethod\",\"params\":[true,\"param2\"]}",
handler.serialize(request));

}

@Test
public void testMultiParamUnwrap_JsonRpc2_0() {
public void testUnwrapMultipleParams_JsonRpc2_0() {
MessageJsonHandler handler = createSimpleRequestHandler(String.class, Boolean.class, String.class);

var request = "{\n"
+ " \"jsonrpc\": \"2.0\",\n"
+ " \"id\": 1,\n"
+ " \"method\": \"testMethod\",\n"
+ " \"params\": [\n"
+ " true,\n"
+ " \"param2\"\n"
+ " ]\n"
+ "}";
RequestMessage message = (RequestMessage) handler.parseMessage(request);

// Check parse - unwrap array
assertEquals(List.of(true, "param2"), message.getParams());

}
@Test
public void testWrapMultipleParamsWithArray_JsonRpc2_0() {
MessageJsonHandler handler = createSimpleRequestHandler(String.class, new TypeToken<List<Boolean>>() {
}.getType(), 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
request.setParams(List.of(List.of(true, false), "param2"));
// Check serialize - wrap primitive wrapper
assertEquals("{\"jsonrpc\":\"2.0\",\"id\":null,\"method\":\"testMethod\",\"params\":[[true,false],\"param2\"]}",
handler.serialize(request));

}

@Test
public void testUnwrapMultipleParamsWithArray_JsonRpc2_0() {
MessageJsonHandler handler = createSimpleRequestHandler(String.class, new TypeToken<List<Boolean>>() {
}.getType(), String.class);

RequestMessage message = (RequestMessage) handler.parseMessage(request.toString());
var request = "{\n"
+ " \"jsonrpc\": \"2.0\",\n"
+ " \"id\": 1,\n"
+ " \"method\": \"testMethod\",\n"
+ " \"params\": [\n"
+ " [\n"
+ " true,\n"
+ " false\n"
+ " ],\n"
+ " \"param2\"\n"
+ " ]\n"
+ "}";
RequestMessage message = (RequestMessage) handler.parseMessage(request);

// Check parse - unwrap array
assertEquals(request.getParams(), message.getParams());
assertEquals(List.of(List.of(true, false),"param2"), 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));
Expand Down