- Notifications
You must be signed in to change notification settings - Fork0
0xwang-coder/jsonrpc4j
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
This project aims to provide the facility to easily implementJSON-RPC for the java programming language. jsonrpc4j uses theJackson library to convert javaobjects to and from json objects (and other things related toJSON-RPC).
- 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
This project is built withMaven. Besure to check the pom.xml for the dependencies if you're not usingmaven. If you're already using spring you should have most (if not all)of the dependencies already - outside of maybe theJackson Library. Jsonrpc4j is availablefrom the maven central repo. Add the following to your pom.xml if you'reusing maven:
In<dependencies>:
<!-- jsonrpc4j--><dependency><groupId>com.github.briandilley.jsonrpc4j</groupId><artifactId>jsonrpc4j</artifactId><version>1.5.0</version></dependency>
If you want to just download the projects output JAR and it's dependencies you cando it over at theMaven repository.
The official source for theJSON-RPC 2.0 specification.The guys over atjson-rpc google groupseem to be fairly active, so you can ask clarifying questions there.
Jsonrpc4j comes with a streaming server and client to support applications of all types(not just HTTP). TheJsonRpcClient andJsonRpcServer have simple methodsthat takeInputStreams andOutputStreams. Also in the library is aJsonRpcHttpClientwhich extends theJsonRpcClient to add HTTP support.
jsonrpc4j provides aRemoteExporter to expose java services as JSON-RPC over HTTP withoutrequiring any additional work on the part of the programmer. The following example explainshow to use theJsonServiceExporter within the Spring Framework.
Create your service interface:
packagecom.mycompany;publicinterfaceUserService {UsercreateUser(StringuserName,StringfirstName,Stringpassword);UsercreateUser(StringuserName,Stringpassword);UserfindUserByUserName(StringuserName);intgetUserCount();}
Implement it:
packagecom.mycompany;publicclassUserServiceImplimplementsUserService {publicUsercreateUser(StringuserName,StringfirstName,Stringpassword) {Useruser =newUser();user.setUserName(userName);user.setFirstName(firstName);user.setPassword(password);database.saveUser(user)returnuser; }publicUsercreateUser(StringuserName,Stringpassword) {returnthis.createUser(userName,null,password); }publicUserfindUserByUserName(StringuserName) {returndatabase.findUserByUserName(userName); }publicintgetUserCount() {returndatabase.getUserCount(); }}
Configure your service in spring as you would any other RemoteExporter:
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <beanclass="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <beanid="userService"class="com.mycompany.UserServiceImpl"> </bean> <beanname="/UserService.json"class="com.googlecode.jsonrpc4j.spring.JsonServiceExporter"> <propertyname="service"ref="userService"/> <propertyname="serviceInterface"value="com.mycompany.UserService"/> </bean></beans>
Your service is now available at the URL /UserService.json. Type conversion ofJSON->Java and Java->JSON will happen for you automatically. This service canbe accessed by any JSON-RPC capable client, including theJsonProxyFactoryBean,JsonRpcClient andJsonRpcHttpClient provided by this project:
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"> <beanclass="com.googlecode.jsonrpc4j.spring.JsonProxyFactoryBean"> <propertyname="serviceUrl"value="http://example.com/UserService.json"/> <propertyname="serviceInterface"value="com.mycompany.UserService"/> </bean><beans>
In the case that your JSON-RPC requires named based parameters rather than indexedparameters an annotation can be added to your service interface (this also works onthe service implementation for the ServiceExporter):
packagecom.mycompany;publicinterfaceUserService {UsercreateUser(@JsonRpcParam(value="theUserName")StringuserName,@JsonRpcParam(value="thePassword")Stringpassword);}
By default all error message responses contain the the message as returned byException.getmessage() with a code of 0. This is not always desirable.jsonrpc4j supports annotated based customization of these error messages andcodes, for example:
packagecom.mycompany;publicinterfaceUserService {@JsonRpcErrors({@JsonRpcError(exception=UserExistsException.class,code=-5678,message="User already exists",data="The Data"),@JsonRpcError(exception=Throwable.class,code=-187) })UsercreateUser(@JsonRpcParam(value="theUserName")StringuserName,@JsonRpcParam(value="thePassword")Stringpassword);}
The previous example will return the error code-5678 with the messageUser already exists if the service throws a UserExistsException. In thecase of any other exception the code-187 is returned with the valueofgetMessage() as returned by the exception itself.
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")interfaceMyService {...servicemethods ...}
Next annotate the implementation of the service interface;
@AutoJsonRpcServiceImplclassMyServiceImpl {...servicemethods' implementations ...}
and use the following configuration to allow spring to find the implementation that you would like to expose:
<beansxmlns="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"> <beanclass="com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImplExporter"/> <beanclass="com.mycompany.MyServiceImpl" /></beans>
Configuring a client is just as easy:
<beansxmlns="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"> <beanclass="com.googlecode.jsonrpc4j.spring.AutoJsonRpcClientProxyCreator"> <propertyname="baseUrl"value="http://hostname/api/" /> <propertyname="scanPackage"value="com.mycompany.services" /> </bean></beans>
Where thebaseUrl is added to the front of the path value provided by theJsonRpcService annotation andscanPackage tells spring which packagesto scan for services.
jsonrpc4j can be used without the spring framework as well. In fact, the clientand server both work in an Android environment.
Here's an example of how to use the client to communicate with the JSON-RPC service described above:
JsonRpcHttpClientclient =newJsonRpcHttpClient(newURL("http://example.com/UserService.json"));Useruser =client.invoke("createUser",newObject[] {"bob","the builder" },User.class);
Or, the ProxyUtil class can be used in conjunction with the interface to create a dynamic proxy:
JsonRpcHttpClientclient =newJsonRpcHttpClient(newURL("http://example.com/UserService.json"));UserServiceuserService =ProxyUtil.createClientProxy(getClass().getClassLoader(),UserService.class,client);Useruser =userService.createUser("bob","the builder");
The server can be used without spring as well:
// create itJsonRpcServerserver =newJsonRpcServer(userService,UserService.class);
After having created the server it's simply a matter of calling one of thehandle(...) methods available. For example, here's a servlet using thevery sameUserService:
classUserServiceServletextendsHttpServlet {privateUserServiceuserService;privateJsonRpcServerjsonRpcServer;protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp) {jsonRpcServer.handle(req,resp); }publicvoidinit(ServletConfigconfig) {//this.userService = ...this.jsonRpcServer =newJsonRpcServer(this.userService,UserService.class); }}
Multiple services can be combined into a single server using one of theProxyUtil::createCompositeService(...) methods. For example:
UserverServiceuserService = ...;ContentServicecontentService = ...;BlackJackServiceblackJackService = ...;ObjectcompositeService =ProxyUtil.createCompositeServiceProxy(this.getClass().getClassLoader(),newObject[] {userService,contentService,blackJackService},newClass<?>[] {UserService.class,ContentService.class,BlackJackService.class},true);// now compositeService can be used as any of the above service, ie:Useruser = ((UserverService)compositService).createUser(...);Contentcontent = ((ContentService)compositService).getContent(...);Handhand = ((BlackJackService)compositService).dealHand(...);
This can be used in conjunction with theJsonRpcServer to expose the servicemethods from all services at a single location:
JsonRpcServerjsonRpcServer =newJsonRpcServer(compositeService);
A spring service exporter exists for creating composite services as wellnamedCompositeJsonServiceExporter.
A streaming server that usesSockets is available in the form of theStreamServer class. It's use is very straightforward:
// create the jsonRpcServerJsonRpcServerjsonRpcServer =newJsonRpcServer(...);// create the stream serverintmaxThreads =50;intport =1420;InetAddressbindAddress =InetAddress.getByName("...");StreamServerstreamServer =newStreamServer(jsonRpcServer,maxThreads,port,bindAddress);// start it, this method doesn't blockstreamServer.start();
and when you're ready to shut the server down:
// stop it, this method blocks until// shutdown is completestreamServer.stop();
Of course, this is all possible in the Spring Framework as well:
<beanid="streamingCompositeService"class="com.googlecode.jsonrpc4j.spring.CompositeJsonStreamServiceExporter"><!-- can be an IP, hostname or omitted to listen on all available devices--> <propertyname="hostName"value="localhost"/> <propertyname="port"value="6420"/> <propertyname="services"> <list> <refbean="userService" /> <refbean="contentService" /> <refbean="blackJackService" /> </list> </property> </bean>
The following settings apply to both theJsonRpcServer andJsonServiceExporter:
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.
Methods are resolved in the following way, each step immediately short circuits theprocess 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 methodssometimes. Primitives areeasily 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:
publicvoidaMethod(Stringparam1);publicvoidaMethod(Stringparam1,Stringparam2);publicvoidaMethod(Stringparam1,Stringparam2,intparam3);
But the following will not:
json request:
{"jsonrpc":"2.0","id":"10","method":"addFriend","params":[{"username":"example","firstName":"John"}]}java methods:
publicvoidaddFriend(UserObjectuserObject);publicvoidaddFriend(UserObjectExuserObjectEx);
The reason being that there is no efficient way for the server todetermine the difference in the json between theUserObjectandUserObjectEx Plain Old Java Objects.
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")publicinterfaceLibraryService {@JsonRpcMethod("VideoLibrary.GetTVShows")List<TVShow>fetchTVShows(@JsonRpcParam(value="properties")finalList<String>properties);}
{"jsonrpc":"2.0","method":"VideoLibrary.GetTVShows","params": {"properties": ["title"] },"id":1}About
JSON-RPC for Java
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Languages
- Java100.0%