user1919346
user1919346

Reputation: 379

How to Prevent Stack Trace from Spring Rest API Exception Handler returning HTTP status 400

I am trying to handle Validation exception in Spring Rest service like code given below:

@Produces("application/json")
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public @ResponseBody ResponseEntity<ValidationErrorDTO> processValidationError(MethodArgumentNotValidException ex) {
        BindingResult result = ex.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();
        ResponseEntity<ValidationErrorDTO> re = new ResponseEntity<>(processFieldErrors(fieldErrors), HttpStatus.BAD_REQUEST);   
        return re;
    }

However when this code executes, it returns stack trace appended to the JSON response. I want to get rid of this stack trace and only return JSON error response. Is this possible with Spring 3.1?

{"fieldErrors":    
[{"field":"type","message":"Pattern.shippingAddress.type"}]}&lt;pre&gt;javax.servlet.ServletException: 400 Bad Request null
        at com.ebay.raptor.kernel.dispatcher.HttpDispatchCommand.execute(HttpDispatchCommand.java:142)
        at com.ebay.ebox.pres.cmd.preshandler.CommandDispatchHandler.handleRequest(CommandDispatchHandler.java:59)
        at com.ebay.ebox.pres.cmd.preshandler.CommandDispatchHandler.handleRequest(CommandDispatchHandler.java:13)
        at com.ebay.ebox.pres.cmd.preshandler.CommandHandlerFactory$CalHandler.handleRequest(CommandHandlerFactory.java:114)
        at com.ebay.ebox.pres.cmd.preshandler.CommandHandlerFactory$CalHandler.handleRequest(CommandHandlerFactory.java:75)
        at com.ebay.kernel.pipeline.RequestPipeline.invoke(RequestPipeline.java:18)
        at com.ebay.kernel.pipeline.RequestPipeline.invoke(RequestPipeline.java:12)
        at com.ebay.kernel.pipeline.BasePipeline.callHandler(BasePipeline.java:75)
        at com.ebay.kernel.pipeline.BasePipeline.execute(BasePipeline.java:53)
        at com.ebay.ebox.pres.stage.BaseCommandRequestStageImpl.doWork(BaseCommandRequestStageImpl.java:64)
        at com.ebay.kernel.stage.StageDriver.execute(StageDriver.java:55)
        at com.ebay.ebox.pres.cmd.WebCommandImpl.execute(WebCommandImpl.java:30)
        at com.ebay.raptor.web.RaptorFrontController.process(RaptorFrontController.java:338)
        at com.ebay.raptor.web.RaptorFrontController.doPost(RaptorFrontController.java:554)
        at com.ebay.raptor.web.RaptorGenericController.service(RaptorGenericController.java:64)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:749)
        at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:487)
        at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:379)
        at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339)
        at com.ebay.raptor.kernel.filter.RaptorDispatchFilter.doFilter(RaptorDispatchFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:195)
        at com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:266)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)
    &lt;/pre&gt;

Upvotes: 10

Views: 10309

Answers (7)

Felipe La Rotta
Felipe La Rotta

Reputation: 393

Another simpler way to do it

public static void main(String[] args) {


System.setProperty("server.error.include-message", "never");
System.setProperty("server.error.include-stacktrace", "never");

//You can also change other important properties with this method, for example:

// System.setProperty("server.port", "8081");
// System.setProperty("server.servlet.context-path", "/api");

SpringApplication.run(YourApplication.class, args);

}

The response will look like this;

{
    "timestamp": "2021-12-30T19:23:24.002+00:00",
    "status": 400,
    "error": "Bad Request",
    "path": "/test"
}

Upvotes: 0

Thor
Thor

Reputation: 17

@Order(Ordered.HIGHEST_PRECEDENCE)

Use @Order(Ordered.HIGHEST_PRECEDENCE) on your method it will work

Upvotes: 1

Sean Cunniffe
Sean Cunniffe

Reputation: 21

You could in your MethodArgumentNotValidException set the stack trace to null if the error is only being returned to the user and not be used for debugging.

Or alternatively, you could just override the getStackTrace() with a @JsonIgnore annotation

@JsonIgnore
@Override
public StackTraceElement[] getStackTrace() {
    return super.getStackTrace();
}

EDIT: I tried all the other solutions but none worked for me.

Upvotes: 1

nikiforovpizza
nikiforovpizza

Reputation: 576

You can just add the application property server.error.include-stacktrace=never which responds for including stack trace into 400 responses.

Upvotes: 9

Phelipe Maia
Phelipe Maia

Reputation: 21

You can do like this:

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ModelAndView methodArgumentError(HttpServletRequest req, Exception exception) {
    return new JsonError(exception.getMessage()).asModelAndView();
}

Upvotes: 2

Ralph
Ralph

Reputation: 120781

It is uncommon to use both: @ResponseBody and ResponseEntity. I think you should clearly decide what you want to do. - And then you should check your internal framework class com.ebay.raptor.kernel.dispatcher.HttpDispatchCommand, because this is the one that throws the exception.

Upvotes: 0

Maxim Gurenko
Maxim Gurenko

Reputation: 29

You can use Aspectj for these purposes. Example http://www.mkyong.com/spring3/spring-aop-aspectj-annotation-example/

You should write an aspect, which will catch your exception.

Example:

@Aspect
public class AroundExample {
 @Around
 pointcut = "execution(* your.package.Class.processValidationError(..))",
      throwing= "error")
 public Object doSomeStuff(ProceedingJoinPoint pjp, Throwable error) throws Throwable {

    Object[] args = joinPoint.getArgs(); // change the args if you want to
    Object retVal = pjp.proceed(args); // run the actual method (or don't)
    return retVal; // return the return value (or something else)
  }

}

Upvotes: -1

Related Questions