Skip to content

Commit

Permalink
Add BindException to DefaultHandlerExceptionResolver
Browse files Browse the repository at this point in the history
Previously DefaultHandlerExceptionResolver did not handle BindException
but after this change it does. A BindException is raised when an
@ModelAttribute annotated argument is not followed by a BindingResult
argument. Hence this is unlikely to affect browser rendering.
For programmatic clients however this change ensures an unhandled
BindException is at least turned into a 400 error.

Issue: SPR-9310
  • Loading branch information
rstoyanchev committed Jul 10, 2012
1 parent e860fa9 commit a1b7a31
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 6 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -32,12 +32,15 @@
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
Expand Down Expand Up @@ -65,6 +68,9 @@
* @see #handleHttpMessageNotReadable
* @see #handleHttpMessageNotWritable
* @see #handleMethodArgumentNotValidException
* @see #handleMissingServletRequestParameter
* @see #handleMissingServletRequestPart
* @see #handleBindException
*/
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {

Expand Down Expand Up @@ -136,6 +142,9 @@ else if (ex instanceof MethodArgumentNotValidException) {
else if (ex instanceof MissingServletRequestPartException) {
return handleMissingServletRequestPartException((MissingServletRequestPartException) ex, request, response, handler);
}
else if (ex instanceof BindException) {
return handleBindException((BindException) ex, request, response, handler);
}
}
catch (Exception handlerException) {
logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
Expand Down Expand Up @@ -346,8 +355,8 @@ protected ModelAndView handleHttpMessageNotWritable(HttpMessageNotWritableExcept
}

/**
* Handle the case where an argument annotated with {@code @Valid} such as
* an {@link RequestBody} or {@link RequestPart} argument fails validation.
* Handle the case where an argument annotated with {@code @Valid} such as
* an {@link RequestBody} or {@link RequestPart} argument fails validation.
* An HTTP 400 error is sent back to the client.
* @param request current HTTP request
* @param response current HTTP response
Expand All @@ -362,8 +371,8 @@ protected ModelAndView handleMethodArgumentNotValidException(MethodArgumentNotVa
}

/**
* Handle the case where an @{@link RequestPart}, a {@link MultipartFile},
* or a {@code javax.servlet.http.Part} argument is required but missing.
* Handle the case where an {@linkplain RequestPart @RequestPart}, a {@link MultipartFile},
* or a {@code javax.servlet.http.Part} argument is required but is missing.
* An HTTP 400 error is sent back to the client.
* @param request current HTTP request
* @param response current HTTP response
Expand All @@ -377,4 +386,21 @@ protected ModelAndView handleMissingServletRequestPartException(MissingServletRe
return new ModelAndView();
}

/**
* Handle the case where an {@linkplain ModelAttribute @ModelAttribute} method
* argument has binding or validation errors and is not followed by another
* method argument of type {@link BindingResult}.
* By default an HTTP 400 error is sent back to the client.
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler
* @return an empty ModelAndView indicating the exception was handled
* @throws IOException potentially thrown from response.sendError()
*/
protected ModelAndView handleBindException(BindException ex, HttpServletRequest request,
HttpServletResponse response, Object handler) throws IOException {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return new ModelAndView();
}

}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,6 +33,7 @@
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
Expand Down Expand Up @@ -157,6 +158,15 @@ public void handleMissingServletRequestPartException() throws Exception {
assertEquals("Invalid status code", 400, response.getStatus());
}

@Test
public void handleBindException() throws Exception {
BindException ex = new BindException(new Object(), "name");
ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex);
assertNotNull("No ModelAndView returned", mav);
assertTrue("No Empty ModelAndView returned", mav.isEmpty());
assertEquals("Invalid status code", 400, response.getStatus());
}

public void handle(String arg) {
}

Expand Down
1 change: 1 addition & 0 deletions src/dist/changelog.txt
Expand Up @@ -21,6 +21,7 @@ Changes in version 3.2 M2 (2012-08-xx)
* add defaultCharset property to StringHttpMessageConverter
* add @ExceptionResolver annotation to detect classes with @ExceptionHandler methods
* move RSS/Atom message converter registration ahead of jackson/jaxb2
* handle BindException in DefaultHandlerExceptionResolver


Changes in version 3.2 M1 (2012-05-28)
Expand Down

0 comments on commit a1b7a31

Please sign in to comment.