Spring Boot JSON-RPC 2.0 sample using jsonrpc-spring-boot-starter.
From repository root:
./gradlew -p samples/spring-boot-demo bootRunFrom repository root:
./gradlew -p samples/spring-boot-demo testEndpoint:
- URL:
http://localhost:8080/jsonrpc - method:
POST - content type:
application/json
flowchart LR
A["HTTP JSON body"] --> B["JsonRpcWebMvcEndpoint"]
B --> C["JsonRpcDispatcher"]
C --> D["Parser + Validator"]
D --> E["Registry + Handler invocation"]
E --> F["Result/Error response"]
curl -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"ping","id":1}'Expected response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "pong"
}curl -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"greet","params":{"name":"developer"},"id":2}'Expected response:
{
"jsonrpc": "2.0",
"id": 2,
"result": "hello developer"
}curl -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"sum","params":{"left":2,"right":3},"id":3}'Expected response:
{
"jsonrpc": "2.0",
"id": 3,
"result": 5
}curl -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"sum","params":[2,3],"id":4}'Expected response:
{
"jsonrpc": "2.0",
"id": 4,
"result": 5
}curl -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"manual.echo","id":5}'Expected response:
{
"jsonrpc": "2.0",
"id": 5,
"result": "echo"
}curl -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"typed.upper","params":{"value":"spring"},"id":6}'Expected response:
{
"jsonrpc": "2.0",
"id": 6,
"result": {
"value": "SPRING"
}
}curl -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"typed.tags","id":7}'Expected response:
{
"jsonrpc": "2.0",
"id": 7,
"result": [
"alpha",
"beta"
]
}curl -i -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"ping"}'Expected response:
- HTTP status:
204 No Content - body: empty
curl -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '[
{"jsonrpc":"2.0","method":"manual.echo","id":8},
{"jsonrpc":"2.0","method":"typed.tags"},
{"jsonrpc":"2.0","method":"missing","id":9}
]'Expected response:
[
{
"jsonrpc": "2.0",
"id": 8,
"result": "echo"
},
{
"jsonrpc": "2.0",
"id": 9,
"error": {
"code": -32601,
"message": "Method not found"
}
}
]curl -s http://localhost:8080/jsonrpc \
-H 'content-type: application/json' \
-d '{'Expected response:
{
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32700,
"message": "Parse error"
}
}- Configured executor path is covered by
GreetingRpcServiceNotificationExecutorIntegrationTest. - Misconfiguration failure path (missing named executor bean) is covered by
GreetingRpcServiceNotificationExecutorConfigurationFailureTest.
REJECTstartup-failure path andREPLACEoverwrite path are covered byGreetingRpcServiceConflictPolicyIntegrationTest.
- Error-data exposure path (
jsonrpc.include-error-data=true) is covered byGreetingRpcServiceErrorDataExposureIntegrationTest. - Custom exception mapping path (
JsonRpcExceptionResolveroverride) is covered byGreetingRpcServiceCustomExceptionResolverIntegrationTest.
Spring sample also demonstrates request/response validation key symmetry through properties:
jsonrpc:
validation:
request:
require-id-member: true
allow-fractional-id: false
reject-response-fields: true
reject-duplicate-members: true
response:
reject-request-fields: true
reject-duplicate-members: true
error-code:
policy: STANDARD_ONLYThe outbound composition example in
src/main/java/com/limehee/jsonrpc/sample/OutboundRequestCompositionExample.java
also shows both direct paramsObject(...) and direct paramsArray(...) usage, in addition to
record / POJO / collection / map conversion through params(JsonNode).
Covered by GreetingRpcServiceValidationProfilesIntegrationTest:
- request-side validation at the HTTP endpoint (
require-id-member, fractional ID, polluted request fields, duplicate members) - response-side parser/validator beans (
reject-duplicate-members,reject-request-fields,error-code.policy)
The Spring sample also includes a small core-only example for composing outbound JSON-RPC payloads when the same application needs to call another JSON-RPC service.
src/main/java/com/limehee/jsonrpc/sample/OutboundRequestCompositionExample.javasrc/test/java/com/limehee/jsonrpc/sample/OutboundRequestCompositionExampleTest.java
Covered scenarios:
- single request payload with object params
- request payloads created from a record, a classic Java class, a collection, and a map
- batch payload containing a request and a notification
- manual
JsonRpcError.of(code, message, data)composition for upstream failures
src/test/java/com/limehee/jsonrpc/sample/GreetingRpcServiceIntegrationTest.javasrc/test/java/com/limehee/jsonrpc/sample/GreetingRpcServiceScenarioCoverageIntegrationTest.javasrc/test/java/com/limehee/jsonrpc/sample/GreetingRpcServiceParamsPolicyIntegrationTest.javasrc/test/java/com/limehee/jsonrpc/sample/GreetingRpcServiceNotificationExecutorIntegrationTest.javasrc/test/java/com/limehee/jsonrpc/sample/GreetingRpcServiceNotificationExecutorConfigurationFailureTest.javasrc/test/java/com/limehee/jsonrpc/sample/GreetingRpcServiceConflictPolicyIntegrationTest.javasrc/test/java/com/limehee/jsonrpc/sample/GreetingRpcServiceErrorDataExposureIntegrationTest.javasrc/test/java/com/limehee/jsonrpc/sample/GreetingRpcServiceCustomExceptionResolverIntegrationTest.javasrc/test/java/com/limehee/jsonrpc/sample/GreetingRpcServiceValidationProfilesIntegrationTest.javasrc/test/java/com/limehee/jsonrpc/sample/OutboundRequestCompositionExampleTest.java