Require explicit path mappings for @RequestMapping methods
Prior to this commit, handler methods in Spring MVC controllers were not required to provide explicit path mappings via @RequestMapping (or any of its specializations such as @GetMapping). Such handler methods were effectively mapped to all paths. Consequently, developers may have unwittingly mapped all requests to a single handler method. This commit addresses this by enforcing that @RequestMapping methods are mapped to an explicit path. Note, however, that this is enforced after type-level and method-level @RequestMapping information has been merged. Developers wishing to map to all paths should now add an explicit path mapping to "/**" or "**". Closes gh-22543
This commit is contained in:
@@ -78,7 +78,7 @@ public class RequestMappingInfoHandlerMappingTests {
|
||||
|
||||
private HandlerMethod barMethod;
|
||||
|
||||
private HandlerMethod emptyMethod;
|
||||
private HandlerMethod rootMethod;
|
||||
|
||||
|
||||
@Before
|
||||
@@ -88,7 +88,7 @@ public class RequestMappingInfoHandlerMappingTests {
|
||||
this.fooMethod = new HandlerMethod(testController, "foo");
|
||||
this.fooParamMethod = new HandlerMethod(testController, "fooParam");
|
||||
this.barMethod = new HandlerMethod(testController, "bar");
|
||||
this.emptyMethod = new HandlerMethod(testController, "empty");
|
||||
this.rootMethod = new HandlerMethod(testController, "root");
|
||||
|
||||
this.handlerMapping = new TestRequestMappingInfoHandlerMapping();
|
||||
this.handlerMapping.registerHandler(testController);
|
||||
@@ -125,12 +125,12 @@ public class RequestMappingInfoHandlerMappingTests {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||
HandlerMethod handlerMethod = getHandler(request);
|
||||
|
||||
assertEquals(this.emptyMethod.getMethod(), handlerMethod.getMethod());
|
||||
assertEquals(this.rootMethod.getMethod(), handlerMethod.getMethod());
|
||||
|
||||
request = new MockHttpServletRequest("GET", "/");
|
||||
handlerMethod = getHandler(request);
|
||||
|
||||
assertEquals(this.emptyMethod.getMethod(), handlerMethod.getMethod());
|
||||
assertEquals(this.rootMethod.getMethod(), handlerMethod.getMethod());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -465,8 +465,8 @@ public class RequestMappingInfoHandlerMappingTests {
|
||||
public void bar() {
|
||||
}
|
||||
|
||||
@RequestMapping(value = "")
|
||||
public void empty() {
|
||||
@RequestMapping("/")
|
||||
public void root() {
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/person/{id}", method = RequestMethod.PUT, consumes="application/xml")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -228,7 +228,7 @@ public class RequestMappingHandlerMappingTests {
|
||||
@RequestMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
static class ComposedAnnotationController {
|
||||
|
||||
@RequestMapping
|
||||
@RequestMapping("/**")
|
||||
public void handle() {
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ public class RequestMappingHandlerMappingTests {
|
||||
public void postJson() {
|
||||
}
|
||||
|
||||
@GetMapping(value = "/get", consumes = MediaType.ALL_VALUE)
|
||||
@GetMapping(path = "/get", consumes = MediaType.ALL_VALUE)
|
||||
public void get() {
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ public class RequestMappingHandlerMappingTests {
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface PostJson {
|
||||
|
||||
@AliasFor(annotation = RequestMapping.class, attribute = "path")
|
||||
@AliasFor(annotation = RequestMapping.class)
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -67,10 +67,10 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.propertyeditors.CustomDateEditor;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
@@ -151,11 +151,13 @@ import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class ServletAnnotationControllerHandlerMethodTests extends AbstractServletHandlerMethodTests {
|
||||
|
||||
@@ -251,7 +253,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
||||
@Test
|
||||
public void defaultExpressionParameters() throws Exception {
|
||||
initServlet(wac -> {
|
||||
RootBeanDefinition ppc = new RootBeanDefinition(PropertyPlaceholderConfigurer.class);
|
||||
RootBeanDefinition ppc = new RootBeanDefinition(PropertySourcesPlaceholderConfigurer.class);
|
||||
ppc.getPropertyValues().add("properties", "myKey=foo");
|
||||
wac.registerBeanDefinition("ppc", ppc);
|
||||
}, DefaultExpressionValueParamController.class);
|
||||
@@ -787,15 +789,19 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equivalentMappingsWithSameMethodName() throws Exception {
|
||||
try {
|
||||
initServletWithControllers(ChildController.class);
|
||||
fail("Expected 'method already mapped' error");
|
||||
}
|
||||
catch (BeanCreationException e) {
|
||||
assertTrue(e.getCause() instanceof IllegalStateException);
|
||||
assertTrue(e.getCause().getMessage().contains("Ambiguous mapping"));
|
||||
}
|
||||
public void equivalentMappingsWithSameMethodName() {
|
||||
assertThatThrownBy(() -> initServletWithControllers(ChildController.class))
|
||||
.isInstanceOf(BeanCreationException.class)
|
||||
.hasCauseInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Ambiguous mapping");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmappedPathMapping() {
|
||||
assertThatThrownBy(() -> initServletWithControllers(UnmappedPathController.class))
|
||||
.isInstanceOf(BeanCreationException.class)
|
||||
.hasCauseInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("Missing path mapping");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1993,7 +1999,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
||||
@Controller
|
||||
static class ControllerWithEmptyValueMapping {
|
||||
|
||||
@RequestMapping("")
|
||||
@RequestMapping("/**")
|
||||
public void myPath2(HttpServletResponse response) throws IOException {
|
||||
throw new IllegalStateException("test");
|
||||
}
|
||||
@@ -2012,7 +2018,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
||||
@Controller
|
||||
private static class ControllerWithErrorThrown {
|
||||
|
||||
@RequestMapping("")
|
||||
@RequestMapping("/**")
|
||||
public void myPath2(HttpServletResponse response) throws IOException {
|
||||
throw new AssertionError("test");
|
||||
}
|
||||
@@ -2726,6 +2732,15 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
||||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
@RequestMapping // path intentionally omitted
|
||||
static class UnmappedPathController {
|
||||
|
||||
@GetMapping // path intentionally omitted
|
||||
public void get(@RequestParam(required = false) String id) {
|
||||
}
|
||||
}
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Controller
|
||||
@@ -3586,7 +3601,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
||||
@Controller
|
||||
static class HttpHeadersResponseController {
|
||||
|
||||
@RequestMapping(value = "", method = RequestMethod.POST)
|
||||
@RequestMapping(value = "/*", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
public HttpHeaders create() throws URISyntaxException {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
Reference in New Issue
Block a user