diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java
index 6253cb8020..45d33469cb 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/HandlerMapping.java
@@ -39,6 +39,17 @@ public interface HandlerMapping {
*/
String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
+ /**
+ * Name of the {@link ServerWebExchange} attribute that contains the path
+ * within the handler mapping, in case of a pattern match, or the full
+ * relevant URI (typically within the DispatcherServlet's mapping) else.
+ *
Note: This attribute is not required to be supported by all
+ * HandlerMapping implementations. URL-based HandlerMappings will
+ * typically support it, but handlers should not necessarily expect
+ * this request attribute to be present in all scenarios.
+ */
+ String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
+
/**
* Name of the {@link ServerWebExchange} attribute that contains the URI
* templates map, mapping variable names to values.
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java
new file mode 100644
index 0000000000..1711e43af2
--- /dev/null
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2002-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.reactive.handler;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import reactor.core.publisher.Mono;
+
+import org.springframework.beans.BeansException;
+import org.springframework.util.Assert;
+import org.springframework.web.server.ServerWebExchange;
+
+/**
+ * Abstract base class for URL-mapped
+ * {@link org.springframework.web.reactive.HandlerMapping} implementations.
+ *
+ *
Supports direct matches, e.g. a registered "/test" matches "/test", and
+ * various Ant-style pattern matches, e.g. a registered "/t*" pattern matches
+ * both "/test" and "/team", "/test/*" matches all paths under "/test",
+ * "/test/**" matches all paths below "/test". For details, see the
+ * {@link org.springframework.util.AntPathMatcher AntPathMatcher} javadoc.
+ *
+ *
Will search all path patterns to find the most exact match for the
+ * current request path. The most exact match is defined as the longest
+ * path pattern that matches the current request path.
+ *
+ * @author Rossen Stoyanchev
+ */
+public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
+
+ private boolean useTrailingSlashMatch = false;
+
+ private boolean lazyInitHandlers = false;
+
+ private final Map handlerMap = new LinkedHashMap<>();
+
+
+ /**
+ * Whether to match to URLs irrespective of the presence of a trailing slash.
+ * If enabled a URL pattern such as "/users" also matches to "/users/".
+ * The default value is {@code false}.
+ */
+ public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
+ this.useTrailingSlashMatch = useTrailingSlashMatch;
+ }
+
+ /**
+ * Whether to match to URLs irrespective of the presence of a trailing slash.
+ */
+ public boolean useTrailingSlashMatch() {
+ return this.useTrailingSlashMatch;
+ }
+
+ /**
+ * Set whether to lazily initialize handlers. Only applicable to
+ * singleton handlers, as prototypes are always lazily initialized.
+ * Default is "false", as eager initialization allows for more efficiency
+ * through referencing the controller objects directly.
+ *
If you want to allow your controllers to be lazily initialized,
+ * make them "lazy-init" and set this flag to true. Just making them
+ * "lazy-init" will not work, as they are initialized through the
+ * references from the handler mapping in this case.
+ */
+ public void setLazyInitHandlers(boolean lazyInitHandlers) {
+ this.lazyInitHandlers = lazyInitHandlers;
+ }
+
+ /**
+ * Return the registered handlers as an unmodifiable Map, with the registered path
+ * as key and the handler object (or handler bean name in case of a lazy-init handler)
+ * as value.
+ */
+ public final Map getHandlerMap() {
+ return Collections.unmodifiableMap(this.handlerMap);
+ }
+
+
+ @Override
+ public Mono getHandler(ServerWebExchange exchange) {
+ String lookupPath = getPathHelper().getLookupPathForRequest(exchange);
+ Object handler = null;
+ try {
+ handler = lookupHandler(lookupPath, exchange);
+ }
+ catch (Exception ex) {
+ return Mono.error(ex);
+ }
+
+ if (handler != null && logger.isDebugEnabled()) {
+ logger.debug("Mapping [" + lookupPath + "] to " + handler);
+ }
+ else if (handler == null && logger.isTraceEnabled()) {
+ logger.trace("No handler mapping found for [" + lookupPath + "]");
+ }
+
+ return Mono.justOrEmpty(handler);
+ }
+
+ /**
+ * Look up a handler instance for the given URL path.
+ *
+ * Supports direct matches, e.g. a registered "/test" matches "/test",
+ * and various Ant-style pattern matches, e.g. a registered "/t*" matches
+ * both "/test" and "/team". For details, see the AntPathMatcher class.
+ *
+ *
Looks for the most exact pattern, where most exact is defined as
+ * the longest path pattern.
+ *
+ * @param urlPath URL the bean is mapped to
+ * @param exchange the current exchange
+ * @return the associated handler instance, or {@code null} if not found
+ * @see org.springframework.util.AntPathMatcher
+ */
+ protected Object lookupHandler(String urlPath, ServerWebExchange exchange) throws Exception {
+ // Direct match?
+ Object handler = this.handlerMap.get(urlPath);
+ if (handler != null) {
+ return handleMatch(handler, urlPath, urlPath, exchange);
+ }
+ // Pattern match?
+ List matches = new ArrayList<>();
+ for (String pattern : this.handlerMap.keySet()) {
+ if (getPathMatcher().match(pattern, urlPath)) {
+ matches.add(pattern);
+ }
+ else if (useTrailingSlashMatch()) {
+ if (!pattern.endsWith("/") && getPathMatcher().match(pattern + "/", urlPath)) {
+ matches.add(pattern +"/");
+ }
+ }
+ }
+ String bestMatch = null;
+ Comparator comparator = getPathMatcher().getPatternComparator(urlPath);
+ if (!matches.isEmpty()) {
+ Collections.sort(matches, comparator);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Matching patterns for request [" + urlPath + "] are " + matches);
+ }
+ bestMatch = matches.get(0);
+ }
+ if (bestMatch != null) {
+ handler = this.handlerMap.get(bestMatch);
+ if (handler == null) {
+ Assert.isTrue(bestMatch.endsWith("/"));
+ handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
+ }
+ String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);
+ return handleMatch(handler, bestMatch, pathWithinMapping, exchange);
+ }
+ // No handler found...
+ return null;
+ }
+
+ private Object handleMatch(Object handler, String bestMatch, String pathWithinMapping,
+ ServerWebExchange exchange) throws Exception {
+
+ // Bean name or resolved handler?
+ if (handler instanceof String) {
+ String handlerName = (String) handler;
+ handler = getApplicationContext().getBean(handlerName);
+ }
+
+ validateHandler(handler, exchange);
+
+ exchange.getAttributes().put(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);
+ exchange.getAttributes().put(BEST_MATCHING_PATTERN_ATTRIBUTE, bestMatch);
+
+ return handler;
+ }
+
+ /**
+ * Validate the given handler against the current request.
+ * The default implementation is empty. Can be overridden in subclasses,
+ * for example to enforce specific preconditions expressed in URL mappings.
+ * @param handler the handler object to validate
+ * @param exchange current exchange
+ * @throws Exception if validation failed
+ */
+ @SuppressWarnings("UnusedParameters")
+ protected void validateHandler(Object handler, ServerWebExchange exchange) throws Exception {
+ }
+
+ /**
+ * Register the specified handler for the given URL paths.
+ * @param urlPaths the URLs that the bean should be mapped to
+ * @param beanName the name of the handler bean
+ * @throws BeansException if the handler couldn't be registered
+ * @throws IllegalStateException if there is a conflicting handler registered
+ */
+ protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
+ Assert.notNull(urlPaths, "URL path array must not be null");
+ for (String urlPath : urlPaths) {
+ registerHandler(urlPath, beanName);
+ }
+ }
+
+ /**
+ * Register the specified handler for the given URL path.
+ * @param urlPath the URL the bean should be mapped to
+ * @param handler the handler instance or handler bean name String
+ * (a bean name will automatically be resolved into the corresponding handler bean)
+ * @throws BeansException if the handler couldn't be registered
+ * @throws IllegalStateException if there is a conflicting handler registered
+ */
+ protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
+ Assert.notNull(urlPath, "URL path must not be null");
+ Assert.notNull(handler, "Handler object must not be null");
+ Object resolvedHandler = handler;
+
+ // Eagerly resolve handler if referencing singleton via name.
+ if (!this.lazyInitHandlers && handler instanceof String) {
+ String handlerName = (String) handler;
+ if (getApplicationContext().isSingleton(handlerName)) {
+ resolvedHandler = getApplicationContext().getBean(handlerName);
+ }
+ }
+
+ Object mappedHandler = this.handlerMap.get(urlPath);
+ if (mappedHandler != null) {
+ if (mappedHandler != resolvedHandler) {
+ throw new IllegalStateException(
+ "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
+ "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
+ }
+ }
+ else {
+ this.handlerMap.put(urlPath, resolvedHandler);
+ if (logger.isInfoEnabled()) {
+ logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
+ }
+ }
+ }
+
+ private String getHandlerDescription(Object handler) {
+ return "handler " + (handler instanceof String ? "'" + handler + "'" : "of type [" + handler.getClass() + "]");
+ }
+
+}
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java
index 0f1709ad85..fc96cbe07e 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMapping.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -16,41 +16,116 @@
package org.springframework.web.reactive.handler;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Properties;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-import org.springframework.web.reactive.HandlerMapping;
-import org.springframework.web.server.ServerWebExchange;
+import org.springframework.beans.BeansException;
+import org.springframework.util.CollectionUtils;
/**
+ * Implementation of the {@link org.springframework.web.reactive.HandlerMapping}
+ * interface to map from URLs to request handler beans. Supports both mapping
+ * to bean instances and mapping to bean names; the latter is required for
+ * non-singleton handlers.
+ *
+ *
The "urlMap" property is suitable for populating the handler map with
+ * bean instances. Mappings to bean names can be set via the "mappings"
+ * property, in a form accepted by the {@code java.util.Properties} class,
+ * like as follows:
+ *
+ *
+ * /welcome.html=ticketController
+ * /show.html=ticketController
+ *
+ *
+ * The syntax is {@code PATH=HANDLER_BEAN_NAME}. If the path doesn't begin
+ * with a slash, one is prepended.
+ *
+ *
Supports direct matches, e.g. a registered "/test" matches "/test", and
+ * various Ant-style pattern matches, e.g. a registered "/t*" pattern matches
+ * both "/test" and "/team", "/test/*" matches all paths under "/test",
+ * "/test/**" matches all paths below "/test". For details, see the
+ * {@link org.springframework.util.AntPathMatcher AntPathMatcher} javadoc.
+ *
* @author Rossen Stoyanchev
*/
-public class SimpleUrlHandlerMapping implements HandlerMapping {
+public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
- private final Map handlerMap = new HashMap<>();
+ private final Map urlMap = new LinkedHashMap<>();
- public void setHandlers(Map handlers) {
- this.handlerMap.clear();
- if (handlers != null) {
- this.handlerMap.putAll(handlers);
+ /**
+ * Map URL paths to handler bean names.
+ * This is the typical way of configuring this HandlerMapping.
+ * Supports direct URL matches and Ant-style pattern matches. For syntax
+ * details, see the {@link org.springframework.util.AntPathMatcher} javadoc.
+ * @param mappings properties with URLs as keys and bean names as values
+ * @see #setUrlMap
+ */
+ public void setMappings(Properties mappings) {
+ CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
+ }
+
+ /**
+ * Set a Map with URL paths as keys and handler beans (or handler bean names)
+ * as values. Convenient for population with bean references.
+ *
Supports direct URL matches and Ant-style pattern matches. For syntax
+ * details, see the {@link org.springframework.util.AntPathMatcher} javadoc.
+ * @param urlMap map with URLs as keys and beans as values
+ * @see #setMappings
+ */
+ public void setUrlMap(Map urlMap) {
+ this.urlMap.putAll(urlMap);
+ }
+
+ /**
+ * Allow Map access to the URL path mappings, with the option to add or
+ * override specific entries.
+ * Useful for specifying entries directly, for example via "urlMap[myKey]".
+ * This is particularly useful for adding or overriding entries in child
+ * bean definitions.
+ */
+ public Map getUrlMap() {
+ return this.urlMap;
+ }
+
+
+ /**
+ * Calls the {@link #registerHandlers} method in addition to the
+ * superclass's initialization.
+ */
+ @Override
+ public void initApplicationContext() throws BeansException {
+ super.initApplicationContext();
+ registerHandlers(this.urlMap);
+ }
+
+ /**
+ * Register all handlers specified in the URL map for the corresponding paths.
+ * @param urlMap Map with URL paths as keys and handler beans or bean names as values
+ * @throws BeansException if a handler couldn't be registered
+ * @throws IllegalStateException if there is a conflicting handler registered
+ */
+ protected void registerHandlers(Map urlMap) throws BeansException {
+ if (urlMap.isEmpty()) {
+ logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
+ }
+ else {
+ for (Map.Entry entry : urlMap.entrySet()) {
+ String url = entry.getKey();
+ Object handler = entry.getValue();
+ // Prepend with slash if not already present.
+ if (!url.startsWith("/")) {
+ url = "/" + url;
+ }
+ // Remove whitespace from handler bean name.
+ if (handler instanceof String) {
+ handler = ((String) handler).trim();
+ }
+ registerHandler(url, handler);
+ }
}
}
-
- @Override
- public Mono getHandler(ServerWebExchange exchange) {
- return Flux.create(subscriber -> {
- String path = exchange.getRequest().getURI().getPath();
- Object handler = this.handlerMap.get(path);
- if (handler != null) {
- subscriber.onNext(handler);
- }
- subscriber.onComplete();
- }).next();
- }
-
}
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMappingTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMappingTests.java
new file mode 100644
index 0000000000..eccda562f6
--- /dev/null
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/handler/SimpleUrlHandlerMappingTests.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2002-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.web.reactive.handler;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.junit.Test;
+
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.server.reactive.MockServerHttpRequest;
+import org.springframework.http.server.reactive.MockServerHttpResponse;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.web.reactive.HandlerMapping;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.adapter.DefaultServerWebExchange;
+import org.springframework.web.server.session.WebSessionManager;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.springframework.web.reactive.HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE;
+
+/**
+ * Unit tests for {@link SimpleUrlHandlerMapping}.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class SimpleUrlHandlerMappingTests {
+
+ @Test
+ public void handlerMappingJavaConfig() throws Exception {
+ AnnotationConfigApplicationContext wac = new AnnotationConfigApplicationContext();
+ wac.register(WebConfig.class);
+ wac.refresh();
+
+ HandlerMapping handlerMapping = (HandlerMapping) wac.getBean("handlerMapping");
+ Object mainController = wac.getBean("mainController");
+ Object otherController = wac.getBean("otherController");
+
+ testUrl("/welcome.html", mainController, handlerMapping, "/welcome.html");
+ testUrl("/welcome.x", otherController, handlerMapping, "welcome.x");
+ testUrl("/welcome/", otherController, handlerMapping, "welcome");
+ testUrl("/show.html", mainController, handlerMapping, "/show.html");
+ testUrl("/bookseats.html", mainController, handlerMapping, "/bookseats.html");
+ }
+
+ @Test
+ public void handlerMappingXmlConfig() throws Exception {
+ ClassPathXmlApplicationContext wac = new ClassPathXmlApplicationContext("map.xml", getClass());
+ wac.refresh();
+
+ HandlerMapping handlerMapping = wac.getBean("mapping", HandlerMapping.class);
+ Object mainController = wac.getBean("mainController");
+
+ testUrl("/pathmatchingTest.html", mainController, handlerMapping, "pathmatchingTest.html");
+ testUrl("welcome.html", null, handlerMapping, null);
+ testUrl("/pathmatchingAA.html", mainController, handlerMapping, "pathmatchingAA.html");
+ testUrl("/pathmatchingA.html", null, handlerMapping, null);
+ testUrl("/administrator/pathmatching.html", mainController, handlerMapping, "pathmatching.html");
+ testUrl("/administrator/test/pathmatching.html", mainController, handlerMapping, "test/pathmatching.html");
+ testUrl("/administratort/pathmatching.html", null, handlerMapping, null);
+ testUrl("/administrator/another/bla.xml", mainController, handlerMapping, "/administrator/another/bla.xml");
+ testUrl("/administrator/another/bla.gif", null, handlerMapping, null);
+ testUrl("/administrator/test/testlastbit", mainController, handlerMapping, "test/testlastbit");
+ testUrl("/administrator/test/testla", null, handlerMapping, null);
+ testUrl("/administrator/testing/longer/bla", mainController, handlerMapping, "bla");
+ testUrl("/administrator/testing/longer2/notmatching/notmatching", null, handlerMapping, null);
+ testUrl("/shortpattern/testing/toolong", null, handlerMapping, null);
+ testUrl("/XXpathXXmatching.html", mainController, handlerMapping, "XXpathXXmatching.html");
+ testUrl("/pathXXmatching.html", mainController, handlerMapping, "pathXXmatching.html");
+ testUrl("/XpathXXmatching.html", null, handlerMapping, null);
+ testUrl("/XXpathmatching.html", null, handlerMapping, null);
+ testUrl("/show12.html", mainController, handlerMapping, "show12.html");
+ testUrl("/show123.html", mainController, handlerMapping, "/show123.html");
+ testUrl("/show1.html", mainController, handlerMapping, "show1.html");
+ testUrl("/reallyGood-test-is-this.jpeg", mainController, handlerMapping, "reallyGood-test-is-this.jpeg");
+ testUrl("/reallyGood-tst-is-this.jpeg", null, handlerMapping, null);
+ testUrl("/testing/test.jpeg", mainController, handlerMapping, "testing/test.jpeg");
+ testUrl("/testing/test.jpg", null, handlerMapping, null);
+ testUrl("/anotherTest", mainController, handlerMapping, "anotherTest");
+ testUrl("/stillAnotherTest", null, handlerMapping, null);
+ testUrl("outofpattern*ye", null, handlerMapping, null);
+ testUrl("/test%26t%20est/path%26m%20atching.html", null, handlerMapping, null);
+
+ }
+
+ private void testUrl(String url, Object bean, HandlerMapping handlerMapping, String pathWithinMapping)
+ throws URISyntaxException {
+
+ ServerWebExchange exchange = createExchange(url);
+ Object actual = handlerMapping.getHandler(exchange).get();
+ if (bean != null) {
+ assertNotNull(actual);
+ assertSame(bean, actual);
+ //noinspection OptionalGetWithoutIsPresent
+ assertEquals(pathWithinMapping, exchange.getAttribute(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).get());
+ }
+ else {
+ assertNull(actual);
+ }
+ }
+
+ private ServerWebExchange createExchange(String path) throws URISyntaxException {
+ ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI(path));
+ WebSessionManager sessionManager = mock(WebSessionManager.class);
+ return new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager);
+ }
+
+
+ @Configuration
+ static class WebConfig {
+
+ @Bean @SuppressWarnings("unused")
+ public SimpleUrlHandlerMapping handlerMapping() {
+ SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();
+ hm.setUseTrailingSlashMatch(true);
+ hm.registerHandler("/welcome*", otherController());
+ hm.registerHandler("/welcome.html", mainController());
+ hm.registerHandler("/show.html", mainController());
+ hm.registerHandler("/bookseats.html", mainController());
+ return hm;
+ }
+
+ @Bean
+ public Object mainController() {
+ return new Object();
+ }
+
+ @Bean
+ public Object otherController() {
+ return new Object();
+ }
+ }
+
+}
diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java
index 49d4aa1e26..dc9a56baf3 100644
--- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java
+++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/WebHandlerIntegrationTests.java
@@ -39,10 +39,8 @@ import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.DispatcherHandler;
import org.springframework.web.reactive.ResponseStatusExceptionHandler;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
-import org.springframework.web.reactive.result.SimpleResultHandler;
-import org.springframework.web.reactive.result.WebHandlerHandlerAdapter;
-import org.springframework.web.server.WebHandler;
import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import static org.junit.Assert.assertArrayEquals;
@@ -138,7 +136,7 @@ public class WebHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTe
map.put("/foo", new FooHandler());
map.put("/bar", new BarHandler());
map.put("/header", new HeaderSettingHandler());
- setHandlers(map);
+ setUrlMap(map);
}
}
diff --git a/spring-web-reactive/src/test/resources/org/springframework/web/reactive/handler/map.xml b/spring-web-reactive/src/test/resources/org/springframework/web/reactive/handler/map.xml
new file mode 100644
index 0000000000..be0f6f067f
--- /dev/null
+++ b/spring-web-reactive/src/test/resources/org/springframework/web/reactive/handler/map.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ welcome.html=mainController
+ /**/pathmatchingTest.html=mainController
+ /**/pathmatching??.html=mainController
+ /**/path??matching.html=mainController
+ /**/??path??matching.html=mainController
+ /**/*.jsp=mainController
+ /administrator/**/pathmatching.html=mainController
+ /administrator/**/testlast*=mainController
+ /administrator/another/bla.xml=mainController
+ /administrator/testing/longer/**/**/**/**/**=mainController
+ /administrator/testing/longer2/**/**/bla/**=mainController
+ /*test*.jpeg=mainController
+ /*/test.jpeg=mainController
+ /outofpattern*yeah=mainController
+ /anotherTest*=mainController
+ /stillAnotherTestYeah=mainController
+ /shortpattern/testing=mainController
+ /show123.html=mainController
+ /sho*=mainController
+ /bookseats.html=mainController
+ /reservation.html=mainController
+ /payment.html=mainController
+ /confirmation.html=mainController
+ /test%26t%20est/path%26m%20atching.html=mainController
+
+
+
+
+
+
+