diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodExceptionResolver.java index a376f7b6dad..c9ef0b85de2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodExceptionResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -22,6 +22,7 @@ import jakarta.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.function.HandlerFunction; /** * Abstract base class for @@ -34,9 +35,9 @@ import org.springframework.web.servlet.ModelAndView; public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExceptionResolver { /** - * Checks if the handler is a {@link HandlerMethod} and then delegates to the - * base class implementation of {@code #shouldApplyTo(HttpServletRequest, Object)} - * passing the bean of the {@code HandlerMethod}. Otherwise returns {@code false}. + * Checks if the handler is a {@link HandlerMethod} or a {@link HandlerFunction} + * and then delegates to the base class implementation of {@code #shouldApplyTo(HttpServletRequest, Object)} + * passing the bean of the {@code HandlerMethod}. Otherwise, returns {@code false}. */ @Override protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) { @@ -47,6 +48,9 @@ public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHan handler = handlerMethod.getBean(); return super.shouldApplyTo(request, handler); } + else if (handler instanceof HandlerFunction handlerFunction) { + return super.shouldApplyTo(request, handlerFunction); + } else if (hasGlobalExceptionHandlers() && hasHandlerMappings()) { return super.shouldApplyTo(request, handler); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolverTests.java index 917294c997e..d0cb25855b0 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolverTests.java @@ -60,6 +60,8 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.FlashMap; import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerResponse; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; import org.springframework.web.testfixture.servlet.MockHttpServletRequest; @@ -82,6 +84,8 @@ import static org.mockito.Mockito.mock; @SuppressWarnings("unused") class ExceptionHandlerExceptionResolverTests { + //TODO + private static int DEFAULT_RESOLVER_COUNT; private static int DEFAULT_HANDLER_COUNT; @@ -255,6 +259,19 @@ class ExceptionHandlerExceptionResolverTests { assertExceptionHandledAsBody(mav, "AnotherTestExceptionResolver: IllegalAccessException"); } + @Test + void resolveExceptionGlobalHandlerForHandlerFunction() throws Exception { + loadConfiguration(MyConfig.class); + + IllegalAccessException ex = new IllegalAccessException(); + HandlerFunction handlerFunction = req -> { + throw new IllegalAccessException(); + }; + ModelAndView mav = this.resolver.resolveException(this.request, this.response, handlerFunction, ex); + + assertExceptionHandledAsBody(mav, "AnotherTestExceptionResolver: IllegalAccessException"); + } + @Test void resolveExceptionGlobalHandlerOrdered() throws Exception { loadConfiguration(MyConfig.class);