'HttpServletRequestWrapper not working in Spring MVC

I am developing a custom log with Spring MVC to get information from all incoming request. I would like to grab both the request body and response body. The issue is, even if I create a HttpServletRequestWrapper, I cannot forward the request after I process and wrap the request.

Here is my code:

Interceptor

@Component
public class LoggerInterceptor implements HandlerInterceptor{

    final static org.apache.log4j.Logger log = Logger.getLogger(LoggerInterceptor.class.getName());

    /**
     * Executed before actual handler is executed
     **/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        long start = System.currentTimeMillis();
        
        MyRequestWrapper requestWrapper = new MyRequestWrapper(request);
        
        
        SimpleDateFormat f = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:SSS");
        String date = f.format(new Date());
        UUID uuid = UUID.randomUUID();
        
        
        String method = requestWrapper.getMethod();
        String uri = requestWrapper.getRequestURI();
        String step = "Default Step";
        String url = String.valueOf(requestWrapper.getRequestURL());
        
        
        String serverName = requestWrapper.getServerName();
        String reqBody = IOUtils.toString(requestWrapper.getInputStream(), Charset.forName("UTF-8").toString());
        
        CustomHttpResponseWrapper responseWrapper = new CustomHttpResponseWrapper(response);
        
        long end = System.currentTimeMillis() - start;

        String status = String.valueOf(responseWrapper.getStatus());

        String resBody = new String(responseWrapper.getBaos().toByteArray());
        
        if(step!=null && !step.isEmpty()) {
            log.info("INFO " + date + " " + uuid + "\n" +
                    "ID : " + getCurrentlyDateTime()  + "\n" +
                    "STEP : " + step + "\n" +
                    "Request URL: " + url + "\n" +
                    "Host : " + serverName + "\n" +
                    "Request Body : " + reqBody + "\n" +
                    "Response Status : " + status + "\n" +
                    "Response Body : " + resBody + "\n" +
                    "Response Time : " + end);
        }
        
        return true;
    }
}

Request Wrapper

public class MyRequestWrapper extends HttpServletRequestWrapper {
     private final String body;
     
     public MyRequestWrapper(HttpServletRequest request) throws IOException {
           super(request);
           StringBuilder stringBuilder = new StringBuilder();
           BufferedReader bufferedReader = null;
           try {
                 InputStream inputStream = request.getInputStream();
                 if (inputStream != null) {
                   bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                   char[] charBuffer = new char[128];
                   int bytesRead = -1;
                   while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                     stringBuilder.append(charBuffer, 0, bytesRead);
                   }
                 } else {
                   stringBuilder.append("");
                 }
           } catch (IOException ex) {
                throw ex;
           } finally {
                 if (bufferedReader != null) {
                       try {
                           bufferedReader.close();
                       } catch (IOException ex) {
                           throw ex;
                       }
                 }
           }
           body = stringBuilder.toString();
     }
    
     
     @Override
     public ServletInputStream getInputStream() throws IOException {
           final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
           ServletInputStream servletInputStream = new ServletInputStream() {
                 public int read() throws IOException {
                     return byteArrayInputStream.read();
                 }

                @Override
                public boolean isFinished() {
                    // TODO Auto-generated method stub
                    return false;
                }

                @Override
                public boolean isReady() {
                    // TODO Auto-generated method stub
                    return false;
                }

                @Override
                public void setReadListener(ReadListener readListener) {
                    // TODO Auto-generated method stub
                    
                }
           };
           return servletInputStream;
     }
    
     @Override
     public BufferedReader getReader() throws IOException {
         return new BufferedReader(new InputStreamReader(this.getInputStream()));
     }
    
     public String getBody() {
         return this.body;
     }
}

Output

INFO 2022/04/12 10:35:18:578 d00ec778-2a6e-4a72-a0e0-9649c13776eb
ID : 20220412103518
STEP : Default Step
Request URL: http://localhost:8080/com.ihcs.api.mobile/loginNew
Host : localhost
Request Body : {
    "username":"P0****",
    "sessionid":"*************************",
    "password":"********",
    "companyCode":"***",
    "UniqueId":"**********",
    "Manufacturer":"google",
    "Brand":"google",
    "Model":"*******",
    "DeviceId":"*******",
    "FcmTokens":"*******",
    "UniqueLogin":false
}
Response Status : 200
Response Body : 
Response Time : 18
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: Stream closed

I've tried some suggestions from stack overflow but still can't help. Thank you.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source