@Override protected ModelAndView doResolveException( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { if (handler != null) { Method handlerMethod = findBestExceptionHandlerMethod(handler, ex); if (handlerMethod != null) { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { Object[] args = resolveHandlerArguments(handlerMethod, handler, webRequest, ex); if (logger.isDebugEnabled()) { logger.debug("Invoking request handler method: " + handlerMethod); } Object retVal = doInvokeMethod(handlerMethod, handler, args); return getModelAndView(handlerMethod, retVal, webRequest); } catch (Exception invocationEx) { logger.error("Invoking request method resulted in exception : " + handlerMethod, invocationEx); } } } return null; }
@Override public void doWith(Method method) { method = ClassUtils.getMostSpecificMethod(method, handlerType); List<Class<? extends Throwable>> handledExceptions = getHandledExceptions(method); for (Class<? extends Throwable> handledException : handledExceptions) { if (handledException.isAssignableFrom(thrownExceptionType)) { if (!matchedHandlers.containsKey(handledException)) { matchedHandlers.put(handledException, method); } else { Method oldMappedMethod = matchedHandlers.get(handledException); if (!oldMappedMethod.equals(method)) { throw new IllegalStateException( "Ambiguous exception handler mapped for " + handledException + "]: {" + oldMappedMethod + ", " + method + "}."); } } } } } });
/** * Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}. */ private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, NativeWebRequest webRequest, Exception thrownException) throws Exception { Class<?>[] paramTypes = handlerMethod.getParameterTypes(); Object[] args = new Object[paramTypes.length]; Class<?> handlerType = handler.getClass(); for (int i = 0; i < args.length; i++) { MethodParameter methodParam = new SynthesizingMethodParameter(handlerMethod, i); GenericTypeResolver.resolveParameterType(methodParam, handlerType); Class<?> paramType = methodParam.getParameterType(); Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException); if (argValue != WebArgumentResolver.UNRESOLVED) { args[i] = argValue; } else { throw new IllegalStateException("Unsupported argument [" + paramType.getName() + "] for @ExceptionHandler method: " + handlerMethod); } } return args; }
/** * Resolves common method arguments. Delegates to registered {@link #setCustomArgumentResolver(WebArgumentResolver) * argumentResolvers} first, then checking {@link #resolveStandardArgument}. * @param methodParameter the method parameter * @param webRequest the request * @param thrownException the exception thrown * @return the argument value, or {@link WebArgumentResolver#UNRESOLVED} */ protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest, Exception thrownException) throws Exception { // Invoke custom argument resolvers if present... if (this.customArgumentResolvers != null) { for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { Object value = argumentResolver.resolveArgument(methodParameter, webRequest); if (value != WebArgumentResolver.UNRESOLVED) { return value; } } } // Resolution of standard parameter types... Class<?> paramType = methodParameter.getParameterType(); Object value = resolveStandardArgument(paramType, webRequest, thrownException); if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { throw new IllegalStateException( "Standard argument type [" + paramType.getName() + "] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) + "]. Consider declaring the argument type in a less specific fashion."); } return value; }
handlerMethod = getBestMatchingMethod(matchedHandlers, thrownException); handlers.put(thrownExceptionType, (handlerMethod == null ? NO_METHOD_FOUND : handlerMethod)); return handlerMethod;
return handleResponseBody(returnValue, webRequest);