瀏覽代碼

Improve Error Message

Closes gh-13667
Josh Cummings 2 年之前
父節點
當前提交
28f98b3351

+ 20 - 3
config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java

@@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -320,14 +321,17 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 		if (!hasDispatcherServlet(registrations)) {
 			return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
 		}
-		Assert.isTrue(registrations.size() == 1,
-				"This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).");
+		if (registrations.size() > 1) {
+			String errorMessage = computeErrorMessage(registrations.values());
+			throw new IllegalArgumentException(errorMessage);
+		}
 		return requestMatchers(createMvcMatchers(method, patterns).toArray(new RequestMatcher[0]));
 	}
 
 	private Map<String, ? extends ServletRegistration> mappableServletRegistrations(ServletContext servletContext) {
 		Map<String, ServletRegistration> mappable = new LinkedHashMap<>();
-		for (Map.Entry<String, ? extends ServletRegistration> entry : servletContext.getServletRegistrations().entrySet()) {
+		for (Map.Entry<String, ? extends ServletRegistration> entry : servletContext.getServletRegistrations()
+				.entrySet()) {
 			if (!entry.getValue().getMappings().isEmpty()) {
 				mappable.put(entry.getKey(), entry.getValue());
 			}
@@ -355,6 +359,19 @@ public abstract class AbstractRequestMatcherRegistry<C> {
 		return false;
 	}
 
+	private String computeErrorMessage(Collection<? extends ServletRegistration> registrations) {
+		String template = "This method cannot decide whether these patterns are Spring MVC patterns or not. "
+				+ "If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); "
+				+ "otherwise, please use requestMatchers(AntPathRequestMatcher).\n\n"
+				+ "This is because there is more than one mappable servlet in your servlet context: %s.\n\n"
+				+ "For each MvcRequestMatcher, call MvcRequestMatcher#setServletPath to indicate the servlet path.";
+		Map<String, Collection<String>> mappings = new LinkedHashMap<>();
+		for (ServletRegistration registration : registrations) {
+			mappings.put(registration.getClassName(), registration.getMappings());
+		}
+		return String.format(template, mappings);
+	}
+
 	/**
 	 * <p>
 	 * If the {@link HandlerMappingIntrospector} is available in the classpath, maps to an

+ 3 - 1
config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryTests.java

@@ -63,12 +63,13 @@ public class AbstractRequestMatcherRegistryTests {
 	private WebApplicationContext context;
 
 	@BeforeEach
-	public void setUp() {
+	public void setUp() throws Exception {
 		this.matcherRegistry = new TestRequestMatcherRegistry();
 		this.context = mock(WebApplicationContext.class);
 		given(this.context.getBean(ObjectPostProcessor.class)).willReturn(NO_OP_OBJECT_POST_PROCESSOR);
 		given(this.context.getServletContext()).willReturn(MockServletContext.mvc());
 		this.matcherRegistry.setApplicationContext(this.context);
+		mockMvcPresentClasspath(true);
 	}
 
 	@Test
@@ -219,6 +220,7 @@ public class AbstractRequestMatcherRegistryTests {
 
 	@Test
 	public void requestMatchersWhenUnmappableServletsThenSkips() {
+		mockMvcIntrospector(true);
 		MockServletContext servletContext = new MockServletContext();
 		given(this.context.getServletContext()).willReturn(servletContext);
 		servletContext.addServlet("dispatcherServlet", DispatcherServlet.class).addMapping("/");