I recently was duped (by myself) at a discussion with a colleague: in our continuous effort to disentangle release schedules of two tightly entangled applications, I exposed some core features as a JSON REST service and told him to “just use the Spring invoker” for JSON. It turns out, there is one for JaxRS, Burlap, Hessian, RMI… but nothing for a generic JSON service.
Pondering over this obvious lack of a facility which binds a JSON service to a java interface it occurs that it’s not exactly trivial: how do you know the URL a method should be bound to? Which HTTP method do you use? GET? POST? PUT? Do you post parameters as URL parameters or are they part of the url path? I.e.
/books/1-2345-678 vs /books/?isbn=1-2345-678
A JSON REST service does not expose it’s structure, so there is no automatic way of binding a Java interface to it.
So I came up with the spring-rest-invoker [1] which binds a java interface to a remote JSON REST service. The idea behind is simple: define a interface and declare the concrete mappings to URLs and HTTP methods via Spring annotations such as @RequestMapping:
public interface BookService { @RequestMapping("/volumes") QueryResult findBooksByTitle(@RequestParam("q") String q); @RequestMapping("/volumes/{id}") Item findBookById(@PathVariable("id") String id); }
Create a proxy to it:
<bean id="RemoteBookService" class="com.github.ggeorgovassilis.springjsonmapper.HttpJsonInvokerFactoryProxyBean">
Use and enjoy:
@Autowired RemoteBookService bookService; ... QueryResult results = bookService.findBooksByTitle("Alice in Wonderland");
Cool things you can do:
- It converts JSON to Java value objects when reading and the other way around when posting
- You can define method parameters to map to parts of the URL via @PathVariable or being sent as URL parameters via @RequestParam
- You can post a single Java object which will be directly JSON-ified
- You can post multiple Java objects, then every object will be a named field in a JSON object (you have to use @RequestParam in that case to assign the name)
- You can provide your own RestTemplate in case you need to hook into the HTTP communication
Resources
[1] Spring http invoker