Reputation: 9072
I would like to wrap the response of my @RestController
method into different object structure before Jackson starts to serialize the response to JSON. Let's say I work with the following Spring controller.
@RestController
@RequestMapping("/api/susu")
public class SusuController {
@RequestMapping(path = "/{id}", method = RequestMethod.GET)
public Susu hello(String id) {
Susu susu = new Susu();
susu.setDate(LocalDate.now());
susu.setName("Peter Pan");
return susu;
}
}
In JEE7 I used JAX-RS Interceptor the get access to the Susu
instance and wrap it.
@Provider
@Priority(1)
public class JsonStructureInterceptor implements WriterInterceptor {
private final JsonResponseBuilder jsonResponseBuilder = new JsonResponseBuilder();
@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
Susu s = (Susu) context.getEntity(); // read the JAX-RS response entity
JsonObject jsonObjectWithStructure = jsonResponseBuilder.toResponse(s); // wrap it
// add it back into the JAX-RS context
context.setEntity(jsonObjectWithStructure);
context.proceed();
}
}
When using Spring Boot what is the preferred way to to something equivalent without using JAX-RS features?
Update 1: Using a HandlerInterceptorAdapter
I added the following HandlerInterceptorAdapter
to my application context and the postHandle
method gets called. Everything works fine so far but I cannot figure out how to get the Susu
instance and how to pass the wrapped instance over for further processing.
@Component
public class SusuHandlerInterceptor extends HandlerInterceptorAdapter {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
Susu s = ; // how to get access to my Susu instance?
Wrapper w = new Wrapper(s);
// how to pass Wrapper instance on?
}
}
Update 2: Implementing a ResponseBodyAdvice
I found another approach that allows me to access the return value of my controller action. The problem here is that I cannot change the type of the return value. It seems it is not possible to wrap Susu
instance in a Wrapper
instance.
@ControllerAdvice
public class JsonFilter implements ResponseBodyAdvice<SusuController.Susu> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public SusuController.Susu beforeBodyWrite(SusuController.Susu body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return body;
}
}
Upvotes: 0
Views: 1310
Reputation: 7147
Implementing a ResponseBodyAdvice
lets you modify the object before it's converted.
If the return-type should be modified, one has to omit the Generic-types:
@ControllerAdvice
class JsonModifyingAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return new WrappedResponse(body);
}
}
Upvotes: 1