I am pretty new to thymeleaf and not too experienced with Spring. In my controller
#Controller
#RequestMapping("form")
#SessionAttributes(types = {Root.class /** another type here**/})
public class FormController extends BaseController {
#ModelAttribute("errorMap")
public Map<String,Integer> getErrorMap(Root root, BindingResult bindingResult) {
Map<String,Integer> result = new HashMap<>();
result.put("somevalue",5); // pretend there are 5 errors for somevalue.
// some logic here processing bindingResult
}
#GetMapping
public void show(#Valid Root root)
// do nothing here, just show the page
}
...
}
public class BaseController {
#ExceptionHandler
void handleBindException( BindException bindException,
Model model, HttpServletRequest request,
HttpSession session) throws Exception {
model.addAllAttributes(bindException.getModel());
addModelAttributes(model, request, true, session);
}
#ModelAttribute
public final void addModelAttributes( Model model, HttpServletRequest request,
boolean isException, HttpSession session) throws Exception {
if(GET.matches(request.getMethod()) || isException)
addModelAttributes(model);
}
}
}
In my form.html there is this part
<div th:if="${errorMap['somevalue']}>0" class="error"> <!-- marked line -->
<sup th:text="${errorMap['somevalue']}" class="error"></sup>
</div>
Now if there are no validation errors everything works fine, the show(...) method is called and a 5 is displayed. But if there is a validation error however there is an error org.attoparser.ParseException: Exception evaluating SpringEL expression: "errorMap['somevalue']" (template: "form" - line 38, col 8) caused by org.springframework.expression.spel.SpelEvaluationException: EL1012E: Cannot index into a null value in the marked line.
I expect this to work especially in case of validation errors. What am I doing wrong here or misunderstanding?
A simple, dirty quickfix is to add a method which adds the model attribute manually:
protected void addErrorAttribute(Model model) {
Root root = (Root)model.getAttribute("root");
BindingResult bindingResult = (BindingResult)model.getAttribute("org.springframework.validation.BindingResult.root");
model.addAttribute("errorMap", getErrorMap(root, bindingResult));
}
and call this method from the handleBindException(...) method.
Related
We are using spring and spring-security-3.2. Recently We are adding annotations #PreAuthorize to RestAPIs(earlier it was URL based).
#PreAuthorize("hasPermission('salesorder','ViewSalesOrder')")
#RequestMapping(value = "/restapi/salesorders/", method = RequestMethod.GET)
public ModelAndView getSalesOrders(){}
We already have Global exception handler which annotated with - #ControllerAdvice and custom PermissionEvaluator in place, everything works fine except the error message.
Lets say some user is accessing API At moment without having 'ViewSalesOrder' permission then spring by default throws the exception 'Access is denied',but didn't tell which permission is missing (Its our requirement to mention which permission is missing).
Is it possible to throw an exception which also include the permission name, so final error message should be look like "Access is denied, you need ViewSalesOrder permission"(here permission name should be from #PreAuthorize annotation)?
Please note that we have 100 such restAPI in place so generic solution will be highly appreciated.
There is no pretty way of achieving what you expect since PermissionEvaluator interface doesn't let you pass the missing permission along with the result of the evaluation.
In addition, AccessDecisionManager decides on the final authorization with respect to the votes of the AccessDecisionVoter instances, one of which is PreInvocationAuthorizationAdviceVoter which votes with respect to the evaluation of #PreAuthorize value.
Long story short, PreInvocationAuthorizationAdviceVoter votes against the request (giving the request –1 point) when your custom PermissionEvaluator returns false to hasPermission call. As you see there is no way to propagate the cause of the failure in this flow.
On the other hand, you may try some workarounds to achieve what you want. One way can be to throw an exception within your custom PermissionEvaluator when permission check fails. You can use this exception to propagate the missing permission to your global exception handler. There, you can pass the missing permission to your message descriptors as a parameter. Beware that this will halt execution process of AccessDecisionManager which means successive voters will not be executed (defaults are RoleVoter and AuthenticatedVoter). You should be careful if you choose to go down this path.
Another safer but clumsier way can be to implement a custom AccessDeniedHandler and customize the error message before responding with 403. AccessDeniedHandler provides you current HttpServletRequest which can be used to retrieve the request URI. However, bad news in this case is, you need a URI to permission mapping in order to locate the missing permission.
I have implemented the second possible solution mentioned by Mert Z. My solution works only for #PreAuthorize annotations used in the API layer (e.g. with #RequestMapping). I have registered a custom AccessDeniedHandler bean in which I get the value of the #PreAuthorize annotation of the forbidden API method and fills it into error message.
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private DispatcherServlet dispatcherServlet;
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException,
ServletException {
if (!response.isCommitted()) {
List<HandlerMapping> handlerMappings = dispatcherServlet.getHandlerMappings();
if (handlerMappings != null) {
HandlerExecutionChain handler = null;
for (HandlerMapping handlerMapping : handlerMappings) {
try {
handler = handlerMapping.getHandler(request);
} catch (Exception e) {}
if (handler != null)
break;
}
if (handler != null && handler.getHandler() instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler.getHandler();
PreAuthorize methodAnnotation = method.getMethodAnnotation(PreAuthorize.class);
if (methodAnnotation != null) {
response.sendError(HttpStatus.FORBIDDEN.value(),
"Authorization condition not met: " + methodAnnotation.value());
return;
}
}
}
response.sendError(HttpStatus.FORBIDDEN.value(),
HttpStatus.FORBIDDEN.getReasonPhrase());
}
}
#Inject
public void setDispatcherServlet(DispatcherServlet dispatcherServlet) {
this.dispatcherServlet = dispatcherServlet;
}
}
The handler is registered in WebSecurityConfigurerAdapter:
#EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true)
#EnableWebSecurity
public abstract class BaseSecurityInitializer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
...
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
...
}
#Bean
public AccessDeniedHandler accessDeniedHandler() {
return new CustomAccessDeniedHandler();
}
}
Beware that if there is also a global resource exception handler with #ControllerAdvice the CustomAccessDeniedHandler won't be executed. I solved this by rethrowing the exception in the global handler (as advised here https://github.com/spring-projects/spring-security/issues/6908):
#ControllerAdvice
public class ResourceExceptionHandler {
#ExceptionHandler(AccessDeniedException.class)
public ResponseEntity accessDeniedException(AccessDeniedException e) throws AccessDeniedException {
log.info(e.toString());
throw e;
}
}
You can throw an org.springframework.security.access.AccessDeniedException from a method that was called inside an EL-Expression:
#PreAuthorize("#myBean.myMethod(#myRequestParameter)")
Ideally, the #PreAuthorize annotation should be supporting String message(); in addition to the SpEl value. But, for whatever reason, it does not. Most of the suggestions here seem unnecessarily cumbersome and elaborate. As #lathspell has suggested, the simplest way to provide your own error message - along with any custom access validation logic - would be to add a simple method that performs the check and throws the AccessDeniedException in case the check fails, and then reference that method in the SpEl expression. Here's an example:
#RestController
#RequiredArgsConstructor // if you use lombok
public class OrderController {
private final OrderService orderService;
...
#GetMapping(value = "/salesorders", produces = MediaType.APPLICATION_JSON_VALUE)
#PreAuthorize("#orderController.hasPermissionToSeeOrders(#someArgOfThisMethod)")
public Page<OrderDto> getSalesOrders(
// someArgOfThisMethod here, perhaps HttpRequest, #PathVariable, #RequestParam, etc.
int pageIndex, int pageSize, String sortBy, String sortOrder) {
Pageable pageRequest = PageRequest.of(pageIndex, pageSize, Sort.Direction.fromString(sortOrder), sortBy);
return ordersService.retrieveSalesOrders(..., pageRequest);
}
public static Boolean hasPermissionToSeeOrders(SomeArgOfTheTargetMethod argToEvaluate) {
//check eligibility to perform the operation based on some data from the incoming objects (argToEvaluate)
if (condition fails) {
throw new AccessDeniedException("Your message");
}
return true;
}
I am trying to capture all exceptions of some class in my Controller class. It works fine when
I define it like this:
#ExceptionHandler(NoSearchResultException.class)
public String handleNoSearchResultException() {
return "someView";
}
But not if I add any parameters:
#ExceptionHandler(NoSearchResultException.class)
public String handleNoSearchResultException(Exception e) {
return "someView";
}
What could possibly be happening? Also, I've read #ExceptionHandler does not support Model arguments, so how would I pass a parameter (like the error message for instance) to the view in order to offer a dynamic error page?
To pass a parameter to the view I would create a custom Exception class in which you can store any required model parameters (such as error messages). Then in #ExceptionHandler method you can extract those model parameters and make them available in the view. For example:
class RequestException extends RuntimeException {
...
public void setErrorMessages(List<String> errorMsgs) {
this.errorMessages = errorMsgs
}
...
}
#ExceptionHandler(RequestException.class)
public ModelAndView handleNoSearchResultException(RequestException ex) {
ModelAndView mav = new ModelAndView("someView");
mav.addObject("errors", ex.getErrorMessages()); //fetch error messages
return mav;
}
As for parameters, try specifying NoSearchResultException as method parameter instead of it's Exception superclass.
EDIT:
Had a bug in 2nd example return value.
I Solved the problem by passing the custom arguments in request itself.
code is as below :
Controller
#RequestMapping(method = RequestMethod.GET, value = "/exception2")
public String getException1(ModelMap model, #CRequestParam("p") String p, HttpServletRequest request) {
System.out.println("Exception 2 " + p);
request.setAttribute("p", p);
throw new CustomGenericException("1", "2");
}
Exception Handler
#ExceptionHandler(CustomGenericException.class)
public ModelAndView handleCustomException(CustomGenericException ex, HttpServletRequest request) {
ModelAndView model2 = new ModelAndView("error/generic_error");
model2.addObject("exception", ex);
System.out.println(request.getAttribute("p"));
System.out.println("CustomGenericException ");
return model2;
}
here is Sackoverflow question and its answer and
Complete source code is available at git
I am currently trying to use HandlerExceptionResolver for exception handling in a Spring MVC project.
I want to handle normal exceptions via resolveException as well as 404's via
handleNoSuchRequestHandlingMethod.
Depending on the request type JSON or text/html the exception response should be returned appropriately.
resolveException works now.
But handleNoSuchRequestHandlingMethod is giving me a headache. It's never called!
According to the docu the method should be called on 404 errors
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.html
What am I doing wrong...
This is what I have so far.
public class JsonExceptionResolver implements HandlerExceptionResolver {
protected final Log logger = LogFactory.getLog(getClass());
public ModelAndView resolveException(HttpServletRequest request,
if (exception instanceof NoSuchRequestHandlingMethodException) {
return handleNoSuchRequestHandlingMethod((NoSuchRequestHandlingMethodException) exception, request, response, handler);
}
...
}
public ModelAndView handleNoSuchRequestHandlingMethod(NoSuchRequestHandlingMethodException ex,
HttpServletRequest request,
HttpServletResponse response,
Object handler){
logger.info("Handle my exception!!!");
ModelAndView mav = new ModelAndView();
boolean isJSON = request.getHeader("Accept").equals("application/json");
if(isJSON){
...
}else{
..
}
return mav;
}
}
EDIT with DefaultHandlerExceptionResolver:
public class MyExceptionResolver extends DefaultHandlerExceptionResolver {
protected final Log logger = LogFactory.getLog(getClass());
#Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
logger.warn("An Exception has occured in the application", exception);
logger.info("exception thrown " + exception.getMessage() );
if (exception instanceof NoSuchRequestHandlingMethodException) {
return handleNoSuchRequestHandlingMethod((NoSuchRequestHandlingMethodException) exception, request, response, handler);
}
...
return mav;
}
public ModelAndView handleNoSuchRequestHandlingMethod(NoSuchRequestHandlingMethodException ex,
HttpServletRequest request,
HttpServletResponse response,
Object handler){
logger.info("Handle my exception!!!");
ModelAndView mav = new ModelAndView();
boolean isJSON = request.getHeader("Accept").equals("application/json");
if(isJSON){
...
}else{
...
}
return mav;
}
}
The above code still has no effect.
Any other ideas?
According to Juergen Hoeller from Spring, it isn't possible with the HandlerExceptionResolver because it only works for sub-mapping e.g.
you have a controller mapped to /account/** and accesss a method from acount where no mapping exists like /acount/notExists than it should work.
I will open a JIRA improvement ticket for this functionality
EDIT:
JIRA ticket about this issue
https://jira.springsource.org/browse/SPR-8837?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=72648#comment-72648
handleNoSuchRequestHandlingMethod isn't part of the HandlerExceptionResolver interface, so just declaring a method of that name will do nothing. It's a protected method specific to DefaultHandlerExceptionResolver, and is called from its resolveException method (which is part of the interface):
if (ex instanceof NoSuchRequestHandlingMethodException) {
return handleNoSuchRequestHandlingMethod((NoSuchRequestHandlingMethodException) ex, request, response, handler);
}
To reproduce the same functionality, you can either subclass DefaultHandlerExceptionResolver and override the methods you need to, or you need to add a case in your resolveException method that handles NoSuchRequestHandlingMethodException.
Situation
I'm trying to group the code that logs the exceptions and render a nice view in a few methods. At the moment the logic is sometime in the #RequestHandler itself (in the a catch block), othertimes is delegated to an utility class (that works but moves the logic away from the place where the exception is thrown).
Spring's #ExceptionHandler seemed the way to group everything in one place (the controller itself or a parent) and get rid of some code (no need to put logic in the try-catch and no need for an utility class)... until I realized that an #ExceptionHandler methods won't have the ModelMap or BindingResult parameters autowired. Currently those objects are used to render the view with a sensible error message and we want to log some information contained in these objects as well.
Question
Why Spring doesn't not support method arguments such ModelMap or BindingResult for the #ExceptionHandler? What is the rationale behind it?
Possible solution
In the Spring source code (3.0.5) the arguments for the method are resolved in the HandlerMethodInvoker.invokeHandlerMethod. A an exception thrown by the request handler is caught there and re-thrown. The #ExceptionHandler and it's parameters are resolved elsewhere. As a workaround I thought to check if the Exception implements an hypothetical "ModelAware" or "BindingResultAware" interface, and in that case set Model and BindingResult attributes before re-throwhing it.
How does it sound?
As stated before you can raise an exception wrapping a binding result object in some method of your controller:
if (bindingResult.hasErrors()) {
logBindingErrors(bindingResult);
//return "users/create";
// Exception handling happens later in this controller
throw new BindingErrorsException("MVC binding errors", userForm, bindingResult);
}
With your exception defined as illustrated here:
public class BindingErrorsException extends RuntimeException {
private static final Logger log = LoggerFactory.getLogger(BindingErrorsException.class);
private static final long serialVersionUID = -7882202987868263849L;
private final UserForm userForm;
private final BindingResult bindingResult;
public BindingErrorsException(
final String message,
final UserForm userForm,
final BindingResult bindingResult
) {
super(message);
this.userForm = userForm;
this.bindingResult = bindingResult;
log.error(getLocalizedMessage());
}
public UserForm getUserForm() {
return userForm;
}
public BindingResult getBindingResult() {
return bindingResult;
}
}
Next you just have to extract the required information from the raised then caught exception. Here assuming you have a suitable exception handler defined on your controller. It might be in a controller advice instead or even elewhere. See the Spring documentation for suitable and appropriate locations.
#ExceptionHandler(BindingErrorsException.class)
public ModelAndView bindingErrors(
final HttpServletResponse resp,
final Exception ex
) {
if(ex instanceof BindingErrorsException) {
final BindingErrorsException bex = (BindingErrorsException) ex;
final ModelAndView mav = new ModelAndView("users/create", bex.getBindingResult().getModel());
mav.addObject("user", bex.getUserForm());
return mav;
} else {
final ModelAndView mav = new ModelAndView("users/create");
return mav;
}
}
I ran into to same problem a while ago. The ModelMap or BindingResult are explicitly not listed as supported argument types in the JavaDocs of #ExceptionHandler, so this must have been intentional.
I reckon the reason behind it being that throwing exceptions in general could leave your ModelMap in an inconsistent state. So depending on your situation you might consider
Explicitly catch the exception to tell Spring MVC that you know what you're doing (you could use the Template pattern to refactor exception handling logic into one single place)
If you're in control of the exception hierarchy you could hand over the BindingResult to the exception and extract it from the exception later for rendering purposes
Not throw an exception in the first place, but use some result code (just like BeanValidation does for example)
HTH
To improve the first answer:
#ExceptionHandler(value = {MethodArgumentNotValidException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public VndErrors methodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
List<ObjectError> globalErrors = ex.getBindingResult().getGlobalErrors();
List<VndError> errors = new ArrayList<>(fieldErrors.size() + globalErrors.size());
VndError error;
for (FieldError fieldError : fieldErrors) {
error = new VndError(ErrorType.FORM_VALIDATION_ERROR.toString(), fieldError.getField() + ", "
+ fieldError.getDefaultMessage());
errors.add(error);
}
for (ObjectError objectError : globalErrors) {
error = new VndError(ErrorType.FORM_VALIDATION_ERROR.toString(), objectError.getDefaultMessage());
errors.add(error);
}
return new VndErrors(errors);
}
There is already MethodArgumentNotValidException has already a BindingResult object, and you can use it, if you don't need to create an specific exception for this purpose.
I had the same problem to "add" FunctinalException to ourthe BindingResult
To resolve it, we use aop, if the controller method throws a runtime exception (or the one you want),
the aop catch it and update the bindingresult or model (if they are args of the method).
The method has to be annoted with a specific annotation containing the error path (configurable for specific exception if necessary).
It is not the best way because developer must not forget to add args that he don't use in its method but Spring does not provide a simple system to do this need.
I've wondered this too.
In order to handle bean validation in a way that allows for a non-global error view to display any ConstraintViolationExceptions that may be thrown, I opted for a solution along the lines of what #Stefan Haberl proposed:
Explicitly catch the exception to tell Spring MVC that you know what you're doing (you could use the Template pattern to refactor exception handling logic into one single place)
I created a simple Action interface:
public interface Action {
String run();
}
And an ActionRunner class which does the work of ensuring ConstraintViolationExceptions are handled nicely (basically the messages from each ConstraintViolationException is simply added to a Set and added to the model):
public class ActionRunner {
public String handleExceptions(Model model, String input, Action action) {
try {
return action.run();
}
catch (RuntimeException rEx) {
Set<String> errors = BeanValidationUtils.getErrorMessagesIfPresent(rEx);
if (!errors.isEmpty()) {
model.addAttribute("errors", errors);
return input;
}
throw rEx;
}
}
}
Java 8 makes this pretty nice to run within the controller action method:
#RequestMapping(value = "/event/save", method = RequestMethod.POST)
public String saveEvent(Event event, Model model, RedirectAttributes redirectAttributes) {
return new ActionRunner().handleExceptions(model, "event/form", () -> {
eventRepository.save(event);
redirectAttributes.addFlashAttribute("messages", "Event saved.");
return "redirect:/events";
});
}
This is to wrap up those action methods for which I'd like to explicitly handle exceptions that could be thrown due to Bean Validation. I still have a global #ExceptionHandler but this deals with only "oh crap" exceptions.
Actually it does, just create an #ExceptionHandler method for MethodArgumentNotValidException.
That class gives you access to a BindingResult object.
I am having trouble with catching and gracefully handling commons fileupload's FileUploadBase.SizeLimitExceededException or spring's MaxUploadSizeExceededException when uploading large files.
From what I can tell these exceptions are thrown during data binding, before the controller is actually reached, therefore resulting in a 500 and no calling of the exception handler method. Has anyone come across this before, and what is the best way for handling these exceptions properly?
thanks to thetoolman for this simple solution. I extended it a bit. I wanted to leave the file handling untouched and transport the Exception to the Controller.
package myCompany;
public class DropOversizeFilesMultipartResolver extends CommonsMultipartResolver {
/**
* Parse the given servlet request, resolving its multipart elements.
*
* Thanks Alexander Semenov # http://forum.springsource.org/showthread.php?62586
*
* #param request
* the request to parse
* #return the parsing result
*/
#Override
protected MultipartParsingResult parseRequest(final HttpServletRequest request) {
String encoding = determineEncoding(request);
FileUpload fileUpload = prepareFileUpload(encoding);
List fileItems;
try {
fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
} catch (FileUploadBase.SizeLimitExceededException ex) {
request.setAttribute(EXCEPTION_KEY, ex);
fileItems = Collections.EMPTY_LIST;
} catch (FileUploadException ex) {
throw new MultipartException("Could not parse multipart servlet request", ex);
}
return parseFileItems(fileItems, encoding);
}
}
and in the controller
#InitBinder("fileForm")
protected void initBinderDesignForm(WebDataBinder binder) {
binder.setValidator(new FileFormValidator());
}
#RequestMapping(value = "/my/mapping", method = RequestMethod.POST)
public ModelAndView acceptFile(HttpServletRequest request, Model model, FormData formData,
BindingResult result) {
Object exception = request.getAttribute(DropOversizeFilesMultipartResolver.EXCEPTION_KEY);
if (exception != null && FileUploadBase.SizeLimitExceededException.class.equals(exception.getClass())) {
result.rejectValue("file", "<your.message.key>");
LOGGER.error(exception);
}
the spring config remains the same. It would be really nice to have the exception transported to the validator, but I haven't figured out how to do this yet.
I know this is old, but I was looking for a solution to this as well and could not find anything. We are providing RESTful services using Spring and we are doing file upload and were not sure how to handle this. I came up with the following and hopefully it will be useful to someone:
All our exceptions are handled with annotations, so we have our error handler resolver set-up like this:
#Configuration
public class MyConfig{
#Bean
public AnnotationMethodHandlerExceptionResolver exceptionResolver(){
final AnnotationMethodHandlerExceptionResolver resolver = new AnnotationMethodHandlerExceptionResolver();
resolver.setMessageConverters(messageConverters());
resolver;
}
}
Then a common class that can handle the exception
public class MultipartExceptionHandler
{
#ExceptionHandler(MaxUploadSizeExceededException.class)
#ResponseStatus(value = HttpStatus.PRECONDITION_FAILED)
#ResponseBody
protected CustomError handleMaxUploadSizeExceededException(final HttpServletRequest request,
final HttpServletResponse response, final Throwable e)
throws IOException
{
logger.error(e);
CustomError c = new CustomErrorMaxFileSize("Max file size exceeded", MAX_FILE_SIZE);
return c;
}
#ExceptionHandler(MultipartException.class)
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ResponseBody
protected CustomError handleGenericMultipartException(final HttpServletRequest request,
final HttpServletResponse response, final Throwable e)
throws IOException
{
logger.error(e);
CustomError c = new CustomErrorGeneric("There was a problem with the upload");
return c;
}
}
Then we subclass the commons multipart resolver and implement the HandlerExceptionResolver interface
#Component(value="multipartResolver") // Spring expects this name
public class MyMultipartResolver extends CommonsMultipartResolver implements HandlerExceptionResolver
{
// This is the Spring bean that handles exceptions
// We defined this in the Java configuration file
#Resource(name = "exceptionResolver")
private AnnotationMethodHandlerExceptionResolver exceptionResolver;
// The multipart exception handler with the #ExceptionHandler annotation
private final MultipartExceptionHandler multipartExceptionHandler = new MultipartExceptionHandler();
// Spring will call this when there is an exception thrown from this
// multipart resolver
#Override
public ModelAndView resolveException(
final HttpServletRequest request,
final HttpServletResponse response,
final Object handlerParam,
final Exception ex)
{
// Notice that we pass this.multipartExceptionHandler
// and not the method parameter 'handlerParam' into the
// exceptionResolver. We do this because the DispatcherServlet
// doDispatch() method calls checkMultipart() before determining
// the handler for the request. If doing the multipart check fails
// with a MultipartException, Spring will never have a reference
// to the handler and so 'handlerParam' will be null at this point.
return exceptionResolver.resolveException(request, response, this.multipartExceptionHandler, ex);
}
}
This seems to be a quite common problem. I've had similar problems and similar questions have been asked, see for example this question. I have yet to see a nice solution to the problem. You could use a vanilla servlet filter to handle these exceptions, but that will duplicate your error handling since you already have an ExceptionHandler.