Of course! Here's a comprehensive guide to using JSON-RPC in Java, covering popular libraries, a complete code example, and best practices.

What is JSON-RPC?
JSON-RPC (Remote Procedure Call) is a stateless, lightweight remote procedure call protocol. It uses JSON for data encoding and typically works over HTTP. A JSON-RPC request is a single JSON object with a few key fields:
jsonrpc: The protocol version, usually "2.0".method: The name of the method to be invoked on the server.params: An array or object containing the parameters for the method.id: A request identifier that can be used to match the response with the request.
A successful response looks like this:
{
"jsonrpc": "2.0",
"result": "The result of the method",
"id": 1
}
An error response looks like this:
{
"jsonrpc": "2.0",
"error": {
"code": -32601,
"message": "Method not found"
},
"id": 1
}
Popular Java Libraries for JSON-RPC
There are several excellent libraries for implementing JSON-RPC in Java. Here are the most popular ones:

| Library | Key Features | Best For |
|---|---|---|
| jsonrpc4j | - Simple and lightweight annotation-based API. - Easy to create a server from a POJO. - Good integration with Spring Framework. |
Quick setup, simplicity, and Spring-based applications. |
| Web3j | - A dedicated library for interacting with Ethereum nodes. - Provides type-safe wrappers for Ethereum JSON-RPC methods. |
DApps, blockchain development, and interacting with Ethereum. |
| Apache XML-RPC | - A mature, stable library from the Apache Software Foundation. - Supports both XML-RPC and JSON-RPC. |
Projects already using Apache libraries or needing high stability. |
| Gson-RPC | - A lightweight library built on top of Google's Gson. | Simple projects where you're already using Gson for JSON parsing. |
For this guide, we'll focus on jsonrpc4j as it's the most general-purpose and easiest to get started with for standard applications.
Step-by-Step Guide with jsonrpc4j
This example will show you how to create a simple JSON-RPC server and a client in plain Java.
Step 1: Add Dependencies
You need to add the jsonrpc4j library to your project. If you're using Maven, add this to your pom.xml:
<dependency>
<groupId>com.github.briandilley.jsonrpc4j</groupId>
<artifactId>jsonrpc4j</artifactId>
<version>1.6.0</version> <!-- Check for the latest version -->
</dependency>
If you're using Gradle, add this to your build.gradle:

implementation 'com.github.briandilley.jsonrpc4j:jsonrpc4j:1.6.0' // Check for the latest version
Step 2: Create the Server
The server consists of two parts:
- A service interface defining the available methods.
- A class implementing that interface.
1. Define the Service Interface
This interface declares the methods that can be called remotely. It's good practice to use @JsonRpcMethod annotations to explicitly define the JSON-RPC method name.
import com.github.briandilley.jsonrpc4j.JsonRpcMethod;
public interface MyService {
/**
* A simple method that takes a name and returns a greeting.
* @param name The name to greet.
* @return A greeting string.
*/
@JsonRpcMethod("greeting")
String sayHello(String name);
/**
* A method that takes two numbers and returns their sum.
* @param a The first number.
* @param b The second number.
* @return The sum of a and b.
*/
@JsonRpcMethod("add")
int add(int a, int b);
}
2. Implement the Service
Now, create a plain Java class that implements the interface.
public class MyServiceImpl implements MyService {
@Override
public String sayHello(String name) {
return "Hello, " + name + "!";
}
@Override
public int add(int a, int b) {
return a + b;
}
}
3. Create and Start the Server
jsonrpc4j provides a JsonRpcServer class that can wrap your service implementation. We'll use a simple HttpServer from the Java standard library to handle HTTP requests.
import com.github.briandilley.jsonrpc4j.JsonRpcServer;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
public class JsonRpcServerStarter {
public static void main(String[] args) throws IOException {
// 1. Create the service implementation
MyService myService = new MyServiceImpl();
// 2. Create the JSON-RPC server, wrapping the service
JsonRpcServer jsonRpcServer = new JsonRpcServer(myService, MyService.class);
// 3. Create a standard Java HttpServer
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
// 4. Create a context to handle all incoming requests at /rpc
server.createContext("/rpc", exchange -> {
// Handle preflight OPTIONS requests for CORS
if ("OPTIONS".equals(exchange.getRequestMethod())) {
exchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
exchange.getResponseHeaders().add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
exchange.getResponseHeaders().add("Access-Control-Allow-Headers", "Content-Type");
exchange.sendResponseHeaders(204, -1); // No content for OPTIONS
return;
}
// 5. Handle the JSON-RPC request
if ("POST".equals(exchange.getRequestMethod())) {
// Set CORS headers for the actual response
exchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
exchange.getResponseHeaders().add("Content-Type", "application/json");
// Get the request body
String requestBody = new String(exchange.getRequestBody().readAllBytes());
// Process the request using the jsonRpcServer
String jsonResponse = jsonRpcServer.handle(requestBody);
// Send the response
exchange.sendResponseHeaders(200, jsonResponse.getBytes().length);
exchange.getResponseBody().write(jsonResponse.getBytes());
exchange.getResponseBody().close();
} else {
exchange.sendResponseHeaders(405, -1); // Method Not Allowed
}
});
// 6. Start the server
server.start();
System.out.println("JSON-RPC Server started on http://localhost:8080/rpc");
}
}
Step 3: Create the Client
The client will send JSON-RPC requests to the server. We'll use jsonrpc4j's JsonRpcClient to make this easy.
import com.github.briandilley.jsonrpc4j.JsonRpcClient;
import com.github.briandilley.jsonrpc4j.JsonRpcTransportException;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;
public class JsonRpcClientExample {
public static void main(String[] args) {
// The URL of our JSON-RPC server
String serviceUrl = "http://localhost:8080/rpc";
// We need a custom transport for the client since jsonrpc4j doesn't have one built-in
// for Java's HttpClient. We'll create a simple one.
JsonRpcTransport transport = new JsonRpcTransport(serviceUrl);
// Create the client
JsonRpcClient client = new JsonRpcClient(transport);
// --- Make a request to the 'greeting' method ---
Map<String, Object> greetingParams = new HashMap<>();
greetingParams.put("name", "Alice");
try {
// The second argument is the expected return type
String greetingResponse = client.invoke("greeting", greetingParams, String.class);
System.out.println("Greeting Response: " + greetingResponse);
// --- Make a request to the 'add' method ---
Map<String, Object> addParams = new HashMap<>();
addParams.put("a", 15);
addParams.put("b", 27);
Integer addResponse = client.invoke("add", addParams, Integer.class);
System.out.println("Add Response: " + addResponse);
} catch (JsonRpcTransportException e) {
System.err.println("Transport error: " + e.getMessage());
} catch (IOException e) {
System.err.println("IO error: " + e.getMessage());
}
}
/**
* A simple custom transport implementation using Java 11+ HttpClient.
*/
static class JsonRpcTransport implements com.github.briandilley.jsonrpc4j.JsonRpcTransport {
private final String serviceUrl;
private final HttpClient httpClient = HttpClient.newHttpClient();
public JsonRpcTransport(String serviceUrl) {
this.serviceUrl = serviceUrl;
}
@Override
public String invoke(String request) throws IOException {
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create(serviceUrl))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(request))
.build();
HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
return response.body();
}
}
}
How to Run the Example
- Start the Server: Run the
JsonRpcServerStarterclass. You will see the message:JSON-RPC Server started on http://localhost:8080/rpc. - Run the Client: Run the
JsonRpcClientExampleclass.
Expected Output from the Client:
Greeting Response: Hello, Alice!
Add Response: 42
Advanced Topics & Best Practices
Integrating with Spring Framework
jsonrpc4j has excellent Spring support. You can expose a service as a JSON-RPC endpoint with a simple annotation.
// 1. Your service implementation (no change needed)
@Service
public class MySpringServiceImpl implements MyService {
// ... same methods as before
}
// 2. Create a controller to handle HTTP requests
@RestController
public class JsonRpcController {
private final MyService myService;
private final JsonRpcServer jsonRpcServer;
@Autowired
public JsonRpcController(MyService myService) {
this.myService = myService;
// The server can be a singleton bean
this.jsonRpcServer = new JsonRpcServer(myService, MyService.class);
}
@PostMapping("/rpc")
public String handleJsonRpcRequest(@RequestBody String json) {
// Spring automatically handles CORS headers with @CrossOrigin
return jsonRpcServer.handle(json);
}
}
This is much cleaner and leverages Spring's dependency injection and web capabilities.
Error Handling
- Server-Side Errors: If your service method throws an exception,
jsonrpc4jwill automatically catch it and convert it into a standard JSON-RPC error response with code-32000(Internal Error) and the exception message. - Client-Side Errors: The
client.invoke(...)method can throwJsonRpcException(or more specific transport exceptions) if the server returns an error response. You should wrap your client calls intry-catchblocks to handle these gracefully.
Security
- Authentication: JSON-RPC itself doesn't define an authentication mechanism. You must implement it at the web server level (e.g., using Spring Security, basic auth, or JWT tokens in the HTTP headers).
- HTTPS: Always use HTTPS in production to encrypt the communication between the client and server, preventing data tampering and eavesdropping.
- Input Validation: Never trust client input. Validate all parameters received by your server-side methods to prevent injection attacks or unexpected behavior. Libraries like Hibernate Validator are excellent for this.
