Skip to content

Commit

Permalink
@ExceptionHandler support for non-@controller handlers
Browse files Browse the repository at this point in the history
Closes gh-22619
  • Loading branch information
rstoyanchev committed Jul 27, 2020
1 parent a4c157f commit 4252b7f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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 @@ -180,8 +180,16 @@ protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object han
}
}
}
// Else only apply if there are no explicit handler mappings.
return (this.mappedHandlers == null && this.mappedHandlerClasses == null);
return !hasHandlerMappings();
}

/**
* Whether there are any handler mappings registered via
* {@link #setMappedHandlers(Set)} or {@link #setMappedHandlerClasses(Class[])}.
* @since 5.3
*/
protected boolean hasHandlerMappings() {
return (this.mappedHandlers != null || this.mappedHandlerClasses != null);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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 @@ -48,17 +48,31 @@ else if (handler instanceof HandlerMethod) {
handler = handlerMethod.getBean();
return super.shouldApplyTo(request, handler);
}
else if (hasGlobalExceptionHandlers() && hasHandlerMappings()) {
return super.shouldApplyTo(request, handler);
}
else {
return false;
}
}

/**
* Whether this resolver has global exception handlers, e.g. not declared in
* the same class as the {@code HandlerMethod} that raised the exception and
* therefore can apply to any handler.
* @since 5.3
*/
protected boolean hasGlobalExceptionHandlers() {
return false;
}

@Override
@Nullable
protected final ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {

return doResolveHandlerMethodException(request, response, (HandlerMethod) handler, ex);
HandlerMethod handlerMethod = (handler instanceof HandlerMethod ? (HandlerMethod) handler : null);
return doResolveHandlerMethodException(request, response, handlerMethod, ex);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ protected List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers()
return handlers;
}

@Override
protected boolean hasGlobalExceptionHandlers() {
return !this.exceptionHandlerAdviceCache.isEmpty();
}

/**
* Find an {@code @ExceptionHandler} method and invoke it to handle the raised exception.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.ClassUtils;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
Expand All @@ -51,6 +52,7 @@
import org.springframework.web.servlet.FlashMap;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import org.springframework.web.util.NestedServletException;
Expand Down Expand Up @@ -346,6 +348,22 @@ void resolveExceptionControllerAdviceAgainstProxy() throws Exception {
assertThat(this.response.getContentAsString()).isEqualTo("BasePackageTestExceptionResolver: IllegalStateException");
}

@Test // gh-22619
void resolveExceptionViaMappedHandler() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyControllerAdviceConfig.class);
this.resolver.setMappedHandlerClasses(HttpRequestHandler.class);
this.resolver.setApplicationContext(ctx);
this.resolver.afterPropertiesSet();

IllegalStateException ex = new IllegalStateException();
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
ModelAndView mav = this.resolver.resolveException(this.request, this.response, handler, ex);

assertThat(mav).as("Exception was not handled").isNotNull();
assertThat(mav.isEmpty()).isTrue();
assertThat(this.response.getContentAsString()).isEqualTo("DefaultTestExceptionResolver: IllegalStateException");
}


private void assertMethodProcessorCount(int resolverCount, int handlerCount) {
assertThat(this.resolver.getArgumentResolvers().getResolvers().size()).isEqualTo(resolverCount);
Expand Down

0 comments on commit 4252b7f

Please sign in to comment.