jsonrpc: Skip serializing params if params are None (#5471)

The JSONRPC spec says:

> If present, parameters for the rpc call MUST be provided as a
> Structured value

https://www.jsonrpc.org/specification#parameter_structures

(Where a "Structured value" is elsewhere defined as either a map or
array.)

This change skips the serialization of the `params` field for JSONRPC
method calls and notifications if the `params` field is the `None`
variant. This fixes compatibility with LSP servers which adhere closely
to that part of the spec: `ocamllsp` in the wild.
This commit is contained in:
Michael Davis 2023-01-10 03:31:41 -06:00 committed by GitHub
parent 2d601d6a59
commit 22298434f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -170,6 +170,10 @@ impl Params {
serde_json::from_value(value)
.map_err(|err| Error::invalid_params(format!("Invalid params: {}.", err)))
}
pub fn is_none(&self) -> bool {
self == &Params::None
}
}
impl From<Params> for Value {
@ -187,7 +191,7 @@ impl From<Params> for Value {
pub struct MethodCall {
pub jsonrpc: Option<Version>,
pub method: String,
#[serde(default = "default_params")]
#[serde(default = "default_params", skip_serializing_if = "Params::is_none")]
pub params: Params,
pub id: Id,
}
@ -197,7 +201,7 @@ pub struct MethodCall {
pub struct Notification {
pub jsonrpc: Option<Version>,
pub method: String,
#[serde(default = "default_params")]
#[serde(default = "default_params", skip_serializing_if = "Params::is_none")]
pub params: Params,
}
@ -334,6 +338,33 @@ fn notification_serialize() {
);
}
#[test]
fn serialize_skip_none_params() {
use serde_json;
let m = MethodCall {
jsonrpc: Some(Version::V2),
method: "shutdown".to_owned(),
params: Params::None,
id: Id::Num(1),
};
let serialized = serde_json::to_string(&m).unwrap();
assert_eq!(
serialized,
r#"{"jsonrpc":"2.0","method":"shutdown","id":1}"#
);
let n = Notification {
jsonrpc: Some(Version::V2),
method: "exit".to_owned(),
params: Params::None,
};
let serialized = serde_json::to_string(&n).unwrap();
assert_eq!(serialized, r#"{"jsonrpc":"2.0","method":"exit"}"#);
}
#[test]
fn success_output_deserialize() {
use serde_json;