there any option to edit values with Interceptor before the request goes to the controller?
I tried to wrap the HttpServletRequest and set the new body.
I have Post request in controller that looks like this :
@PostMapping("/edit-via-interceptor")
public MyObject getNewObjectFromInterceptor(@RequestBody MyObject myObject){
return myObject;}
The Object looks like this:
@Data
public class MyObject implements Serializable {
private List<String> ids;
}
The RequestBody has List of ids, and I want to add inside the interceptor 2 default id's to the current list.
The Interceptor looks like this:
@Component
public class Interceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpServletRequest httpRequest = request;
CustomHttpServletRequestWrapper wrapper = new CustomHttpServletRequestWrapper(httpRequest);
ObjectMapper objectMapper = new ObjectMapper();
MyObject newMyObject = objectMapper.readValue(wrapper.getInputStream(), MyObject.class);
List<String> newIdsList = newMyObject.getIds();
newIdsList.add("123");
newIdsList.add("1234");
newMyObject.setIds(newIdsList);
byte[] data = SerializationUtils.serialize(newMyObject);
wrapper.setBody(data);
return super.preHandle(wrapper, response, handler);
}
}
CustomHttpServletRequestWrapper looks like this:
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
public CustomHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
try {
body = IOUtils.toByteArray(request.getInputStream());
} catch (IOException ex) {
body = new byte[0];
}
}
public void setBody(byte[] body){
this.body = body;
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStream() {
ByteArrayInputStream bais = new ByteArrayInputStream(body);
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
}
}
The configuration on Interceptor pattern :
@Configuration
public class AuthConfig implements WebMvcConfigurer {
@Autowired
private Interceptor controllerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// The registration of /api/** must be in the end
registry.addInterceptor(controllerInterceptor).addPathPatterns("/**");
}
After all that, When its comes to the Controller - MyObject is null.
I did the same using @Arround
annotation. Here is the doc 6.2.4.5. Around advice (You need to search @around after going to the link). You can modify both the request and response.
There is also @Before
and @After
advice you can use if required. If you only need to access the object BEFORE controller is invoked, @Before
should be enough.
@Aspect
@Component
public class RequestModifierAspect {
@Around("execution(* com.example.YourController.methodName(..))")
public Object modifyRequest(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
// Modify the request object here
// For example, change a parameter value
request.setParameter("yourParam", "newValue");
// Proceed with the modified request
Object result = joinPoint.proceed();
// You can also modify the result returned by the controller method if needed
return result;
}
}