SON-RPC for Java
JSON-RPC for Java
https://github.com/briandilley/jsonrpc4j#json-rpc-for-java
This project aims to provide the facility to easily implement JSON-RPC for the java programming language. jsonrpc4j uses the Jackson library to convert java objects to and from json objects (and other things related to JSON-RPC).
Features Include:
- Streaming server (
InputStream\OutputStream) - HTTP Server (
HttpServletRequest\HttpServletResponse) - Portlet Server (
ResourceRequest\ResourceResponse) - Socket Server (
StreamServer) - Integration with the Spring Framework (
RemoteExporter) - Streaming client
- HTTP client
- Dynamic client proxies
- Annotations support
- Custom error resolving
- Composite services
Maven
This project is built with Maven. Be sure to check the pom.xml for the dependencies if you're not using maven. If you're already using spring you should have most (if not all) of the dependencies already - outside of maybe the Jackson Library. Jsonrpc4j is available from the maven central repo. Add the following to your pom.xml if you're using maven:
In <dependencies>:
<!-- jsonrpc4j -->
<dependency>
<groupId>com.github.briandilley.jsonrpc4j</groupId>
<artifactId>jsonrpc4j</artifactId>
<version>1.1</version>
</dependency>
JSON-RPC specification
The official source for the JSON-RPC 2.0 specification. The guys over at json-rpc google group seem to be fairly active, so you can ask clarifying questions there.
Streaming server and client
Jsonrpc4j comes with a streaming server and client to support applications of all types (not just HTTP). The JsonRpcClient and JsonRpcServer have simple methods that take InputStreams andOutputStreams. Also in the library is a JsonRpcHttpClient which extends the JsonRpcClient to add HTTP support.
Spring Framework
jsonrpc4j provides a RemoteExporter to expose java services as JSON-RPC over HTTP without requiring any additional work on the part of the programmer. The following example explains how to use the JsonServiceExporter within the Spring Framework.
Create your service interface:
package com.mycompany;
public interface UserService {
User createUser(String userName, String firstName, String password);
User createUser(String userName, String password);
User findUserByUserName(String userName);
int getUserCount();
}
Implement it:
package com.mycompany;
public class UserServiceImpl
implements UserService { public User createUser(String userName, String firstName, String password) {
User user = new User();
user.setUserName(userName);
user.setFirstName(firstName);
user.setPassword(password);
database.saveUser(user)
return user;
} public User createUser(String userName, String password) {
return this.createUser(userName, null, password);
} public User findUserByUserName(String userName) {
return database.findUserByUserName(userName);
} public int getUserCount() {
return database.getUserCount();
} }
Configure your service in spring as you would any other RemoteExporter:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="userService" class="com.mycompany.UserServiceImpl">
</bean> <bean name="/UserService.json" class="com.googlecode.jsonrpc4j.spring.JsonServiceExporter">
<property name="service" ref="userService"/>
<property name="serviceInterface" value="com.mycompany.UserService"/>
</bean> </beans>
Your service is now available at the URL /UserService.json. Type conversion of JSON->Java and Java->JSON will happen for you automatically. This service can be accessed by any JSON-RPC capable client, including the JsonProxyFactoryBean, JsonRpcClient and JsonRpcHttpClient provided by this project:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.googlecode.jsonrpc4j.spring.JsonProxyFactoryBean">
<property name="serviceUrl" value="http://example.com/UserService.json"/>
<property name="serviceInterface" value="com.mycompany.UserService"/>
</bean> <beans>
In the case that your JSON-RPC requires named based parameters rather than indexed parameters an annotation can be added to your service interface (this also works on the service implementation for the ServiceExporter):
package com.mycompany;
public interface UserService {
User createUser(@JsonRpcParamName("theUserName") String userName, @JsonRpcParamName("thePassword") String password);
}
By default all error message responses contain the the message as returned by Exception.getmessage() with a code of 0. This is not always desirable. jsonrpc4j supports annotated based customization of these error messages and codes, for example:
package com.mycompany;
public interface UserService {
@JsonRpcErrors({
@JsonRpcError(exception=UserExistsException.class,
code=-5678, message="User already exists", data="The Data"),
@JsonRpcError(exception=Throwable.class,code=-187)
})
User createUser(@JsonRpcParamName("theUserName") String userName, @JsonRpcParamName("thePassword") String password);
}
The previous example will return the error code -5678 with the message User already exists if the service throws a UserExistsException. In the case of any other exception the code -187 is returned with the value of getMessage() as returned by the exception itself.
Auto Discovery With Annotations
Spring can also be configured to auto-discover services and clients with annotations.
To configure auto-discovery of annotated services first annotate the service interface:
@JsonRpcService("/path/to/MyService")
interface MyService {
... service methods ...
}
and use the following configuration to allow spring to find it:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean class="com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceExporter"/> <bean class="com.mycompany.MyServiceImpl" /> </beans>
Configuring a client is just as easy:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean class="com.googlecode.jsonrpc4j.spring.AutoJsonRpcClientProxyCreator">
<property name="baseUrl" value="http://hostname/api/" />
<property name="scanPackage" value="com.mycompany.services" />
</bean> </beans>
Where the baseUrl is added to the front of the path value provided by the JsonRpcService annotation and scanPackage tells spring which packages to scan for services.
Without the Spring Framework
jsonrpc4j can be used without the spring framework as well. In fact, the client and server both work in an Android environment.
Client
Here's an example of how to use the client to communicate with the JSON-RPC service described above:
JsonRpcHttpClient client = new JsonRpcHttpClient(
new URL("http://example.com/UserService.json")); User user = client.invoke("createUser", new Object[] { "bob", "the builder" }, User.class);
Or, the ProxyUtil class can be used in conjunction with the interface to create a dynamic proxy:
JsonRpcHttpClient client = new JsonRpcHttpClient(
new URL("http://example.com/UserService.json")); UserService userService = ProxyUtil.createClientProxy(
getClass().getClassLoader(),
UserService.class,
client); User user = userService.createUser("bob", "the builder");
server
The server can be used without spring as well:
// create it
JsonRpcServer server = new JsonRpcServer(userService, UserService.class);
After having created the server it's simply a matter of calling one of the handle(...) methods available. For example, here's a servlet using the very same UserService:
class UserServiceServlet
extends HttpServlet { private UserService userService;
private JsonRpcServer jsonRpcServer; protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
jsonRpcServer.handle(req, resp);
} public void init(ServletConfig config) {
this.userService = ...;
this.jsonRpcServer = new JsonRpcServer(this.userService, UserService.class);
} }
Composite Services
Multiple services can be combined into a single server using one of theProxyUtil::createCompositeService(...) methods. For example:
UserverService userService = ...;
ContentService contentService = ...;
BlackJackService blackJackService = ...; Object compositeService = ProxyUtil.createCompositeServiceProxy(
this.getClass().getClassLoader(),
new Object[] { userService, contentService, blackJackService},
new Class<?>[] { UserService.class, ContentService.class, BlackJackService.class},
true); // now compositeService can be used as any of the above service, ie:
User user = ((UserverService)compositService).createUser(...);
Content content = ((ContentService)compositService).getContent(...);
Hand hand = ((BlackJackService)compositService).dealHand(...);
This can be used in conjunction with the JsonRpcServer to expose the service methods from all services at a single location:
JsonRpcServer jsonRpcServer = new JsonRpcServer(compositeService);
A spring service exporter exists for creating composite services as well namedCompositeJsonServiceExporter.
Streaming (Socket) Server
A streaming server that uses Sockets is available in the form of the StreamServer class. It's use is very straitforward:
// create the jsonRpcServer
JsonRpcServer jsonRpcServer = new JsonRpcServer(...); // create the stream server
int maxThreads = 50;
int port = 1420;
InetAddress bindAddress = InetAddress.getByName("...");
StreamServer streamServer = new StreamServer(
jsonRpcServer, maxThreads, port, bindAddress); // start it, this method doesn't block
streamServer.start();
and when you're ready to shut the server down:
// stop it, this method blocks until
// shutdown is complete
streamServer.stop();
Of course, this is all possible in the Spring Framework as well:
<bean id="streamingCompositeService" class="com.googlecode.jsonrpc4j.spring.CompositeJsonStreamServiceExporter">
<!-- can be an IP, hostname or omitted to listen on all available devices -->
<property name="hostName" value="localhost"/>
<property name="port" value="6420"/>
<property name="services">
<list>
<ref bean="userService" />
<ref bean="contentServic" />
<ref bean="blackJackService" />
</list>
</property>
</bean>
JsonRpcServer settings explained
The following settings apply to both the JsonRpcServer and JsonServiceExporter:
allowLessParams- Boolean specifying whether or not the server should allow for methods to be invoked by clients supplying less than the required number of parameters to the method.allowExtraParams- Boolean specifying whether or not the server should allow for methods to be invoked by clients supplying more than the required number of parameters to the method.rethrowExceptions- Boolean specifying whether or not the server should re-throw exceptions after sending them back to the client.backwardsComaptible- Boolean specifying whether or not the server should allow for jsonrpc 1.0 calls. This only includes the omission of the jsonrpc property of the request object, it will not enable class hinting.errorResolver- An implementation of theErrorResolverinterface that resolves exception thrown by services into meaningful responses to be sent to clients. MultipleErrorResolvers can be configured using theMultipleErrorResolverimplementation of this interface.
Server Method resolution
Methods are resolved in the following way, each step immediately short circuits the process when the available methods is 1 or less.
- All methods with the same name as the request method are considered
- If
allowLessParamsis disabled methods with more parameters than the request are removed - If
allowExtraParamsis disabled then methods with less parameters than the request are removed - If either of the two parameters above are enabled then methods with the lowest difference in parameter count from the request are kept
- Parameters types are compared to the request parameters and the method(s) with the highest number of matching parameters is kept
- If there are multiple methods remaining then the first of them are used
jsonrpc4j's method resolution allows for overloaded methods sometimes. Primitives are easily resolved from json to java. But resolution between other objects are not possible.
For example, the following overloaded methods will work just fine:
json request:
{"jsonrpc":"2.0", "id":"10", "method":"aMethod", "params":["Test"]}
java methods:
public void aMethod(String param1);
public void aMethod(String param1, String param2);
public void aMethod(String param1, String param2, int param3);
But the following will not:
json request:
{"jsonrpc":"2.0", "id":"10", "method":"addFriend", "params":[{"username":"example", "firstName":"John"}]}
java methods:
public void addFriend(UserObject userObject);
public void addFriend(UserObjectEx userObjectEx);
The reason being that there is no efficient way for the server to determine the difference in the json between the UserObject and UserObjectEx pojos.
Custom method names
In some instances, you may need to expose a JsonRpc method that is not a valid Java method name. In this case, use the annotation @JsonRpcMethod on the service method.
@JsonRpcService("/jsonrpc")
public interface LibraryService {
@JsonRpcMethod("VideoLibrary.GetTVShows")
List<TVShow> fetchTVShows(@JsonRpcParam("properties") final List<String> properties);
}
{"jsonrpc":"2.0", "method": "VideoLibrary.GetTVShows", "params": { "properties": ["title"]
SON-RPC for Java的更多相关文章
- (转) RabbitMQ学习之远程过程调用(RPC)(java)
http://blog.csdn.net/zhu_tianwei/article/details/40887885 在一般使用RabbitMQ做RPC很容易.客户端发送一个请求消息然后服务器回复一个响 ...
- java 远程调用 RPC
1. 概念 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).H ...
- Java简单的RPC实现(一)
RPC使用java最基本的,传输层使用Socket,序列化使用Serializable,java 动态代理模式,但是未实现消息注册等相关信息 大道至简 server端 package com.rpc. ...
- 【Other】最近在研究的, Java/Springboot/RPC/JPA等
我的Springboot框架,欢迎关注: https://github.com/junneyang/common-web-starter Dubbo-大波-服务化框架 dubbo_百度搜索 Dubbo ...
- 面试题思考:Java RMI与RPC,JMS的比较
RPC:(Remote Procedure Call) 被设计为在应用程序间通信的平台中立的方式,它不理会操作系统之间以及语言之间的差异. 支持多语言 RMI:(Remote Method Invo ...
- Hadoop中RPC协议小例子报错java.lang.reflect.UndeclaredThrowableException解决方法
最近在学习传智播客吴超老师的Hadoop视频,里面他在讲解RPC通信原理的过程中给了一个RPC的小例子,但是自己编写的过程中遇到一个小错误,整理如下: log4j:WARN No appenders ...
- java实现RPC
一,服务提供者 工程为battercake-provider,项目结构图如下图所示 1.1 先创建一个“卖煎饼”微服务的接口和实现类 package com.jp.service; public in ...
- 从RPC开始(一)
这是一篇关于纯C++RPC框架的文章.所以,我们先看看,我们有什么? 1.一个什么都能干的C++.(前提是,你什么都干了) 2.原始的Socket接口,还是C API.还得自己去二次封装... 3.C ...
- RPC远程过程调用学习之路(一):用最原始代码还原PRC框架
RPC: Remote Procedure Call 远程过程调用,即业务的具体实现不是在自己系统中,需要从其他系统中进行调用实现,所以在系统间进行数据交互时经常使用. rpc的实现方式有很多,可以通 ...
- RPC
那是N年前的一天,老王在看一本讲java的技术书(可惜忘了叫啥名字了),突然看到有一章讲RMI的,立马就觉得很好奇.于是乎,就按书上所讲,写了demo程序.当时也就只知道怎么用,却不知道什么原理.直到 ...
随机推荐
- HDU 2227-Find the nondecreasing subsequences(dp+BIT优化)
题意: 给你一个序列a[],求它的不降子序列的个数 分析: dp[i]表示以i结尾不降子序列的个数,dp[i]=sum(dp[j])+1(j<i&&a[j]<=a[i]); ...
- Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF
在实时渲染中Physically-Based Rendering(PBR)中文为基于物理的渲染它能为渲染的物体带来更真实的效果,而且能量守恒 稍微解释一下字母的意思,为对后文的理解有帮助,从右到左L为 ...
- 利用ASP.NET MVC源代码调试你的应用程序[转]
由于项目需要,最近学起asp.net mvc.昨天遇到ViewData和TempData他们之间的分别这样让我纠结的问题.有园友强烈建议我去看ASP.NET MVC的源代码.所以,我想到如何在调试AS ...
- 单词计数WordCountApp.class
public class WordCountApp { // 可以指定目录,目录下如果有二级目录的话,是不会执行的,只会执行一级目录. private static final String INPU ...
- Hadoop-安装过程-单虚拟机版(伪分布式)(Ubuntu13.04版本下安装)
由于新装的Ubutu默认情况下,系统只安装了SSH客户端,需要自行安装SSH服务端 如何确定是否安装了SSH服务端? 可以通过命令ssh localhost,结果如下,即未安装SSH服务端: 安装 ...
- SRM 509 DIV1 500pt(DP)
题目简述 给定一个字符串,可以对其进行修改,删除,增加操作,相应的操作有对应的花费,要求你用最小的花费把字符串变为回文串 题目做法 先搞一遍floyed把各种操作的最小花费求出来,然后就是类似编辑距离 ...
- JAVA NIO 类库的异步通信框架netty和mina
Netty 和 Mina 我究竟该选择哪个? 根据我的经验,无论选择哪个,都是个正确的选择.两者各有千秋,Netty 在内存管理方面更胜一筹,综合性能也更优.但是,API 变更的管理和兼容性做的不是太 ...
- Spark RDD概念学习系列之Spark的数据存储(十二)
Spark数据存储的核心是弹性分布式数据集(RDD). RDD可以被抽象地理解为一个大的数组(Array),但是这个数组是分布在集群上的. 逻辑上RDD的每个分区叫一个Partition. 在Spar ...
- RTMP、RTSP、HTTP视频协议详解(转)
一.RTMP.RTSP.HTTP协议 这三个协议都属于互联网 TCP/IP 五层体系结构中应用层的协议.理论上这三种都可以用来做视频直播或点播.但通常来说,直播一般用 RTMP.RTSP.而点播用 H ...
- Oracle的回收站和闪回查询机制(一)
实际工作中,我们经常会遇到一些情况,误删除某些表或某些表的某些记录,这时候就需要我们将这些记录重新插入进去.如何才能解决这个问题呢? Oracle的Flashback query(闪回查询)为我们解决 ...