Skip to content

Commit db27a95

Browse files
henryjupisv
andauthored
Use configured gson instance for toString (#772)
This is important when users have registered custom type adapters Fixes #768 Co-authored-by: Vladimir Piskarev <[email protected]>
1 parent ce3af94 commit db27a95

File tree

20 files changed

+784
-28
lines changed

20 files changed

+784
-28
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Fixed issues: <https://github.com/eclipse-lsp4j/lsp4j/milestone/29?closed=1>
66

77
Breaking API changes:
88

9+
* The Message class now has a new transient field, `jsonHandler`, to enable the `toString` implementation to properly format messages when custom type adapters are used.
10+
* For consumers that have their own custom serializers or other reflective message processors they may need to be updated to ensure that transient fields are skipped, for example by using [`Modifier.isTransient`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/Modifier.html#isTransient(int))
11+
* See [#768](https://github.com/eclipse-lsp4j/lsp4j/issues/768) for detailed discussion.
912
* The name field in WorkspaceFolder is no longer optional according to the specification.
1013
* See [#741](https://github.com/eclipse-lsp4j/lsp4j/issues/741) for detailed discussion.
1114

org.eclipse.lsp4j.jsonrpc.debug/src/main/java/org/eclipse/lsp4j/jsonrpc/debug/DebugLauncher.java

+1
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ protected RemoteEndpoint createRemoteEndpoint(MessageJsonHandler jsonHandler) {
218218
else
219219
remoteEndpoint = new DebugRemoteEndpoint(outgoingMessageStream, localEndpoint, exceptionHandler);
220220
jsonHandler.setMethodProvider(remoteEndpoint);
221+
remoteEndpoint.setJsonHandler(jsonHandler);
221222
return remoteEndpoint;
222223
}
223224

org.eclipse.lsp4j.jsonrpc.debug/src/main/java/org/eclipse/lsp4j/jsonrpc/debug/DebugRemoteEndpoint.java

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public DebugRemoteEndpoint(MessageConsumer out, Endpoint localEndpoint,
3838
@Override
3939
protected DebugRequestMessage createRequestMessage(String method, Object parameter) {
4040
DebugRequestMessage requestMessage = new DebugRequestMessage();
41+
requestMessage.setJsonHandler(getJsonHandler());
4142
requestMessage.setId(nextSeqId.incrementAndGet());
4243
requestMessage.setMethod(method);
4344
requestMessage.setParams(parameter);
@@ -47,6 +48,7 @@ protected DebugRequestMessage createRequestMessage(String method, Object paramet
4748
@Override
4849
protected DebugResponseMessage createResponseMessage(RequestMessage requestMessage) {
4950
DebugResponseMessage responseMessage = new DebugResponseMessage();
51+
responseMessage.setJsonHandler(getJsonHandler());
5052
responseMessage.setResponseId(nextSeqId.incrementAndGet());
5153
responseMessage.setRawId(requestMessage.getRawId());
5254
responseMessage.setMethod(requestMessage.getMethod());
@@ -56,6 +58,7 @@ protected DebugResponseMessage createResponseMessage(RequestMessage requestMessa
5658
@Override
5759
protected DebugNotificationMessage createNotificationMessage(String method, Object parameter) {
5860
DebugNotificationMessage notificationMessage = new DebugNotificationMessage();
61+
notificationMessage.setJsonHandler(getJsonHandler());
5962
notificationMessage.setId(nextSeqId.incrementAndGet());
6063
notificationMessage.setMethod(method);
6164
notificationMessage.setParams(parameter);

org.eclipse.lsp4j.jsonrpc.debug/src/main/java/org/eclipse/lsp4j/jsonrpc/debug/adapters/DebugMessageTypeAdapter.java

+3
Original file line numberDiff line numberDiff line change
@@ -343,20 +343,23 @@ private Message createMessage(String messageType, int seq, int request_seq, Stri
343343
switch (messageType) {
344344
case "request": {
345345
DebugRequestMessage message = new DebugRequestMessage();
346+
message.setJsonHandler(handler);
346347
message.setId(seq);
347348
message.setMethod(method);
348349
message.setParams(params);
349350
return message;
350351
}
351352
case "event": {
352353
DebugNotificationMessage message = new DebugNotificationMessage();
354+
message.setJsonHandler(handler);
353355
message.setId(seq);
354356
message.setMethod(method);
355357
message.setParams(body);
356358
return message;
357359
}
358360
case "response": {
359361
DebugResponseMessage message = new DebugResponseMessage();
362+
message.setJsonHandler(handler);
360363
message.setId(request_seq);
361364
message.setResponseId(seq);
362365
message.setMethod(method);

org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/Launcher.java

+4
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@ public Launcher<T> create() {
317317

318318
// Create the JSON handler, remote endpoint and remote proxy
319319
MessageJsonHandler jsonHandler = createJsonHandler();
320+
if (messageTracer != null) {
321+
messageTracer.setJsonHandler(jsonHandler);
322+
}
320323
RemoteEndpoint remoteEndpoint = createRemoteEndpoint(jsonHandler);
321324
T remoteProxy = createProxy(remoteEndpoint);
322325

@@ -352,6 +355,7 @@ protected RemoteEndpoint createRemoteEndpoint(MessageJsonHandler jsonHandler) {
352355
else
353356
remoteEndpoint = new RemoteEndpoint(outgoingMessageStream, localEndpoint, exceptionHandler);
354357
jsonHandler.setMethodProvider(remoteEndpoint);
358+
remoteEndpoint.setJsonHandler(jsonHandler);
355359
return remoteEndpoint;
356360
}
357361

org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/MessageTracer.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@
1111
******************************************************************************/
1212
package org.eclipse.lsp4j.jsonrpc;
1313

14-
import org.eclipse.lsp4j.jsonrpc.TracingMessageConsumer.RequestMetadata;
15-
1614
import java.io.PrintWriter;
1715
import java.time.Clock;
1816
import java.util.HashMap;
1917
import java.util.Map;
2018
import java.util.Objects;
2119
import java.util.function.Function;
2220

21+
import org.eclipse.lsp4j.jsonrpc.TracingMessageConsumer.RequestMetadata;
22+
import org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler;
23+
2324
/**
2425
* Wraps a {@link MessageConsumer} with one that logs in a way that the LSP Inspector can parse. *
2526
* https://microsoft.github.io/language-server-protocol/inspector/
@@ -28,14 +29,21 @@ public class MessageTracer implements Function<MessageConsumer, MessageConsumer>
2829
private final PrintWriter printWriter;
2930
private final Map<String, RequestMetadata> sentRequests = new HashMap<>();
3031
private final Map<String, RequestMetadata> receivedRequests = new HashMap<>();
32+
private MessageJsonHandler jsonHandler;
3133

3234
MessageTracer(PrintWriter printWriter) {
3335
this.printWriter = Objects.requireNonNull(printWriter);
3436
}
3537

38+
public void setJsonHandler(MessageJsonHandler jsonHandler) {
39+
this.jsonHandler = jsonHandler;
40+
}
41+
3642
@Override
3743
public MessageConsumer apply(MessageConsumer messageConsumer) {
38-
return new TracingMessageConsumer(
44+
TracingMessageConsumer tracingMessageConsumer = new TracingMessageConsumer(
3945
messageConsumer, sentRequests, receivedRequests, printWriter, Clock.systemDefaultZone());
46+
tracingMessageConsumer.setJsonHandler(jsonHandler);
47+
return tracingMessageConsumer;
4048
}
4149
}

org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/RemoteEndpoint.java

+12
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ private static ResponseError fallbackResponseError(String header, Throwable thro
7474
private final MessageConsumer out;
7575
private final Endpoint localEndpoint;
7676
private final Function<Throwable, ResponseError> exceptionHandler;
77+
private MessageJsonHandler jsonHandler;
7778

7879
private final AtomicInteger nextRequestId = new AtomicInteger();
7980
private final Map<String, PendingRequestInfo> sentRequestMap = new LinkedHashMap<>();
@@ -116,6 +117,14 @@ public RemoteEndpoint(MessageConsumer out, Endpoint localEndpoint) {
116117
this(out, localEndpoint, DEFAULT_EXCEPTION_HANDLER);
117118
}
118119

120+
public void setJsonHandler(MessageJsonHandler jsonHandler) {
121+
this.jsonHandler = jsonHandler;
122+
}
123+
124+
public MessageJsonHandler getJsonHandler() {
125+
return jsonHandler;
126+
}
127+
119128
/**
120129
* Send a notification to the remote endpoint.
121130
*/
@@ -132,6 +141,7 @@ public void notify(String method, Object parameter) {
132141

133142
protected NotificationMessage createNotificationMessage(String method, Object parameter) {
134143
NotificationMessage notificationMessage = new NotificationMessage();
144+
notificationMessage.setJsonHandler(getJsonHandler());
135145
notificationMessage.setJsonrpc(MessageConstants.JSONRPC_VERSION);
136146
notificationMessage.setMethod(method);
137147
notificationMessage.setParams(parameter);
@@ -168,6 +178,7 @@ public boolean cancel(boolean mayInterruptIfRunning) {
168178

169179
protected RequestMessage createRequestMessage(String method, Object parameter) {
170180
RequestMessage requestMessage = new RequestMessage();
181+
requestMessage.setJsonHandler(getJsonHandler());
171182
requestMessage.setId(String.valueOf(nextRequestId.incrementAndGet()));
172183
requestMessage.setMethod(method);
173184
requestMessage.setParams(parameter);
@@ -361,6 +372,7 @@ protected void handleResponseIssues(ResponseMessage responseMessage, List<Messag
361372

362373
protected ResponseMessage createResponseMessage(RequestMessage requestMessage) {
363374
ResponseMessage responseMessage = new ResponseMessage();
375+
responseMessage.setJsonHandler(getJsonHandler());
364376
responseMessage.setRawId(requestMessage.getRawId());
365377
responseMessage.setJsonrpc(MessageConstants.JSONRPC_VERSION);
366378
return responseMessage;

org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/TracingMessageConsumer.java

+20-11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class TracingMessageConsumer implements MessageConsumer {
4242
private final PrintWriter printWriter;
4343
private final Clock clock;
4444
private final DateTimeFormatter dateTimeFormatter;
45+
private MessageJsonHandler jsonHandler;
4546

4647
/**
4748
* @param messageConsumer The {@link MessageConsumer} to wrap.
@@ -86,6 +87,10 @@ public TracingMessageConsumer(
8687
}
8788
}
8889

90+
public void setJsonHandler(MessageJsonHandler jsonHandler) {
91+
this.jsonHandler = jsonHandler;
92+
}
93+
8994
/**
9095
* Constructs a log string for a given {@link Message}. The type of the {@link MessageConsumer}
9196
* determines if we're sending or receiving a message. The type of the @{link Message} determines
@@ -122,33 +127,33 @@ private String consumeMessageSending(Message message, Instant now, String date)
122127
RequestMetadata requestMetadata = new RequestMetadata(method, now);
123128
sentRequests.put(id, requestMetadata);
124129
Object params = requestMessage.getParams();
125-
String paramsJson = MessageJsonHandler.toString(params);
130+
String paramsJson = toString(params);
126131
String format = "[Trace - %s] Sending request '%s - (%s)'\nParams: %s\n\n\n";
127132
return String.format(format, date, method, id, paramsJson);
128133
} else if (message instanceof ResponseMessage) {
129134
ResponseMessage responseMessage = (ResponseMessage) message;
130135
String id = responseMessage.getId();
131136
RequestMetadata requestMetadata = receivedRequests.remove(id);
132137
if (requestMetadata == null) {
133-
LOG.log(WARNING, String.format("Unmatched response message: %s", message));
138+
LOG.log(WARNING, String.format("Unmatched response message: %s", toString(message)));
134139
return null;
135140
}
136141
String method = requestMetadata.method;
137142
long latencyMillis = now.toEpochMilli() - requestMetadata.start.toEpochMilli();
138143
Object result = responseMessage.getResult();
139-
String resultJson = MessageJsonHandler.toString(result);
144+
String resultJson = toString(result);
140145
String format =
141146
"[Trace - %s] Sending response '%s - (%s)'. Processing request took %sms\nResult: %s\n\n\n";
142147
return String.format(format, date, method, id, latencyMillis, resultJson);
143148
} else if (message instanceof NotificationMessage) {
144149
NotificationMessage notificationMessage = (NotificationMessage) message;
145150
String method = notificationMessage.getMethod();
146151
Object params = notificationMessage.getParams();
147-
String paramsJson = MessageJsonHandler.toString(params);
152+
String paramsJson = toString(params);
148153
String format = "[Trace - %s] Sending notification '%s'\nParams: %s\n\n\n";
149154
return String.format(format, date, method, paramsJson);
150155
} else {
151-
LOG.log(WARNING, String.format("Unknown message type: %s", message));
156+
LOG.log(WARNING, String.format("Unknown message type: %s", toString(message)));
152157
return null;
153158
}
154159
}
@@ -161,38 +166,42 @@ private String consumeMessageReceiving(Message message, Instant now, String date
161166
RequestMetadata requestMetadata = new RequestMetadata(method, now);
162167
receivedRequests.put(id, requestMetadata);
163168
Object params = requestMessage.getParams();
164-
String paramsJson = MessageJsonHandler.toString(params);
169+
String paramsJson = toString(params);
165170
String format = "[Trace - %s] Received request '%s - (%s)'\nParams: %s\n\n\n";
166171
return String.format(format, date, method, id, paramsJson);
167172
} else if (message instanceof ResponseMessage) {
168173
ResponseMessage responseMessage = (ResponseMessage) message;
169174
String id = responseMessage.getId();
170175
RequestMetadata requestMetadata = sentRequests.remove(id);
171176
if (requestMetadata == null) {
172-
LOG.log(WARNING, String.format("Unmatched response message: %s", message));
177+
LOG.log(WARNING, String.format("Unmatched response message: %s", toString(message)));
173178
return null;
174179
}
175180
String method = requestMetadata.method;
176181
long latencyMillis = now.toEpochMilli() - requestMetadata.start.toEpochMilli();
177182
Object result = responseMessage.getResult();
178-
String resultJson = MessageJsonHandler.toString(result);
183+
String resultJson = toString(result);
179184
Object error = responseMessage.getError();
180-
String errorJson = MessageJsonHandler.toString(error);
185+
String errorJson = toString(error);
181186
String format = "[Trace - %s] Received response '%s - (%s)' in %sms\nResult: %s\nError: %s\n\n\n";
182187
return String.format(format, date, method, id, latencyMillis, resultJson, errorJson);
183188
} else if (message instanceof NotificationMessage) {
184189
NotificationMessage notificationMessage = (NotificationMessage) message;
185190
String method = notificationMessage.getMethod();
186191
Object params = notificationMessage.getParams();
187-
String paramsJson = MessageJsonHandler.toString(params);
192+
String paramsJson = toString(params);
188193
String format = "[Trace - %s] Received notification '%s'\nParams: %s\n\n\n";
189194
return String.format(format, date, method, paramsJson);
190195
} else {
191-
LOG.log(WARNING, String.format("Unknown message type: %s", message));
196+
LOG.log(WARNING, String.format("Unknown message type: %s", toString(message)));
192197
return null;
193198
}
194199
}
195200

201+
private String toString(Object object) {
202+
return jsonHandler != null ? jsonHandler.format(object) : MessageJsonHandler.toString(object);
203+
}
204+
196205
/** Data class for holding pending request metadata. */
197206
public static class RequestMetadata {
198207
final String method;

org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/json/MessageJsonHandler.java

+31-5
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@
3535
import com.google.gson.Gson;
3636
import com.google.gson.GsonBuilder;
3737
import com.google.gson.JsonIOException;
38+
import com.google.gson.JsonNull;
3839
import com.google.gson.JsonParseException;
3940
import com.google.gson.stream.JsonReader;
4041
import com.google.gson.stream.JsonToken;
42+
import com.google.gson.stream.JsonWriter;
4143
import com.google.gson.stream.MalformedJsonException;
4244

4345
/**
@@ -48,7 +50,7 @@ public class MessageJsonHandler {
4850
public static final JsonRpcMethod CANCEL_METHOD = JsonRpcMethod.notification("$/cancelRequest", CancelParams.class);
4951

5052
private final Gson gson;
51-
53+
5254
private final Map<String, JsonRpcMethod> supportedMethods;
5355

5456
private MethodProvider methodProvider;
@@ -119,6 +121,8 @@ public Message parseMessage(Reader input) throws JsonParseException {
119121
Message message = gson.fromJson(jsonReader, Message.class);
120122

121123
if (message != null) {
124+
message.setJsonHandler(this);
125+
122126
// Check whether the input has been fully consumed
123127
try {
124128
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
@@ -144,10 +148,32 @@ public String serialize(Message message) {
144148
public void serialize(Message message, Writer output) throws JsonIOException {
145149
gson.toJson(message, Message.class, output);
146150
}
147-
148-
151+
152+
/**
153+
* Perform JSON serialization of the given object using the configuration of JSON-RPC messages
154+
* enhanced with the pretty printing option.
155+
*/
156+
public String format(Object object) {
157+
StringWriter writer = new StringWriter();
158+
JsonWriter jsonWriter = null;
159+
try {
160+
jsonWriter = gson.newJsonWriter(writer);
161+
// Equivalent to set pretty printing on the gson builder
162+
jsonWriter.setIndent(" ");
163+
} catch (IOException e) {
164+
throw new JsonIOException(e);
165+
}
166+
if (object != null) {
167+
gson.toJson(object, object.getClass(), jsonWriter);
168+
} else {
169+
gson.toJson(JsonNull.INSTANCE, jsonWriter);
170+
}
171+
return writer.toString();
172+
}
173+
174+
149175
private static MessageJsonHandler toStringInstance;
150-
176+
151177
/**
152178
* Perform JSON serialization of the given object using the default configuration of JSON-RPC messages
153179
* enhanced with the pretty printing option.
@@ -160,5 +186,5 @@ public static String toString(Object object) {
160186
}
161187
return toStringInstance.gson.toJson(object);
162188
}
163-
189+
164190
}

org.eclipse.lsp4j.jsonrpc/src/main/java/org/eclipse/lsp4j/jsonrpc/json/adapters/MessageTypeAdapter.java

+3
Original file line numberDiff line numberDiff line change
@@ -379,13 +379,15 @@ protected Message createMessage(String jsonrpc, Either<String, Number> id, Strin
379379
Object responseResult, ResponseError responseError) throws JsonParseException {
380380
if (id != null && method != null) {
381381
RequestMessage message = new RequestMessage();
382+
message.setJsonHandler(handler);
382383
message.setJsonrpc(jsonrpc);
383384
message.setRawId(id);
384385
message.setMethod(method);
385386
message.setParams(params);
386387
return message;
387388
} else if (id != null) {
388389
ResponseMessage message = new ResponseMessage();
390+
message.setJsonHandler(handler);
389391
message.setJsonrpc(jsonrpc);
390392
message.setRawId(id);
391393
if (responseError != null)
@@ -395,6 +397,7 @@ protected Message createMessage(String jsonrpc, Either<String, Number> id, Strin
395397
return message;
396398
} else if (method != null) {
397399
NotificationMessage message = new NotificationMessage();
400+
message.setJsonHandler(handler);
398401
message.setJsonrpc(jsonrpc);
399402
message.setMethod(method);
400403
message.setParams(params);

0 commit comments

Comments
 (0)