Log warning if @RequestMapping method has no explicit mapping
Commit c0b52d09f5 introduced support for
throwing an exception if a @RequestMapping handler method in a Spring
MVC controller was mapped to an empty path. This had negative side
effects for applications that intentionally mapped to an empty path,
potentially alongside a mapping to an explicit path for the same
handler method.
This commit addresses this by logging a warning (instead of throwing an
exception) if a @RequestMapping method is mapped only to empty paths.
This commit also introduces the same support for WebFlux-based
@RequestMapping handler methods.
Closes gh-22543
This commit is contained in:
@@ -62,7 +62,7 @@ import org.springframework.web.servlet.HandlerMapping;
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
* @param <T> the mapping for a {@link HandlerMethod} containing the conditions
|
||||
* needed to match the handler method to incoming request.
|
||||
* needed to match the handler method to an incoming request.
|
||||
*/
|
||||
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
|
||||
|
||||
@@ -496,7 +496,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
|
||||
|
||||
/**
|
||||
* Extract and return the URL paths contained in a mapping.
|
||||
* Extract and return the URL paths contained in the supplied mapping.
|
||||
*/
|
||||
protected abstract Set<String> getMappingPathPatterns(T mapping);
|
||||
|
||||
@@ -616,11 +616,11 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
}
|
||||
|
||||
private void validateMethodMapping(HandlerMethod handlerMethod, T mapping) {
|
||||
// Assert that the supplied mapping maps the supplied HandlerMethod
|
||||
// to explicit, non-empty paths.
|
||||
if (!getMappingPathPatterns(mapping).stream().allMatch(StringUtils::hasText)) {
|
||||
throw new IllegalStateException(String.format("Missing path mapping. " +
|
||||
"Handler method '%s' in bean '%s' must be mapped to a non-empty path. " +
|
||||
// Log a warning if the supplied mapping maps the supplied HandlerMethod
|
||||
// only to empty paths.
|
||||
if (logger.isWarnEnabled() && getMappingPathPatterns(mapping).stream().noneMatch(StringUtils::hasText)) {
|
||||
logger.warn(String.format(
|
||||
"Handler method '%s' in bean '%s' is not mapped to an explicit path. " +
|
||||
"If you wish to map to all paths, please map explicitly to \"/**\" or \"**\".",
|
||||
handlerMethod, handlerMethod.getBean()));
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
||||
|
||||
|
||||
/**
|
||||
* Get the URL path patterns associated with this {@link RequestMappingInfo}.
|
||||
* Get the URL path patterns associated with the supplied {@link RequestMappingInfo}.
|
||||
*/
|
||||
@Override
|
||||
protected Set<String> getMappingPathPatterns(RequestMappingInfo info) {
|
||||
|
||||
@@ -797,11 +797,28 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmappedPathMapping() {
|
||||
assertThatThrownBy(() -> initServletWithControllers(UnmappedPathController.class))
|
||||
.isInstanceOf(BeanCreationException.class)
|
||||
.hasCauseInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Missing path mapping");
|
||||
public void unmappedPathMapping() throws Exception {
|
||||
initServletWithControllers(UnmappedPathController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bogus-unmapped");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
getServlet().service(request, response);
|
||||
assertEquals("get", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void explicitAndEmptyPathsControllerMapping() throws Exception {
|
||||
initServletWithControllers(ExplicitAndEmptyPathsController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
getServlet().service(request, response);
|
||||
assertEquals("get", response.getContentAsString());
|
||||
|
||||
request = new MockHttpServletRequest("GET", "");
|
||||
response = new MockHttpServletResponse();
|
||||
getServlet().service(request, response);
|
||||
assertEquals("get", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2733,11 +2750,22 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
||||
}
|
||||
|
||||
@Controller
|
||||
@RequestMapping // path intentionally omitted
|
||||
// @RequestMapping intentionally omitted
|
||||
static class UnmappedPathController {
|
||||
|
||||
@GetMapping // path intentionally omitted
|
||||
public void get(@RequestParam(required = false) String id) {
|
||||
public void get(Writer writer) throws IOException {
|
||||
writer.write("get");
|
||||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
// @RequestMapping intentionally omitted
|
||||
static class ExplicitAndEmptyPathsController {
|
||||
|
||||
@GetMapping({"/", ""})
|
||||
public void get(Writer writer) throws IOException {
|
||||
writer.write("get");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user