diff --git a/modules/core/src/main/scala/jsonrpclib/internals/RawMessage.scala b/modules/core/src/main/scala/jsonrpclib/internals/RawMessage.scala index 62eaf0d..4ef588c 100644 --- a/modules/core/src/main/scala/jsonrpclib/internals/RawMessage.scala +++ b/modules/core/src/main/scala/jsonrpclib/internals/RawMessage.scala @@ -63,7 +63,7 @@ private[jsonrpclib] object RawMessage { "params" -> msg.params.asJson, "error" -> msg.error.asJson, "id" -> msg.id.asJson - ) ++ { + ).filterNot(_._2.isNull) ++ { msg.result match { case Some(Some(payload)) => List("result" -> payload.asJson) case Some(None) => List("result" -> Json.Null) diff --git a/modules/core/src/test/scala/jsonrpclib/RawMessageSpec.scala b/modules/core/src/test/scala/jsonrpclib/RawMessageSpec.scala index 11b2e5d..c1f3306 100644 --- a/modules/core/src/test/scala/jsonrpclib/RawMessageSpec.scala +++ b/modules/core/src/test/scala/jsonrpclib/RawMessageSpec.scala @@ -7,12 +7,13 @@ import jsonrpclib.CallId.NumberId import jsonrpclib.OutputMessage.ResponseMessage import io.circe.Json import com.github.plokhotnyuk.jsoniter_scala.circe.JsoniterScalaCodec._ +import io.circe.syntax._ object RawMessageSpec extends FunSuite { test("json parsing with null result") { // This is a perfectly valid response object, as result field has to be present, // but can be null: https://www.jsonrpc.org/specification#response_object - val rawMessage = readFromString[Json](""" {"jsonrpc":"2.0","result":null,"id":3} """.trim) + val rawMessage = readFromString[Json](""" {"jsonrpc":"2.0","id":3,"result":null}""".trim) .as[RawMessage] .fold(throw _, identity) @@ -31,4 +32,40 @@ object RawMessageSpec extends FunSuite { ) && assert(invalidRawMessage.toMessage.isLeft, invalidRawMessage.toMessage.toString) } + + test("request message serialization") { + val input: Message = InputMessage.RequestMessage("my/method", CallId.NumberId(1), None) + val expected = """{"jsonrpc":"2.0","method":"my/method","id":1}""" + val result = writeToString(input.asJson) + + assert(result == expected, s"Expected: $expected, got: $result") + } + + test("notification message serialization") { + val input: Message = InputMessage.NotificationMessage("my/method", None) + val expected = """{"jsonrpc":"2.0","method":"my/method"}""" + val result = writeToString(input.asJson) + + assert(result == expected, s"Expected: $expected, got: $result") + } + + test("response message serialization") { + val input: Message = OutputMessage.ResponseMessage(CallId.NumberId(1), Payload.NullPayload) + val expected = """{"jsonrpc":"2.0","id":1,"result":null}""" + val result = writeToString(input.asJson) + + assert(result == expected, s"Expected: $expected, got: $result") + } + + test("error message serialization") { + val input: Message = OutputMessage.ErrorMessage( + CallId.NumberId(1), + ErrorPayload(-32603, "Internal error", None) + ) + val expected = """{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}""" + val result = writeToString(input.asJson) + + assert(result == expected, s"Expected: $expected, got: $result") + } + }