4

My rest controller

@RestController
public class MyController {

    @RequestMapping(value = "/getrawjson",  method =  RequestMethod.POST)
    public @ResponseBody
    String search(@RequestBody Map<String, Object> json, HttpServletRequest httpServletRequest) throws PushNotiException,Exception {
        return "OK";
    }
}

My Exception handling for invalid raw json post. I tried to use request.getInputStream() but I got the error

IllegalStateException: getInputStream() has already been called for this request

@ControllerAdvice
public class MethodArgumentNotValidExceptionHandler {

        @ExceptionHandler({org.springframework.http.converter.HttpMessageNotReadableException.class})
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        @ResponseBody
        public TrueIDResponse resolveException(HttpServletRequest request,Exception ex) throws IOException {

        }
}

I want to keep log input raw json data on this exception.

Anyone Can help me? Thanks.

Update

As @Sean Carrol suggestion. I tried to use HttpServletRequestWrapper following a suggestion but it's still not work.

@ControllerAdvice
public class MethodArgumentNotValidExceptionHandler {



    @ExceptionHandler({org.springframework.http.converter.HttpMessageNotReadableException.class})
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        @ResponseBody
        public TrueIDResponse resolveException(HttpServletRequest request,Exception ex) throws IOException {
            MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request);
            InputStream inputStream = multiReadRequest.getInputStream();
            String theString = IOUtils.toString(inputStream, "UTF-8");

        }
}

I got this error at the InputStream inputStream = multiReadRequest.getInputStream(); line.

java.io.IOException: Stream closed

Panup Pong
  • 1,871
  • 2
  • 22
  • 44

1 Answers1

0

I can solve this problem just add a filter , intercept the current HttpServletRequest and wrap it in a custom HttpServletRequestWrapper (MultipleReadHttpRequest)

@Component
public class CachingRequestBodyFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest currentRequest = (HttpServletRequest) servletRequest;
        MultipleReadHttpRequest wrappedRequest = new MultipleReadHttpRequest(currentRequest);
        chain.doFilter(wrappedRequest, servletResponse);
    }
}

MultipleReadHttpRequest class for servlet 3.0

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
    private ByteArrayOutputStream cachedBytes;

    public MultiReadHttpServletRequest(HttpServletRequest request) {
        super(request);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (cachedBytes == null)
            cacheInputStream();

        return new CachedServletInputStream();
    }

    @Override
    public BufferedReader getReader() throws IOException{
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    private void cacheInputStream() throws IOException {
    /* Cache the inputstream in order to read it multiple times. For
     * convenience, I use apache.commons IOUtils
     */
        cachedBytes = new ByteArrayOutputStream();
        IOUtils.copy(super.getInputStream(), cachedBytes);
    }

    /* An inputstream which reads the cached request body */
    public class CachedServletInputStream extends ServletInputStream {
        private ByteArrayInputStream input;

        public CachedServletInputStream() {
      /* create a new input stream from the cached request body */
            input = new ByteArrayInputStream(cachedBytes.toByteArray());
        }

        @Override
        public int read() throws IOException {
            return input.read();
        }

        @Override
        public boolean isFinished() {
            return input.available() == 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {
            throw new RuntimeException("Not implemented");
        }
    }
}
Panup Pong
  • 1,871
  • 2
  • 22
  • 44