Ready to use JSON-RPC Servlet in Java

I needed to write some Web based project in Java as an assignment, so I decide to use single page application and JSON-RPC service.

You can find the whole code in this gist.

Here is the code I use to create this task, step by step

First I found JSON-RPC library, I choose JSON-RPC 2.0 Base library.

I put both JSON Smart and JSON-RPC 2.0 Base jar files into lib directory (inside WEB-INF) of my java app.

In order to use JSON-RPC I needed to get raw POST data from request, I do this using this method (of the Servlet class):

    public String getInputData(HttpServletRequest request) throws IOException {
        ServletInputStream input = request.getInputStream();
        int buff;
        String output = "";
        while (true) {
            buff = input.read();
            if (buff == -1) {
                break;
            }
            output += (char)buff;
        }
        return output;
    }

Then I could parse that POST data (inside doPost Servlet method):

JSONRPC2Request reqIn = JSONRPC2Request.parse(this.getInputData(request));

Now I could extract data from the JSON-RPC request:

     Object id = reqIn.getID();
     Object[] params = reqIn.getPositionalParams().toArray();
     String method_name = reqIn.getMethod();

I decide to use other class as a Service and call method of that class based on JSON-RPC request, so I needed to use Reflection to do that

ClassLoader classLoader = ServletClass.class.getClassLoader();
Object service = classLoader.newInstance();
Class aClass = classLoader.loadClass("pl.jcubic.Service");
Method[] methods = aClass.getMethods();
                
Method method = null;
for (int i=0; i<methods.length; ++i) {
    if (methods[i].getName().equals(method_name)) {
        method = methods[i];
        break;
    }
}
if (method != null) {
    Object result = method.invoke(service, params);
    JSONRPC2Response respOut = new JSONRPC2Response(result, id);
    out.println(respOut);
} else {
    out.println(new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, id));
}

I use getMethods and search for method instead of using getMethod because I didn’t know what the classes I need to use for the params to get the right method.

I use class loader because I wanted to be able to recompile the Service (pl.jcubic.Service) and use it without the need to restart the app. But this loader don’t work as expected, the class file is loaded only once (when called the first time) the same as if I use import statement.

In order to have dynamic class load I need to write custom class loader, it look like this:

    class ServiceReloader extends ClassLoader {
        public ServiceReloader(ClassLoader parent) {
            super(parent);
        }

        public Class loadClass(String name) throws ClassNotFoundException {
            if (!"pl.jcubic.Service".equals(name)) {
                return super.loadClass(name);
            }
            try {
                String path = getClassPath(name);
                
                DataInputStream input = new DataInputStream(new BufferedInputStream(new FileInputStream(new File(path))));
                
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                while (true) {
                    int data = input.read();
                    if (data == -1) {
                        break;
                    } 
                    buffer.write(data);
                }
                byte[] classData = buffer.toByteArray();
                return defineClass(name, classData, 0, classData.length);
            } catch (IOException e) {
                throw new ClassNotFoundException(e.getMessage());
            }
        }
    }

I write it as inner class of my Servlet. Then I use this class to load my Service class.

    ClassLoader parentClassLoader = ServiceReloader.class.getClassLoader();
    ServiceReloader classLoader = new ServiceReloader(parentClassLoader);
    Class aClass = classLoader.loadClass("pl.jcubic.Service");

Now I could recompile the Service class and use it from JavaScript without need to restart the app (don’t even refresh the browser if I write new method and wanted to test it)

One more thing that need to be written is catch exceptions and display proper JSON-RPC error responses.

You can find the whole code in this gist.

Now all you need is a class with methods that will become your JSON-RPC methods. Here is list of Java types mapend to JSON-RPC types. All paramters and return values of your methods need to be of those types.

, ,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: