I have several controllers that return the same generic Response object with @ResponseBody annotation, like this:
@RequestMapping(value = "/status", method = RequestMethod.GET)
@Transactional(readOnly = true)
public @ResponseBody Response<StatusVM> status()
I need to perform an operation on every controller, after the Response is returned. This operation will enrich the Response object with new data.
I don't want to duplicate code, so I need a single point of intervention. I thought I could do this with Interceptors, however, according to the docs http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-handlermapping-interceptor this does not work well with @ResponseBody:
Note that the postHandle method of HandlerInterceptor is not always ideally suited for use with @ResponseBody and ResponseEntity methods. In such cases an HttpMessageConverter writes to and commits the response before postHandle is called which makes it impossible to change the response, for example to add a header. Instead an application can implement ResponseBodyAdvice and either declare it as an @ControllerAdvice bean or configure it directly on RequestMappingHandlerAdapter.
I haven't been able to find an example of this tecnique, could anybody help me?
As an alternative I could work with aspects, but then I'd need to annotate every controller, which is something I'd like to avoid.
Send JSON Data in POST Spring provides a straightforward way to send JSON data via POST requests. The built-in @RequestBody annotation can automatically deserialize the JSON data encapsulated in the request body into a particular model object. In general, we don't have to parse the request body ourselves.
To return JSON from the server, you must include the JSON data in the body of the HTTP response message and provide a "Content-Type: application/json" response header. The Content-Type response header allows the client to interpret the data in the response body correctly.
The @ResponseBody annotation tells a controller that the object returned is automatically serialized into JSON and passed back into the HttpResponse object.
@RequestBody : Annotation indicating a method parameter should be bound to the body of the HTTP request. @ResponseBody annotation can be put on a method and indicates that the return type should be written straight to the HTTP response body (and not placed in a Model, or interpreted as a view name).
In the end I implemented ResponseBodyAdvice like this:
@ControllerAdvice
public class StatusAdvice implements ResponseBodyAdvice<Response<?>> {
@Override
public boolean supports(MethodParameter returnType,
Class<? extends HttpMessageConverter<?>> converterType) {
if (returnTypeIsReponseVM(returnType)&&responseConverterIsJackson2(converterType)){
return true;
}
return false;
}
....
@Override
public Response<?> beforeBodyWrite(Response<?> body, MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
....
return body;
}
}
So it was easier then expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With