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 →