Backend Development 10 min read

Master JSON-RPC with Spring Boot 3: Full Guide and Code Samples

This article introduces the JSON-RPC 2.0 protocol, demonstrates how to integrate the jsonrpc4j library into a Spring Boot 3.4.2 project, and provides step‑by‑step code examples for defining services, exposing them via beans or annotations, configuring various client proxies, handling errors, and implementing streaming socket communication.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master JSON-RPC with Spring Boot 3: Full Guide and Code Samples

Environment: Spring Boot 3.4.2.

1. Introduction

JSON‑RPC is a lightweight remote‑procedure‑call protocol that uses JSON as the data format. The current widely used version is 2.0, which adds error handling, batch requests, and notifications.

JSON‑RPC 2.0 Structure

Request fields:

jsonrpc: String, usually "2.0"

method: String, the name of the method to invoke

params: optional, an array or object with parameters

id: optional, a string, number or null to correlate the response

Response fields:

jsonrpc: String, usually "2.0"

result: the return value when the request succeeds

error: the error object when the request fails

id: must match the request id

Only one of result or error is returned.

2. Practical Example with jsonrpc4j

2.1 Dependency Management & Interface Definition

<code>&lt;dependency&gt;
  &lt;groupId&gt;com.github.briandilley.jsonrpc4j&lt;/groupId&gt;
  &lt;artifactId&gt;jsonrpc4j&lt;/artifactId&gt;
  &lt;version&gt;1.7&lt;/version&gt;
&lt;/dependency&gt;</code>

Current latest version is 1.7.

<code>public interface UserService {
  User createUser(String userName, String firstName, String password);
  User createUser(String userName, String password);
  User findUserByUserName(String userName);
  int getUserCount();
}

@Service
@Primary
public class UserServiceImpl implements UserService {
  private static final List<User> USERS = new ArrayList<>();

  public User createUser(String userName, String firstName, String password) {
    User user = new User(userName, firstName, password);
    USERS.add(user);
    return user;
  }

  public User createUser(String userName, String password) {
    return this.createUser(userName, null, password);
  }

  public User findUserByUserName(String userName) {
    System.err.println("admin".equals(userName) ? 1 / 0 : "success");
    return USERS.stream()
        .filter(user -> user.userName().equals(userName))
        .findFirst()
        .orElse(null);
  }

  public int getUserCount() {
    return USERS.size();
  }
}</code>

2.2 RPC Server Exposure

Method 1: JsonServiceExporter bean

<code>@Bean("/us")
JsonServiceExporter exporter(UserService userService, ObjectMapper objectMapper) {
  JsonServiceExporter exporter = new JsonServiceExporter();
  exporter.setServiceInterface(UserService.class);
  exporter.setObjectMapper(objectMapper);
  exporter.setService(userService);
  return exporter;
}</code>

Service is accessible at http://localhost:8080/us for any JSON‑RPC client.

Method 2: Annotation‑based discovery

<code>@JsonRpcService("/us")
public interface UserService {}

@AutoJsonRpcServiceImpl
@Service
@Primary
public class UserServiceImpl implements UserService {}

@Bean
AutoJsonRpcServiceImplExporter autoExporter() {
  return new AutoJsonRpcServiceImplExporter();
}</code>

2.3 RPC Client Invocation

Configuration 1: AutoJsonRpcClientProxyCreator

<code>@Bean
AutoJsonRpcClientProxyCreator proxyCreator() throws Exception {
  AutoJsonRpcClientProxyCreator creator = new AutoJsonRpcClientProxyCreator();
  creator.setBaseUrl(URI.create("http://localhost:8080").toURL());
  creator.setScanPackage("com.pack.rpc.server");
  return creator;
}</code>

Configuration 2: JsonProxyFactoryBean

<code>@Bean
JsonProxyFactoryBean userServiceProxy() {
  JsonProxyFactoryBean proxy = new JsonProxyFactoryBean();
  proxy.setServiceUrl("http://localhost:8080/us");
  proxy.setServiceInterface(UserService.class);
  return proxy;
}</code>

Configuration 3: JsonRpcHttpClient

<code>JsonRpcHttpClient client = new JsonRpcHttpClient(URI.create("http://localhost:8080/us").toURL());
User user = client.invoke("createUser", new Object[]{"Spring Boot3实战案例200讲", "Pack", "123456"}, User.class);
System.err.println(user);

UserService userService = ProxyUtil.createClientProxy(
    ClientTest.class.getClassLoader(), UserService.class, client);
User user2 = userService.createUser("Pack", "xg");
System.err.println(user2);
</code>

2.4 Testing Controller

<code>@RestController
@RequestMapping("/rpc")
public class RpcController {
  private final UserService userService;
  public RpcController(UserService userService) { this.userService = userService; }

  @GetMapping("/create")
  public ResponseEntity<User> createUser(String userName, String firstName, String password) {
    return ResponseEntity.ok(userService.createUser(userName, firstName, password));
  }

  @GetMapping("/query")
  public ResponseEntity<User> queryUser(String userName) {
    return ResponseEntity.ok(userService.findUserByUserName(userName));
  }
}
</code>

2.5 Custom Error Handling

<code>@JsonRpcErrors({
  @JsonRpcError(exception = Exception.class, code = -1, message = "服务发生异常")
})
User findUserByUserName(String userName);
</code>

2.6 Streaming (Socket) Service

Server side

<code>JsonRpcServer server = new JsonRpcServer(new UserServiceImpl());
int maxThreads = 50;
int port = 8080;
ServerSocket serverSocket = new ServerSocket(port);
StreamServer ss = new StreamServer(server, maxThreads, serverSocket);
ss.start();
</code>

Client side

<code>Socket socket = new Socket(InetAddress.getLocalHost(), 8080);
OutputStream os = socket.getOutputStream();
Map<String, Object> data = Map.of(
    "jsonrpc", "2.0",
    "method", "createUser",
    "params", new Object[]{"Spring Boot3实战案例200讲", "Pack", "111111"},
    "id", "s-0001"
);
os.write(new ObjectMapper().writeValueAsBytes(data));
socket.shutdownOutput();

InputStream is = socket.getInputStream();
System.err.println(new String(is.readAllBytes()));
</code>

The above examples show successful calls, error responses, and how to customize error messages.

JavaBackend DevelopmentRPCSpring BootJSON-RPCjsonrpc4j
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.