Java – how to design a common response builder / restful web service using spring MVC?
Try to use spring MVC to build restful web services
The controller should return a specific Java type, but the response body must be a generic envelope How can this be done?
The following code section is what I have so far:
Controller method:
@Controller @RequestMapping(value = "/mycontroller") public class MyController { public ServiceDetails getServiceDetails() { return new ServiceDetails("MyService"); } }
Reply envelope:
public class Response<T> { private String message; private T responseBody; }
Servicedetails Code:
public class ServiceDetails { private String serviceName; public ServiceDetails(String serviceName) { this.serviceName = serviceName; } }
The final response to the customer should be displayed as:
{ "message" : "Operation OK" "responseBody" : { "serviceName" : "MyService" } }
Solution
What you can do is to let a myrestcontroller just wrap the results in a response, as shown below:
@Controller @RequestMapping(value = "/mycontroller") public class MyRestController { @Autowired private MyController myController; @RequestMapping(value = "/details") public @ResponseBody Response<ServiceDetails> getServiceDetails() { return new Response(myController.getServiceDetails(),"Operation OK"); } }
This solution keeps your original mycontroller independent of rest code It seems that you need to include Jackson in the classpath so that spring can automatically and magically serialize JSON (see this for details)
edit
It seems that you need something more general... So here's a suggestion
@Controller @RequestMapping(value = "/mycontroller") public class MyGenericRestController { @Autowired private MyController myController; //this will match all "/myController/*" @RequestMapping(value = "/{operation}") public @ResponseBody Response getGenericOperation(String @PathVariable operation) { Method operationToInvoke = findMethodWithRequestMapping(operation); Object responseBody = null; try{ responseBody = operationToInvoke.invoke(myController); }catch(Exception e){ e.printStackTrace(); return new Response(null,"operation Failed"); } return new Response(responseBody,"Operation OK"); } private Method findMethodWithRequestMapping(String operation){ //TODO //This method will use reflection to find a method annotated //@RequestMapping(value=<operation>) //in myController return ... } }
And keep the original "mycontroller" almost as it is:
@Controller public class MyController { //this method is not expected to be called directly by spring MVC @RequestMapping(value = "/details") public ServiceDetails getServiceDetails() { return new ServiceDetails("MyService"); } }
The main problem is that @ requestmapping in mycontroller may need to be replaced by some custom annotations (and adjust findmethodwithrequestmapping to introspect this custom annotation)