SPR-6093 - MVC Annotation Inheritance
This commit is contained in:
parent
d8245c800b
commit
04fa5d4b99
|
|
@ -341,7 +341,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
|
||||
if (handler.getClass().getAnnotation(SessionAttributes.class) != null) {
|
||||
if (AnnotationUtils.findAnnotation(handler.getClass(), SessionAttributes.class) != null) {
|
||||
// Always prevent caching in case of session attribute management.
|
||||
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
|
||||
// Prepare cached set of session attributes names.
|
||||
|
|
@ -707,8 +707,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
ExtendedModelMap implicitModel,
|
||||
ServletWebRequest webRequest) throws Exception {
|
||||
|
||||
if (handlerMethod.isAnnotationPresent(ResponseStatus.class)) {
|
||||
ResponseStatus responseStatus = handlerMethod.getAnnotation(ResponseStatus.class);
|
||||
ResponseStatus responseStatus = AnnotationUtils.findAnnotation(handlerMethod, ResponseStatus.class);
|
||||
if (responseStatus != null) {
|
||||
HttpServletResponse response = webRequest.getResponse();
|
||||
response.setStatus(responseStatus.value().value());
|
||||
responseArgumentUsed = true;
|
||||
|
|
@ -725,8 +725,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
}
|
||||
}
|
||||
|
||||
if (returnValue != null && handlerMethod.isAnnotationPresent(ResponseBody.class)) {
|
||||
handleRequestBody(returnValue, webRequest);
|
||||
if (returnValue != null && AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {
|
||||
handleResponseBody(returnValue, webRequest);
|
||||
}
|
||||
|
||||
if (returnValue instanceof ModelAndView) {
|
||||
|
|
@ -740,7 +740,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
else if (returnValue instanceof View) {
|
||||
return new ModelAndView((View) returnValue).addAllObjects(implicitModel);
|
||||
}
|
||||
else if (handlerMethod.isAnnotationPresent(ModelAttribute.class)) {
|
||||
else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) {
|
||||
addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
|
||||
return new ModelAndView().addAllObjects(implicitModel);
|
||||
}
|
||||
|
|
@ -771,7 +771,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleRequestBody(Object returnValue, ServletWebRequest webRequest) throws ServletException, IOException {
|
||||
private void handleResponseBody(Object returnValue, ServletWebRequest webRequest) throws ServletException, IOException {
|
||||
HttpInputMessage inputMessage = new ServletServerHttpRequest(webRequest.getRequest());
|
||||
List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept();
|
||||
HttpOutputMessage outputMessage = new ServletServerHttpResponse(webRequest.getResponse());
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import javax.servlet.http.HttpSession;
|
|||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
|
@ -56,8 +57,8 @@ import org.springframework.web.servlet.support.RequestContextUtils;
|
|||
|
||||
/**
|
||||
* Implementation of the {@link org.springframework.web.servlet.HandlerExceptionResolver} interface that handles
|
||||
* exceptions through the {@link ExceptionHandler} annotation.
|
||||
* <p>This exception resolver is enabled by default in the {@link org.springframework.web.servlet.DispatcherServlet}.
|
||||
* exceptions through the {@link ExceptionHandler} annotation. <p>This exception resolver is enabled by default in the
|
||||
* {@link org.springframework.web.servlet.DispatcherServlet}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
|
|
@ -132,23 +133,25 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
|||
}
|
||||
else {
|
||||
Method oldMappedMethod = resolverMethods.get(handledException);
|
||||
if (!oldMappedMethod.equals(method)) {
|
||||
throw new IllegalStateException(
|
||||
"Ambiguous exception handler mapped for " + handledException + "]: {" +
|
||||
oldMappedMethod + ", " + method + "}.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return getBestMatchingMethod(thrownException, resolverMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the exception classes handled by the given method.
|
||||
* <p>Default implementation looks for exceptions in the {@linkplain ExceptionHandler#value() annotation}, or -
|
||||
* if that annotation element is empty - any exceptions listed in the method parameters if the method is annotated
|
||||
* with {@code @ExceptionHandler}.
|
||||
* Returns all the exception classes handled by the given method. <p>Default implementation looks for exceptions in the
|
||||
* {@linkplain ExceptionHandler#value() annotation}, or - if that annotation element is empty - any exceptions listed
|
||||
* in the method parameters if the method is annotated with {@code @ExceptionHandler}.
|
||||
*
|
||||
* @param method the method
|
||||
* @return the handled exceptions
|
||||
|
|
@ -156,7 +159,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
|||
@SuppressWarnings("unchecked")
|
||||
protected List<Class<? extends Throwable>> getHandledExceptions(Method method) {
|
||||
List<Class<? extends Throwable>> result = new ArrayList<Class<? extends Throwable>>();
|
||||
ExceptionHandler exceptionHandler = method.getAnnotation(ExceptionHandler.class);
|
||||
ExceptionHandler exceptionHandler = AnnotationUtils.findAnnotation(method, ExceptionHandler.class);
|
||||
if (exceptionHandler != null) {
|
||||
if (!ObjectUtils.isEmpty(exceptionHandler.value())) {
|
||||
result.addAll(Arrays.asList(exceptionHandler.value()));
|
||||
|
|
@ -172,9 +175,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the best matching method. Uses the {@link DepthComparator}.
|
||||
*/
|
||||
/** Returns the best matching method. Uses the {@link DepthComparator}. */
|
||||
private Method getBestMatchingMethod(Exception thrownException,
|
||||
Map<Class<? extends Throwable>, Method> resolverMethods) {
|
||||
if (!resolverMethods.isEmpty()) {
|
||||
|
|
@ -189,9 +190,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}.
|
||||
*/
|
||||
/** Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}. */
|
||||
private Object[] resolveHandlerArguments(Method handlerMethod,
|
||||
Object handler,
|
||||
NativeWebRequest webRequest,
|
||||
|
|
@ -222,8 +221,8 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
|||
}
|
||||
|
||||
/**
|
||||
* Resolves common method arguments. Delegates to registered {@link #setCustomArgumentResolver(WebArgumentResolver) argumentResolvers} first,
|
||||
* then checking {@link #resolveStandardArgument}.
|
||||
* 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
|
||||
|
|
@ -256,10 +255,10 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
|||
}
|
||||
|
||||
/**
|
||||
* Resolves standard method arguments. Default implementation handles {@link NativeWebRequest},
|
||||
* {@link ServletRequest}, {@link ServletResponse}, {@link HttpSession}, {@link Principal}, {@link Locale},
|
||||
* request {@link InputStream}, request {@link Reader}, response {@link OutputStream}, response {@link Writer},
|
||||
* and the given {@code thrownException}.
|
||||
* Resolves standard method arguments. Default implementation handles {@link NativeWebRequest}, {@link ServletRequest},
|
||||
* {@link ServletResponse}, {@link HttpSession}, {@link Principal}, {@link Locale}, request {@link InputStream},
|
||||
* request {@link Reader}, response {@link OutputStream}, response {@link Writer}, and the given {@code
|
||||
* thrownException}.
|
||||
*
|
||||
* @param parameterType the method parameter type
|
||||
* @param webRequest the request
|
||||
|
|
@ -327,8 +326,8 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
|||
private ModelAndView getModelAndView(Method handlerMethod, Object returnValue, ServletWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
if (handlerMethod.isAnnotationPresent(ResponseStatus.class)) {
|
||||
ResponseStatus responseStatus = handlerMethod.getAnnotation(ResponseStatus.class);
|
||||
ResponseStatus responseStatus = AnnotationUtils.findAnnotation(handlerMethod, ResponseStatus.class);
|
||||
if (responseStatus != null) {
|
||||
HttpServletResponse response = webRequest.getResponse();
|
||||
response.setStatus(responseStatus.value().value());
|
||||
}
|
||||
|
|
@ -355,9 +354,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparator capable of sorting exceptions based on their depth from the thrown exception type.
|
||||
*/
|
||||
/** Comparator capable of sorting exceptions based on their depth from the thrown exception type. */
|
||||
private static class DepthComparator implements Comparator<Class<? extends Throwable>> {
|
||||
|
||||
private final Class<? extends Throwable> handlerExceptionType;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ public class AnnotationMethodHandlerExceptionResolverTests {
|
|||
assertEquals("Invalid status code returned", 406, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inherited() {
|
||||
IOException ex = new IOException();
|
||||
InheritedController controller = new InheritedController();
|
||||
ModelAndView mav = exceptionResolver.resolveException(request, response, controller, ex);
|
||||
assertNotNull("No ModelAndView returned", mav);
|
||||
assertEquals("Invalid view name returned", "GenericError", mav.getViewName());
|
||||
assertEquals("Invalid status code returned", 500, response.getStatus());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void ambiguous() {
|
||||
IllegalArgumentException ex = new IllegalArgumentException();
|
||||
|
|
@ -86,6 +96,7 @@ public class AnnotationMethodHandlerExceptionResolverTests {
|
|||
private static class SimpleController {
|
||||
|
||||
@ExceptionHandler(IOException.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public String handleIOException(IOException ex, HttpServletRequest request) {
|
||||
return ClassUtils.getShortName(ex.getClass());
|
||||
}
|
||||
|
|
@ -103,6 +114,15 @@ public class AnnotationMethodHandlerExceptionResolverTests {
|
|||
|
||||
}
|
||||
|
||||
@Controller
|
||||
private static class InheritedController extends SimpleController
|
||||
{
|
||||
@Override
|
||||
public String handleIOException(IOException ex, HttpServletRequest request) {
|
||||
return "GenericError";
|
||||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
private static class AmbiguousController {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue