JSON-RPC 2.0 for Java
Annotation-based implementation of the JSON-RPC 2.0 specification.
Description
JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol. Primarily this specification defines several data structures and the rules around their processing. It is transport agnostic in that the concepts can be used within the same process, over sockets, over http, or in many various message passing environments. It uses JSON (RFC 4627) as data format.
Specification: https://www.jsonrpc.org/specification
Maven configuration
Add the Maven dependency:
<dependency>
<groupId>com.github.nmuzhichin</groupId>
<artifactId>jsonrpc-core</artifactId>
<version>1.0.4.0</version>
</dependency>
(Optional) Add the extension dependency:
<!-- Cache -->
<dependency>
<groupId>com.github.nmuzhichin</groupId>
<artifactId>jsonrpc-cache-extension</artifactId>
<version>1.0.4.0</version>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.github.nmuzhichin</groupId>
<artifactId>jsonrpc-jackson-extension</artifactId>
<version>1.0.4.0</version>
</dependency>
Project info
- Java 8 and above
- Maven modular system
- Cache support (module/interface)
- Parameter validation
- Annotation-based
The library operates with the following basic concepts:
- Context (contains information about methods)
- RpcConsumer (receiver the request and call the method)
- JsonRpc* annotations
- Processor (annotation processing)
Examples
Look at a simple synthetic examples.
5-minute example
Create service interface:
package example;
import com.github.nmuzhichin.jsonrpc.annotation.JsonRpcMethod;
import com.github.nmuzhichin.jsonrpc.annotation.JsonRpcType;
import com.github.nmuzhichin.jsonrpc.annotation.JsonRpcParam;
import com.github.nmuzhichin.jsonrpc.annotation.Constraint;
import static com.github.nmuzhichin.jsonrpc.validation.ConstraintType.*;
@JsonRpcType // Optional annotation for document generation
public interface SomeService {
@JsonRpcMethod
void doSomething(@JsonRpcParam(value = "notify", constraints = @Constraint(type = NOT_NULL)) String value);
@JsonRpcMethod("superAction")
Model action(@JsonRpcParam("argumentStr") String v0,
@JsonRpcParam("argumentLong") Long v1,
@JsonRpcParam("myModel") AnotherModel model);
}
And implements it:
package example;
public class SomeServiceImpl implements SomeService {
@Override
public void doSomething(String value) {
// Some action
}
@Override
public Model action(String v0, Long v1, AnotherModel model) {
// Some action
}
}
Now build consumer, create processor.
package example;
import java.util.HashMap;
public class Runner {
public static void main(String[] args) {
final RpcConsumer consumer = JsonRpc
.builder()
// Use custom cache provider
.cacheProvider(new MyCacheProvider())
// Set custom thread pool
.threadPool(Executors.newFixedThreadPool(5))
// Use predefine (in module) Jackson object mapper for an object normalization.
// For example, convert LinkedHashMap -> TreeNode -> Object
// NOTE: If you use objectMapper
// needed registered JsonRpcModule for correctly de- serialization
.valueNormalizer(new JacksonNormalization(objectMapper))
.build();
consumer.getProcessor().process(new SomeServiceImpl(), SomeService.class);
// More process ...
}
}
Handling of the received request:
package example;
public class RequestHandler {
public Response getRequest(final List<Request> requests) {
/* -- Get something in batch request, example --
[
{"jsonrpc":"2.0","method":"superAction","id":1234,"params":{"argumentStr":"Caesar", "argumentLong":70L, "myModel":{}}},
{"jsonrpc":"2.0","method":"doSomething","params":{"notify":"Hello, world!"}}
]
*/
// Request -> Response
final Response<?> response = consumer.execution(requests.get(0));
// Request without an id is a notification and don't return a response.
consumer.notify(requests.get(1));
return response;
}
}
5-minute example with Spring
For example, create BeanPostProcessor bean in your config and create RpcConsumer
bean.
package example.spring;
@EnableJsonRpc
@Configuration
public class ApplicationConfig {
@Bean
ObjectMapper objectMapper() {
// Register custom serializer and deserializer
return new ObjectMapper().registerModule(new JsonRpcModule());
}
@Bean("rpcConsumer")
RpcConsumer consumer(final ObjectMapper objectMapper) {
objectMapper.registerModule(new JsonRpcModule());
return new ConsumerBuilder()
.valueNormalizer(new JacksonNormalization(objectMapper))
.build();
}
@Bean
@DependsOn("rpcConsumer")
BeanPostProcessor beanPostProcessor(@Autowired final RpcConsumer rpcConsumer) {
final Processor processor = rpcConsumer.getProcessor();
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(final Object bean, final String name) throws BeansException {
processor.process(bean, AopUtils.getTargetClass(bean));
return bean;
}
};
}
}
Mark service.
package example.spring;
public interface MyService {
@JsonRpcMethod
String joiner(@JsonRpcParam("listStrings") List<String> args);
}
@Service // Spring's annotation
public class MyServiceImpl implements MyService {
@Override
public String joiner(final List<String> args) {
// Action
}
}
And get request in controller
package example.spring;
@RestController
public class MyController {
private final RpcConsumer rpcConsumer;
@Autowired
public MyController(final RpcConsumer rpcConsumer) {
this.rpcConsumer = rpcConsumer;
}
@PostController("/rpc")
public ResponseEntity<?> api(@ResponseBody final Request request) { // Request is json rpc interface
return ResponseEntity.ok(rpcConsumer.execution(request));
}
}
More examples
For more detailed examples, see modules jsonrpc-examples
and jsonrpc-test
.