Search code examples
javaspring-bootcontrollerinterceptorendpoint

Edit values of object with Interceptor before the controller


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.


Solution

  • 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;
        }
    }