Jdk1.8, spring v4.3.9. RELEASE
For springMVC projects through inheritance SimpleMappingExceptionResolver class implements the class global exception handling function. However, there are some cases where exceptions thrown cannot be handled uniformly by custom exception resolvers, such as TypeMismatchException caused by a rest interface parameter type error.
The original code is as follows
public class ExceptionHandler extends SimpleMappingExceptionResolver {
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { String message = ex.getMessage(); String forward = Constant.ERROR_URL; JsonResponse JsonResponse = null;if (ex instanceof UnloginException) {
jsonResponse = JsonResponse.unlogin(message);
forward = Constant.LOGIN_URL;
} else if (ex instanceof UnauthorizedException) {
jsonResponse = JsonResponse.unauthorized(message);
} else if (ex instanceof UnvalidatedException) {
jsonResponse = JsonResponse.unvalidated(message);
} else if (ex instanceof ForbiddenException) {
jsonResponse = JsonResponse.forbidden(message);
} else {
message = "Internal system error";
jsonResponse = JsonResponse.serverInternalError(message);
}
if (UtilRequest.isAjaxRequest(request) || UtilRequest.isMultipartContent(request)) {
writeJson(response, jsonResponse);
return null;
}
return new ModelAndView(forward, "message", jsonResponse.getMessage());
}
private void writeJson(HttpServletResponse response, Object object) {
response.setContentType("application/json;");
PrintWriter pw = null;
try {
pw = response.getWriter();
pw.write(UtilJson.toJson(object));
} catch (IOException e) {
logger.error(e);
} finally {
if(pw ! = null) { pw.close(); }}}}Copy the code
I started with the idea of catching thrown exceptions in filter, but found exceptions that I couldn’t get anyway, and then came across an article: For instructions on catching Struts2 exceptions in filter, According to this idea is indeed found in the request of the attribute to be processed after the EXCEPTION “org. Springframework. Web. Servlet. DispatcherServlet. EXCEPTION”.
So I went down to the DispatcherServlet and found the problem in the processHandlerException method
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // Check registered HandlerExceptionResolvers... ModelAndView exMv = null; // This iterates through all exception parsers in one step and executes resolveException, breaking out of the loop if the return is not emptyfor (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if(exMv ! = null) {break; }}if(exMv ! = null) {if(exmv.isempty ()) {request. SetAttribute (EXCEPTION_ATTRIBUTE, ex);return null;
}
// We might still need view name translation for a plain error model...
if(! exMv.hasView()) { exMv.setViewName(getDefaultViewName(request)); }if (logger.isDebugEnabled()) {
logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
throw ex;
}
Copy the code
Breaking point, found in the traversal by DefaultHandlerExceptionResolver will jump out of the loop, so continue to enter DefaultHandlerExceptionResolver.
@Override
@SuppressWarnings("deprecation")
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
try {
if (ex instanceof org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException) {
returnhandleNoSuchRequestHandlingMethod((org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException) ex, request, response, handler); }else if (ex instanceof HttpRequestMethodNotSupportedException) {
return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request,
response, handler);
}
else if (ex instanceof HttpMediaTypeNotSupportedException) {
return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response,
handler);
}
else if (ex instanceof HttpMediaTypeNotAcceptableException) {
return handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException) ex, request, response,
handler);
}
else if (ex instanceof MissingPathVariableException) {
return handleMissingPathVariable((MissingPathVariableException) ex, request,
response, handler);
}
else if (ex instanceof MissingServletRequestParameterException) {
return handleMissingServletRequestParameter((MissingServletRequestParameterException) ex, request,
response, handler);
}
else if (ex instanceof ServletRequestBindingException) {
return handleServletRequestBindingException((ServletRequestBindingException) ex, request, response,
handler);
}
else if (ex instanceof ConversionNotSupportedException) {
return handleConversionNotSupported((ConversionNotSupportedException) ex, request, response, handler);
}
else if (ex instanceof TypeMismatchException) {
return handleTypeMismatch((TypeMismatchException) ex, request, response, handler);
}
else if (ex instanceof HttpMessageNotReadableException) {
return handleHttpMessageNotReadable((HttpMessageNotReadableException) ex, request, response, handler);
}
else if (ex instanceof HttpMessageNotWritableException) {
return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, request, response, handler);
}
else if (ex instanceof MethodArgumentNotValidException) {
return handleMethodArgumentNotValidException((MethodArgumentNotValidException) ex, request, response,
handler);
}
else if (ex instanceof MissingServletRequestPartException) {
return handleMissingServletRequestPartException((MissingServletRequestPartException) ex, request,
response, handler);
}
else if (ex instanceof BindException) {
return handleBindException((BindException) ex, request, response, handler);
}
else if (ex instanceof NoHandlerFoundException) {
return handleNoHandlerFoundException((NoHandlerFoundException) ex, request, response, handler);
}
else if (ex instanceof AsyncRequestTimeoutException) {
return handleAsyncRequestTimeoutException(
(AsyncRequestTimeoutException) ex, request, response, handler);
}
}
catch (Exception handlerException) {
if (logger.isWarnEnabled()) {
logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException); }}return null;
}
Copy the code
DefaultHandlerExceptionResolver do to deal with anomalies, including TypeMismatchException, and in their respective treatment method returns a new ModelAndView (), Request. setAttribute(EXCEPTION_ATTRIBUTE, ex) is executed.
The reason why the exception was not caught in the filter has been found, but it is not the problem I want to solve.
In processHandlerException traversal enclosing handlerExceptionResolvers, they found a custom ExceptionHandler behind DefaultHandlerExceptionResolver. Cause DefaultHandlerExceptionResolver processing TypeMismatchException, jump out of the loop without executing ExceptionHandler directly.
Continue to follow this. HandlerExceptionResolvers, can see
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {
// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true.false);
if(! matchingBeans.isEmpty()) { this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values()); // We keep HandlerExceptionResolversinsorted order. AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers); }}else {
try {
HandlerExceptionResolver her =
context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, no HandlerExceptionResolver is fine too.
}
}
// Ensure we have at least some HandlerExceptionResolvers, by registering
// default HandlerExceptionResolvers if no other resolvers are found.
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default"); }}}Copy the code
InitHandlerExceptionResolvers through AnnotationAwareOrderComparator. Sort (enclosing handlerExceptionResolvers) Dui handlerExceptionResol Vers sorted it, and it was easy (I spent hours watching it anyway).
public class AnnotationAwareOrderComparator extends OrderComparator { ... . protected Integer findOrder(Object obj) { // Checkfor regular Ordered interface
Integer order = super.findOrder(obj);
if(order ! = null) {return order;
}
// Check for @Order and @Priority on various kinds of elements
if (obj instanceof Class) {
returnOrderUtils.getOrder((Class<? >) obj); }else if (obj instanceof Method) {
Order ann = AnnotationUtils.findAnnotation((Method) obj, Order.class);
if(ann ! = null) {returnann.value(); }}else if (obj instanceof AnnotatedElement) {
Order ann = AnnotationUtils.getAnnotation((AnnotatedElement) obj, Order.class);
if(ann ! = null) {returnann.value(); }}else if(obj ! = null) { order = OrderUtils.getOrder(obj.getClass());if(order == null && obj instanceof DecoratingProxy) { order = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass()); }}returnorder; }... . public static void sort(List<? > list) {if(list.size() > 1) { Collections.sort(list, INSTANCE); }}... . }Copy the code
Can see AnnotationAwareOrderComparator inherited OrderComparator class and AnnotationAwareOrderComparator. Sort can see is to use the Collections class rank. I won’t expand on the OrderComparator.
So the ExceptionHandler is changed to
public class ExceptionHandler extends AbstractHandlerExceptionResolver{ ... . @Override public intgetOrder() {
return1; }... . }Copy the code
Break point when see DefaultHandlerExceptionResolver order is 2, so this order is set to 1, problem solving. As for the inherited class, in fact, I am not quite clear about the specific function difference of several ExceptionResolver, with the original should also be no problem. AbstractHandlerExceptionResolver and SimpleMappingExceptionResolver Ordered interface is realized
As far as the result is concerned, I only changed a few lines of code, but it took quite a long time to solve the problem. I felt very satisfied, so I specially registered to write an article.