JSON-RPC
Jooby provides full support for the JSON-RPC 2.0 specification, allowing you to build robust RPC APIs using standard Java and Kotlin controllers.
The implementation leverages Jooby’s Annotation Processing Tool (APT) to generate highly optimized, reflection-free dispatchers at compile time.
Usage
Add dependencies:
<!-- Jackson module-->
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-jackson3</artifactId>
<version>4.3.0</version>
</dependency>
<!-- Jackson JSON-RPC implementation-->
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-jsonrpc-jackson3</artifactId>
<version>4.3.0</version>
</dependency>
<!-- JSON-RPC Module-->
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-jsonrpc</artifactId>
<version>4.3.0</version>
</dependency>
To expose a JSON-RPC endpoint, annotate your controller or service with @JsonRpc. You can optionally provide a namespace to the annotation, which will prefix all generated method names for that class.
import io.jooby.rpc.jsonrpc.JsonRpc;
@JsonRpc("movies")
public class MovieService {
public Movie getById(int id) {
return database.stream()
.filter(m -> m.id() == id)
.findFirst()
.orElseThrow(() -> new NotFoundException("Movie not found: " + id));
}
}
When the Jooby APT detects the @JsonRpc annotation, it generates a class ending in Rpc_ (e.g., MovieServiceRpc_) that implements the io.jooby.rpc.jsonrpc.JsonRpcService interface.
The annotation dictates how the protocol methods are named and exposed:
-
Class Level: Placing
@JsonRpcon a class treats its public methods as JSON-RPC endpoints. An optional string value defines a namespace prefix for all methods within that class (e.g.,@JsonRpc("movies")). If no value is provided, no namespace is applied. -
Method Level: By default, the generated JSON-RPC method name is exactly the name of the Java/Kotlin method, prefixed by the class-level namespace if one is present (e.g.,
movies.getByIdor justgetByIdif no namespace was set). You can also place@JsonRpc("customName")directly on specific methods to explicitly override this default naming convention.
Mixing Annotations: You can freely mix standard REST annotations (like @GET, @POST) and @JsonRpc on the same class. The APT handles this by generating two entirely separate dispatchers: one standard MVC extension (e.g., MovieService_) and one JSON-RPC service (e.g., MovieServiceRpc_). They do not interfere with each other, allowing you to expose the exact same business logic over both REST and JSON-RPC simultaneously.
Registration
Register the generated JsonRpcService in your application using the jsonrpc method. You must also install a supported JSON engine.
import io.jooby.Jooby;
import io.jooby.jackson.Jackson3Module;
{
install(new Jackson3Module()); // (1)
install(new JsonRpcJackson3Module()); // (2)
install(new JsonRpcModule(new MovieServiceRpc_())); // (3)
}
-
Install a JSON engine
-
Install a JSON-RPC implementation
-
Register the generated JSON-RPC service
JSON Engine Support
The JSON-RPC extension delegates payload parsing and serialization to Jooby’s standard JSON modules while enforcing strict JSON-RPC 2.0 compliance (such as the mutual exclusivity of result and error fields).
Supported engines include:
-
Jackson 2:
Jackson2Module,JsonRpcJackson2Module -
Jackson 3:
Jackson3Module,JsonRpcJackson3Module -
Avaje JSON-B:
AvajeJsonbModule,JsonRpcAvajeJsonbModule
No additional configuration is required. The generated dispatcher automatically hooks into the installed engine using the JsonRpcParser and JsonRpcDecoder interfaces, ensuring primitive types are strictly validated and parsed.
Error Mapping
Jooby seamlessly bridges standard Java application exceptions and HTTP status codes into the JSON-RPC 2.0 format using the JsonRpcErrorCode mapping. You do not need to throw custom protocol exceptions for standard failures.
When an application exception is thrown (like a NotFoundException with an HTTP 404 status), the dispatcher catches it and translates it into a compliant JSON-RPC error. The standard HTTP status defines the error code, while the specific exception message is safely passed into the data field:
{
"jsonrpc": "2.0",
"error": {
"code": -32004,
"message": "Not found",
"data": "Movie not found: 99"
},
"id": 1
}
Standard Protocol Errors
The engine handles core JSON-RPC 2.0 protocol errors automatically, returning HTTP 200 OK with the corresponding error payload:
-
-32700: Parse error (Malformed JSON) -
-32600: Invalid Request (Missing version, ID, or malformed envelope) -
-32601: Method not found -
-32602: Invalid params (Missing arguments, type mismatches) -
-32603: Internal error
Application-defined errors map standard HTTP status codes to the -32000 to -32099 range (e.g., an HTTP 404 maps to -32004, an HTTP 401 maps to -32001).
Batch Processing
Batch processing is natively supported. Clients can send an array of JSON-RPC request objects, and the dispatcher will process them and return an array of corresponding response objects.
In accordance with the specification, notifications (requests lacking an id field) are processed normally but generate no response payload, leaving no trace in the returned batch array.