I wanted to modify a REST service with a change in the response.
The service was already doing what it was intended to do . There was a requirement to change certain things related to the representation of the response.
I didn’t want to change the existing code and clutter it with this logic.
So I used an advice instead.
Spring Boot provides RestControllerAdvice to handle this logic.
Here are the steps to do it:
STEP 1:
Create a RestControllerAdvice class (annotate a class with @RestControllerAdvice ) and implement ResponseBodyAdvice interface:
package com.springboot.restadvice;
import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice
public class RestAdvice implements ResponseBodyAdvice<T> {
}
STEP 2:
Implement the method required by the interface ResponseBodyAdvice (Replace <T> parameter in the interface with the return type of the REST service ):
package com.springboot.restadvice;
import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice
public class RestAdvice implements ResponseBodyAdvice<Map<String, String>> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
String className = returnType.getContainingClass().toString();
String methodName = returnType.getMethod().toString();
if (className.contains("RestController") && methodName.contains("modifyRestResponse")) {
return true;
}
return false;
}
@Override
public Map<String, String> beforeBodyWrite(Map<String, String> body, MethodParameter returnType,
MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
body.put("message", "Hi! This is Response Body Advice modifying the response");
return body;
}
}
There are two methods:
- supports()
- beforeBodyWrite()
the supports() method decides when to apply the advice.
In the above case I have checked for the class and the method for which I want to apply this advice.
the beforeBodyWrite() method lets you to modify the response.
In the above case I have put a message on the response .
That is all the change we need to do!
Here is the REST controller for which I am applying this advice:
package com.springboot.restadvice;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@org.springframework.web.bind.annotation.RestController
public class RestController {
@PostMapping("/modifyRESTResponse")
public Map<String, String> modifyRestResponse(@RequestBody Map<String,String> message) {
Map<String, String> result = new HashMap<>();
result.put("name", "Mr Spring Boot Advice");
result.putAll(message);
return result;
}
}
As you see , the above rest service just returns the message posted by the user along with the name “Mr Spring Boot Advice”.
Here is the response what I got before applying the advice:

And below is the response after applying the advice:

The response has been modified by the advice!
I have not touched the existing controller class.
This provides loose coupling for the logic I added. Also the same advice can be applied to multiple REST services.
Here is the code :
Leave a Reply