Skip to content

JSON-RPC Request Builder — Java source

Build valid JSON-RPC 2.0 requests, notifications, success responses, and error responses, plus batch arrays. Validate message structure.

This is the Java implementation — the same logic the interactive tool runs, in a shareable, citable form.

// json-rpc-builder — Java port: JSON-RPC 2.0 message builder + structural validation.

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class JsonRpc {
    static final String VERSION = "2.0";
    /** Sentinel telling "argument absent" apart from a legitimate JSON null. */
    static final Object UNSET = new Object();
    record Outcome(boolean ok, String json, String error) {}
    static String standardError(int code) {
        return switch (code) {
            case -32700 -> "Parse error";      case -32600 -> "Invalid Request";
            case -32601 -> "Method not found"; case -32602 -> "Invalid params";
            case -32603 -> "Internal error";   case -32000 -> "Server error";
            default -> "Error";
        };
    }
    /** Minimal JSON writer — insertion-ordered Map, List, String, Number, Boolean, null. */
    static String toJson(Object v) {
        if (v == null) return "null";
        if (v instanceof String s) return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
        if (v instanceof Number || v instanceof Boolean) return v.toString();
        if (v instanceof List<?> l)
            return l.stream().map(JsonRpc::toJson).collect(Collectors.joining(",", "[", "]"));
        return ((Map<?, ?>) v).entrySet().stream()
                .map(e -> toJson(e.getKey().toString()) + ":" + toJson(e.getValue()))
                .collect(Collectors.joining(",", "{", "}"));
    }
    static Outcome buildRequest(String method, Object params, Object id) {
        if (method == null || method.isEmpty())
            return new Outcome(false, "", "method must be a non-empty string");
        Map<String, Object> obj = new LinkedHashMap<>();
        obj.put("jsonrpc", VERSION); obj.put("method", method);
        if (params != UNSET) obj.put("params", params);  // a passed null is a real JSON null
        obj.put("id", id);
        return new Outcome(true, toJson(obj), null);
    }
    /** A notification is a request without an id: fire-and-forget, no reply. */
    static Outcome buildNotification(String method, Object params) {
        if (method == null || method.isEmpty())
            return new Outcome(false, "", "method must be a non-empty string");
        Map<String, Object> obj = new LinkedHashMap<>();
        obj.put("jsonrpc", VERSION); obj.put("method", method);
        if (params != UNSET) obj.put("params", params);
        return new Outcome(true, toJson(obj), null);
    }
    static Outcome buildErrorResponse(Object id, int code, String message, Object data) {
        Map<String, Object> error = new LinkedHashMap<>();
        error.put("code", code);
        error.put("message", message != null ? message : standardError(code));
        if (data != UNSET) error.put("data", data);
        Map<String, Object> obj = new LinkedHashMap<>();
        obj.put("jsonrpc", VERSION); obj.put("error", error); obj.put("id", id);
        return new Outcome(true, toJson(obj), null);
    }
    /** Lightweight shape check — reports every problem, not just the first. */
    static List<String> validateRpc(Object obj) {
        if (!(obj instanceof Map<?, ?> m)) return List.of("Not an object.");
        List<String> errors = new ArrayList<>();
        if (!"2.0".equals(m.get("jsonrpc"))) errors.add("jsonrpc must be \"2.0\".");
        if (m.containsKey("method") && !(m.get("method") instanceof String))
            errors.add("method must be a string.");
        if (m.containsKey("result") && m.containsKey("error"))
            errors.add("cannot have both result and error.");
        if (!m.containsKey("method") && !m.containsKey("result") && !m.containsKey("error"))
            errors.add("must have method, result, or error.");
        return errors;
    }
    public static void main(String[] args) {
        System.out.println(buildRequest("getBalance", List.of("0x1234"), 1).json());
        System.out.println(buildNotification("blockHeader", UNSET).json());
        System.out.println(buildErrorResponse(1, -32601, null, UNSET).json());
        System.out.println(validateRpc(Map.of("jsonrpc", "1.0")));
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →