This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit e09b9fe29ac5349047eb88fa13d98d1c4de1edda
Author: James Bognar <[email protected]>
AuthorDate: Tue Jul 28 16:14:55 2026 -0400

    feat: add JsonRpcResponse.notification/ok/errorResponse static helpers
    
    Ports the neutral response-construction helpers out of McpDispatcher's 
privates
    onto the envelope bean itself. notification(Object) is a predicate, not a 
factory
    (matching the original private static); errorResponse keeps its 4-arg form 
so the
    internal-error path's error.data survives, with a 3-arg convenience 
overload.
    
    Co-authored-by: Cursor <[email protected]>
---
 .../juneau/bean/jsonrpc/JsonRpcResponse.java       | 58 +++++++++++++
 .../juneau/bean/jsonrpc/JsonRpcBeans_Test.java     | 94 ++++++++++++++++++++++
 2 files changed, 152 insertions(+)

diff --git 
a/juneau-bean/juneau-bean-jsonrpc/src/main/java/org/apache/juneau/bean/jsonrpc/JsonRpcResponse.java
 
b/juneau-bean/juneau-bean-jsonrpc/src/main/java/org/apache/juneau/bean/jsonrpc/JsonRpcResponse.java
index 0e4a38628c..6fdf4b2f1a 100644
--- 
a/juneau-bean/juneau-bean-jsonrpc/src/main/java/org/apache/juneau/bean/jsonrpc/JsonRpcResponse.java
+++ 
b/juneau-bean/juneau-bean-jsonrpc/src/main/java/org/apache/juneau/bean/jsonrpc/JsonRpcResponse.java
@@ -27,6 +27,8 @@ import org.apache.juneau.marshall.*;
 @Marshalled
 public class JsonRpcResponse {
 
+       private static final String JSONRPC_2_0 = "2.0";
+
        private String jsonrpc;
        private Object id;
        private Object result;
@@ -111,4 +113,60 @@ public class JsonRpcResponse {
                error = value;
                return this;
        }
+
+       /**
+        * Tests whether a JSON-RPC id identifies a notification (a request 
that must not be answered).
+        *
+        * <p>
+        * A JSON-RPC request with no {@code id} is a notification; the server 
performs the work and returns
+        * no response body.
+        *
+        * @param id The request id. Can be <jk>null</jk>.
+        * @return <jk>true</jk> if the id is <jk>null</jk>.
+        */
+       public static boolean notification(Object id) {
+               return id == null;
+       }
+
+       /**
+        * Creates a JSON-RPC 2.0 success response.
+        *
+        * @param id The request id to correlate against. Can be <jk>null</jk>.
+        * @param result The result payload. Can be <jk>null</jk>.
+        * @return A new response object. Never <jk>null</jk>.
+        */
+       public static JsonRpcResponse ok(Object id, Object result) {
+               return new JsonRpcResponse()
+                       .setJsonrpc(JSONRPC_2_0)
+                       .setId(id)
+                       .setResult(result);
+       }
+
+       /**
+        * Creates a JSON-RPC 2.0 error response with no structured error data.
+        *
+        * @param id The request id to correlate against. Can be <jk>null</jk>.
+        * @param code The JSON-RPC error code.
+        * @param message The error message. Can be <jk>null</jk>.
+        * @return A new response object. Never <jk>null</jk>.
+        */
+       public static JsonRpcResponse errorResponse(Object id, int code, String 
message) {
+               return errorResponse(id, code, message, null);
+       }
+
+       /**
+        * Creates a JSON-RPC 2.0 error response.
+        *
+        * @param id The request id to correlate against. Can be <jk>null</jk>.
+        * @param code The JSON-RPC error code.
+        * @param message The error message. Can be <jk>null</jk>.
+        * @param data Optional structured error data. Can be <jk>null</jk> to 
leave the property unset.
+        * @return A new response object. Never <jk>null</jk>.
+        */
+       public static JsonRpcResponse errorResponse(Object id, int code, String 
message, Object data) {
+               return new JsonRpcResponse()
+                       .setJsonrpc(JSONRPC_2_0)
+                       .setId(id)
+                       .setError(new 
JsonRpcError().setCode(code).setMessage(message).setData(data));
+       }
 }
diff --git 
a/juneau-bean/juneau-bean-jsonrpc/src/test/java/org/apache/juneau/bean/jsonrpc/JsonRpcBeans_Test.java
 
b/juneau-bean/juneau-bean-jsonrpc/src/test/java/org/apache/juneau/bean/jsonrpc/JsonRpcBeans_Test.java
new file mode 100644
index 0000000000..2fe0997f13
--- /dev/null
+++ 
b/juneau-bean/juneau-bean-jsonrpc/src/test/java/org/apache/juneau/bean/jsonrpc/JsonRpcBeans_Test.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau.bean.jsonrpc;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.apache.juneau.marshall.collections.*;
+import org.apache.juneau.marshall.json.*;
+import org.junit.jupiter.api.*;
+
+/**
+ * Coverage for the JSON-RPC 2.0 envelope beans and {@link JsonRpcResponse}'s 
static helpers.
+ */
+class JsonRpcBeans_Test {
+
+       private static void assertRoundTrip(Object bean, Class<?> type) {
+               var a = JsonSerializer.DEFAULT.write(bean);
+               var b = JsonSerializer.DEFAULT.write(JsonParser.DEFAULT.read(a, 
type));
+               assertEquals(a, b, () -> "Round-trip JSON mismatch for " + 
type.getName() + ": " + a);
+       }
+
+       @Test
+       void a01_request_roundTrip() {
+               var a = new 
JsonRpcRequest().setJsonrpc("2.0").setId("abc").setMethod("tools/list").setParams(JsonMap.of("cursor",
 "1"));
+               assertRoundTrip(a, JsonRpcRequest.class);
+       }
+
+       @Test
+       void a02_response_resultRoundTrip() {
+               var a = new 
JsonRpcResponse().setJsonrpc("2.0").setId(42).setResult(JsonMap.of("x", 1));
+               assertRoundTrip(a, JsonRpcResponse.class);
+       }
+
+       @Test
+       void a03_response_errorRoundTrip() {
+               var a = new JsonRpcResponse().setJsonrpc("2.0").setId(7)
+                       .setError(new 
JsonRpcError().setCode(-32600).setMessage("Invalid 
Request").setData(JsonMap.of("detail", "x")));
+               assertRoundTrip(a, JsonRpcResponse.class);
+       }
+
+       @Test
+       void a04_error_roundTrip() {
+               assertRoundTrip(new 
JsonRpcError().setCode(-32603).setMessage("boom").setData(JsonMap.of("type", 
"X")), JsonRpcError.class);
+       }
+
+       @Test
+       void b01_notification_isNullId() {
+               assertTrue(JsonRpcResponse.notification(null));
+               assertFalse(JsonRpcResponse.notification(1));
+               assertFalse(JsonRpcResponse.notification("abc"));
+       }
+
+       @Test
+       void b02_ok_setsVersionIdAndResult() {
+               var a = JsonRpcResponse.ok(1, JsonMap.of("k", "v"));
+               assertEquals("2.0", a.getJsonrpc());
+               assertEquals(1, a.getId());
+               assertNotNull(a.getResult());
+               assertNull(a.getError());
+       }
+
+       @Test
+       void b03_errorResponse_fourArg_carriesData() {
+               var a = JsonRpcResponse.errorResponse(1, -32603, "boom", 
JsonMap.of("type", "X"));
+               assertEquals("2.0", a.getJsonrpc());
+               assertEquals(1, a.getId());
+               assertNull(a.getResult());
+               assertEquals(-32603, a.getError().getCode());
+               assertEquals("boom", a.getError().getMessage());
+               assertNotNull(a.getError().getData());
+       }
+
+       @Test
+       void b04_errorResponse_threeArg_leavesDataNull() {
+               var a = JsonRpcResponse.errorResponse(null, -32600, "Request 
envelope is null");
+               assertNull(a.getId());
+               assertEquals(-32600, a.getError().getCode());
+               assertNull(a.getError().getData());
+       }
+}

Reply via email to