3

I have already looked at a bunch of existing pages on stackoverflow for this but none of these helped:

How to customize @RequestParam error 400 response in Spring MVC

How to inform callers when required rquest parameter is missing?

My problem is extremely similar:

  • My application is really a REST api, returning json/xml data rather that html (ie I don't use jsps, but marshalling to transform java beans to json/xml)
  • When I query the URL with a required parameter, I get a 400 status with nothing in the payload, no text, nada.
  • I would like to return a json/xml payload using my ErrorResponse object that I use in other places.
  • I am using Spring 3.2.5
  • I have a controller which maps a URL to a method with a required parameter(candidateBillDay)

    @Controller
    public class AccountController extends WsController {
    
      private static final String JSP_CANDIDATE_PDD = "candidatepdd";
    
      @RequestMapping( value="/account/{externalId}/{externalIdType}/candidatepdd"
                     , method = RequestMethod.GET)
      public String getCandidatePaymentDueDateInfo( ModelMap model
                                                  , @PathVariable String externalId
                                                  , @PathVariable Integer externalIdType
                                                  , @RequestParam Integer candidateBillDay
                                                  , @RequestParam(required=false) Boolean includeCurrent ){
        ...
    
        model.addAttribute( CandidatePaymentDueDateResponse.ROOT_ELEMENT, ...));
    
        return JSP_CANDIDATE_PDD;
      }
    }
    
  • I have an exception handler that catches all types of exceptions, has some logic to do some specific bits for some types (instanceof):

    @ControllerAdvice
    public class BWSExceptionHandler extends ResponseEntityExceptionHandler {
      private static final Logger LOG = LoggerFactory.getLogger(BWSExceptionHandler.class);
      @ExceptionHandler(value = { Exception.class } )
      public ResponseEntity<Object> handleOtherExceptions(final Exception ex, final WebRequest req) {
        LOG.error("Uncaught Exception: ", ex);
        ErrorResponse resp = null;
        ...
        if( ex instanceof MissingServletRequestParameterException ){
          MissingServletRequestParameterException e = (MissingServletRequestParameterException)ex;
          resp = new ErrorResponse( Validatable.ERR_CODE_FIELD_NOT_POPULATED
                                  , String.format( Validatable.MSG_FIELD_IS_REQUIRED
                                                 , e.getParameterName()
                                                 )
                                  );
          httpStatusCode = HttpStatus.BAD_REQUEST;
        }
        if(resp==null){
          resp = new ErrorResponse(new ErrorElement("unknown_error", ex.getMessage()));
        }
        return handleExceptionInternal(ex, resp, new HttpHeaders(), httpStatusCode, req);
      }
    }
    

So this doesn't do anything when a parameter is missing. When I get an actual exception (ie account doesn't exist) then it does catch the exception and works as excepted. This leads me to think that no MissingServletRequestParameterException exception is thrown, which according to the doc, blogs and stackoverflow pages I've read should be thrown...

I have also tried implementing a class that extends DefaultHandlerExceptionResolver and override the handleMissingServletRequestParameter method with not much success ( following this blog: http://alexcuesta.wordpress.com/2011/05/11/error-handling-and-http-status-codes-with-spring-mvc/ )

Any idea of what I am doing wrong or what other option should I explore?

Community
  • 1
  • 1
XSen
  • 188
  • 1
  • 2
  • 9
  • Are you perhaps declaring any other exception handlers in XML? – geoand Apr 23 '14 at 12:43
  • nope; my application context simply defines DAOs, data source config and other app specific beans. The web.xml defines 1 servlet, maps it to the url-pattern, adds 1 filter to it. The servlet xml file defines a transaction manager and all the json/xml marshalling. Nothing exception handling specific – XSen Apr 23 '14 at 12:51
  • Does your exception handler work for other types of exceptions? – geoand Apr 23 '14 at 12:52
  • yes as mentioned in the question, when an exception is raised by either my code or spring JDBC the method in my BWSExceptionHandler class is called and works as expected. So it is wired properly as far as I can see; which is why I think the MissingServletRequestParameterException is not raised... – XSen Apr 23 '14 at 12:53
  • Perhaps maybe it's `ServletRequestBindingException`. Try that and let me now – geoand Apr 23 '14 at 12:59
  • The method catches anything extending Exception; if there is not something inside for the specific type, it will still return something with "unknown_error". Also there is some logging that I should see in the server logs but I don't. So to summarize, when required `@RequestParam` is missing, a 400 code is returned directly. without raising any exception catchable by `@ExceptionHandler`. – XSen Apr 23 '14 at 13:03
  • Ok, now I fully understand your issue. If I think of something I will post it – geoand Apr 23 '14 at 13:05

1 Answers1

4

Try overriding handleMissingServletRequestParameter method in the BWSExceptionHandler class.

@ControllerAdvice
public class BWSExceptionHandler extends ResponseEntityExceptionHandler {
  ...
  @Override
  protected ResponseEntity<Object> handleMissingServletRequestParameter(
      MissingServletRequestParameterException ex, HttpHeaders headers,
      HttpStatus status, WebRequest request) {
      // MissingServletRequestParameterException handling code goes here.
  }
  ...
  @ExceptionHandler(value = { Exception.class } )
  public ResponseEntity<Object> handleOtherExceptions(final Exception ex, 
    final WebRequest req) {
    ...
  }

}

Hope this helps.

Shinichi Kai
  • 4,415
  • 2
  • 21
  • 25
  • http://pastebin.com/v6B0VsyB Mine is not for some reason. Returns a blank page, when @RequestParam(value = "token", required = true), is not present – Devian Dec 04 '16 at 13:08