Remove PathPatternRegistry

This commit is contained in:
Rossen Stoyanchev 2017-07-10 11:37:18 +02:00
parent e7b77cb2b6
commit fac35ebec2
9 changed files with 131 additions and 446 deletions

View File

@ -17,6 +17,8 @@
package org.springframework.web.reactive.handler;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import reactor.core.publisher.Mono;
@ -25,6 +27,7 @@ import org.springframework.beans.BeansException;
import org.springframework.http.server.reactive.PathContainer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
@ -51,8 +54,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
private boolean lazyInitHandlers = false;
@Nullable
private PathPatternRegistry<Object> patternRegistry;
private final Map<PathPattern, Object> handlerMap = new LinkedHashMap<>();
/**
@ -70,12 +72,12 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
}
/**
* Return the registered handlers as an unmodifiable Map, with the registered path
* pattern as key and the handler object (or handler bean name in case of a lazy-init handler)
* as value.
* Return a read-only view of registered path patterns and handlers which may
* may be an actual handler instance or the bean name of lazily initialized
* handler.
*/
public final Map<PathPattern, Object> getHandlerMap() {
return (this.patternRegistry != null ? this.patternRegistry.getPatternsMap() : Collections.emptyMap());
return Collections.unmodifiableMap(this.handlerMap);
}
@ -111,25 +113,26 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
* @see org.springframework.web.util.pattern.PathPattern
*/
@Nullable
protected Object lookupHandler(PathContainer lookupPath, ServerWebExchange exchange) throws Exception {
if (this.patternRegistry != null) {
PathMatchResult<Object> bestMatch = this.patternRegistry.findFirstMatch(lookupPath);
if (bestMatch != null) {
if (logger.isDebugEnabled()) {
logger.debug("Matching patterns for request [" + lookupPath + "] are " + bestMatch);
}
PathContainer pathWithinMapping = bestMatch.getPattern().extractPathWithinPattern(lookupPath);
Object handler = bestMatch.getHandler();
return handleMatch(handler, bestMatch.getPattern(), pathWithinMapping, exchange);
}
}
protected Object lookupHandler(PathContainer lookupPath, ServerWebExchange exchange)
throws Exception {
// No handler found...
return null;
return this.handlerMap.entrySet().stream()
.filter(entry -> entry.getKey().matches(lookupPath))
.sorted(Comparator.comparing(Map.Entry::getKey))
.findFirst()
.map(entry -> {
PathPattern pattern = entry.getKey();
if (logger.isDebugEnabled()) {
logger.debug("Matching pattern for request [" + lookupPath + "] is " + pattern);
}
PathContainer pathWithinMapping = pattern.extractPathWithinPattern(lookupPath);
return handleMatch(entry.getValue(), pattern, pathWithinMapping, exchange);
})
.orElse(null);
}
private Object handleMatch(Object handler, PathPattern bestMatch, PathContainer pathWithinMapping,
ServerWebExchange exchange) throws Exception {
ServerWebExchange exchange) {
// Bean name or resolved handler?
if (handler instanceof String) {
@ -152,10 +155,9 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
* 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 {
protected void validateHandler(Object handler, ServerWebExchange exchange) {
}
/**
@ -165,7 +167,9 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
* @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 {
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);
@ -180,11 +184,26 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
* @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 {
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;
// Parse path pattern
urlPath = prependLeadingSlash(urlPath);
PathPattern pattern = getPathPatternParser().parse(urlPath);
if (this.handlerMap.containsKey(pattern)) {
Object existingHandler = this.handlerMap.get(pattern);
if (existingHandler != null) {
if (existingHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to [" + urlPath + "]: " +
"there is already " + getHandlerDescription(existingHandler) + " mapped.");
}
}
}
// Eagerly resolve handler if referencing singleton via name.
if (!this.lazyInitHandlers && handler instanceof String) {
@ -193,32 +212,26 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
resolvedHandler = obtainApplicationContext().getBean(handlerName);
}
}
if (this.patternRegistry == null) {
this.patternRegistry = new PathPatternRegistry<>(getPathPatternParser());
}
Map<PathPattern, Object> patternsMap = this.patternRegistry.getPatternsMap();
if (patternsMap.containsKey(urlPath)) {
Object mappedHandler = patternsMap.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.patternRegistry.register(urlPath, resolvedHandler);
}
// Register resolved handler
this.handlerMap.put(pattern, resolvedHandler);
if (logger.isInfoEnabled()) {
logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
private static String prependLeadingSlash(String pattern) {
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
return "/" + pattern;
}
else {
return pattern;
}
}
private String getHandlerDescription(Object handler) {
return "handler " + (handler instanceof String ? "'" + handler + "'" : "of type [" + handler.getClass() + "]");
return "handler " + (handler instanceof String ?
"'" + handler + "'" : "of type [" + handler.getClass() + "]");
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright 2002-2017 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 org.jetbrains.annotations.NotNull;
import org.springframework.util.Assert;
import org.springframework.web.util.pattern.PathPattern;
/**
* Result of path match performed through a {@link PathPatternRegistry}.
* Each result contains the matched pattern and handler of type {@code T}.
*
* @author Brian Clozel
* @since 5.0
* @see PathPatternRegistry
*/
public class PathMatchResult<T> implements Comparable<PathMatchResult<T>> {
private final PathPattern pattern;
private final T handler;
public PathMatchResult(PathPattern pattern, T handler) {
Assert.notNull(pattern, "PathPattern must not be null");
Assert.notNull(handler, "Handler must not be null");
this.pattern = pattern;
this.handler = handler;
}
/**
* Return the {@link PathPattern} that matched the incoming request.
*/
public PathPattern getPattern() {
return this.pattern;
}
/**
* Return the request handler associated with the {@link PathPattern}.
*/
public T getHandler() {
return this.handler;
}
@Override
public int compareTo(@NotNull PathMatchResult<T> other) {
int index = this.pattern.compareTo(other.pattern);
return (index != 0 ? index : this.getPatternString().compareTo(other.getPatternString()));
}
private String getPatternString() {
return this.pattern.getPatternString();
}
@Override
public String toString() {
return "PathMatchResult{pattern=" + this.pattern + ", handler=" + this.handler + "]";
}
}

View File

@ -1,141 +0,0 @@
/*
* Copyright 2002-2017 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.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.springframework.http.server.reactive.PathContainer;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* Registry that holds {@code PathPattern}s instances
* and allows matching against them with a lookup path.
*
* @author Brian Clozel
* @since 5.0
*/
public class PathPatternRegistry<T> {
private final PathPatternParser pathPatternParser;
private final Map<PathPattern, T> patternsMap;
/**
* Create a new {@code PathPatternRegistry} with
* a default instance of {@link PathPatternParser}.
*/
public PathPatternRegistry() {
this(new PathPatternParser());
}
/**
* Create a new {@code PathPatternRegistry} using
* the provided instance of {@link PathPatternParser}.
* @param patternParser the {@link PathPatternParser} to use
*/
public PathPatternRegistry(PathPatternParser patternParser) {
this(patternParser, Collections.emptyMap());
}
/**
* Create a new {@code PathPatternRegistry} using
* the provided instance of {@link PathPatternParser}
* and the given map of {@link PathPattern}.
* @param patternParser the {@link PathPatternParser} to use
* @param patternsMap the map of {@link PathPattern} to use
*/
public PathPatternRegistry(PathPatternParser patternParser, Map<PathPattern, T> patternsMap) {
this.pathPatternParser = patternParser;
this.patternsMap = new HashMap<>(patternsMap);
}
/**
* Return a (read-only) map of all patterns and associated values.
*/
public Map<PathPattern, T> getPatternsMap() {
return Collections.unmodifiableMap(this.patternsMap);
}
/**
* Parse the given {@code rawPattern} and adds it to this registry.
* @param rawPattern raw path pattern to parse and register
* @param handler the associated handler object
*/
public void register(String rawPattern, T handler) {
String fixedPattern = prependLeadingSlash(rawPattern);
PathPattern newPattern = this.pathPatternParser.parse(fixedPattern);
this.patternsMap.put(newPattern, handler);
}
private static String prependLeadingSlash(String pattern) {
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
return "/" + pattern;
}
else {
return pattern;
}
}
/**
* Return patterns matching the given {@code lookupPath}.
* <p>The returned set sorted with the most specific
* patterns first, according to the given {@code lookupPath}.
* @param lookupPath the URL lookup path to be matched against
*/
public SortedSet<PathMatchResult<T>> findMatches(PathContainer lookupPath) {
return this.patternsMap.entrySet().stream()
.filter(entry -> entry.getKey().matches(lookupPath))
.sorted(Comparator.comparing(Map.Entry::getKey))
.map(entry -> new PathMatchResult<>(entry.getKey(), entry.getValue()))
.collect(Collectors.toCollection(TreeSet::new));
}
/**
* Return, if any, the most specific {@code PathPattern} matching the given {@code lookupPath}.
* @param lookupPath the URL lookup path to be matched against
*/
@Nullable
public PathMatchResult<T> findFirstMatch(PathContainer lookupPath) {
return this.patternsMap.entrySet().stream()
.filter(entry -> entry.getKey().matches(lookupPath))
.sorted(Comparator.comparing(Map.Entry::getKey))
.findFirst()
.map(entry -> new PathMatchResult<>(entry.getKey(), entry.getValue()))
.orElse(null);
}
/**
* Remove all {@link PathPattern}s from this registry
*/
public void clear() {
this.patternsMap.clear();
}
}

View File

@ -18,13 +18,14 @@ package org.springframework.web.reactive.resource;
import java.nio.charset.StandardCharsets;
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 java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.context.ApplicationContext;
@ -34,8 +35,8 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.server.reactive.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.web.reactive.handler.PathMatchResult;
import org.springframework.web.reactive.handler.PathPatternRegistry;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
@ -54,41 +55,33 @@ import org.springframework.web.util.pattern.PathPatternParser;
*/
public class ResourceUrlProvider implements ApplicationListener<ContextRefreshedEvent> {
protected final Log logger = LogFactory.getLog(getClass());
private static final Log logger = LogFactory.getLog(ResourceUrlProvider.class);
private PathPatternRegistry<ResourceWebHandler> patternRegistry = new PathPatternRegistry<>();
private final PathPatternParser patternParser;
private final Map<PathPattern, ResourceWebHandler> handlerMap = new LinkedHashMap<>();
private boolean autodetect = true;
/**
* Configure a {@code PathPatternParser} to use when comparing target lookup path
* against resource mappings.
*/
public void setPathPatternParser(PathPatternParser patternParser) {
this.patternRegistry = new PathPatternRegistry<>(patternParser);
public ResourceUrlProvider() {
this(new PathPatternParser());
}
/**
* Manually configure the resource mappings.
* <p><strong>Note:</strong> by default resource mappings are auto-detected
* from the Spring {@code ApplicationContext}. However if this property is
* used, the auto-detection is turned off.
*/
public void setHandlerMap(@Nullable Map<String, ResourceWebHandler> handlerMap) {
if (handlerMap != null) {
this.patternRegistry.clear();
handlerMap.forEach(this.patternRegistry::register);
this.autodetect = false;
}
public ResourceUrlProvider(PathPatternParser patternParser) {
Assert.notNull(patternParser, "'patternParser' is required.");
this.patternParser = patternParser;
}
/**
* Return the resource mappings, either manually configured or auto-detected
* when the Spring {@code ApplicationContext} is refreshed.
* Return a read-only view of the resource handler mappings either manually
* configured or auto-detected when the Spring {@code ApplicationContext}
* is refreshed.
*/
public Map<PathPattern, ResourceWebHandler> getHandlerMap() {
return this.patternRegistry.getPatternsMap();
return Collections.unmodifiableMap(this.handlerMap);
}
/**
@ -99,12 +92,13 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
return this.autodetect;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (isAutodetect()) {
this.patternRegistry.clear();
this.handlerMap.clear();
detectResourceHandlers(event.getApplicationContext());
if (!this.patternRegistry.getPatternsMap().isEmpty()) {
if (!this.handlerMap.isEmpty()) {
this.autodetect = false;
}
else if(logger.isDebugEnabled()) {
@ -113,17 +107,15 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
}
}
protected void detectResourceHandlers(ApplicationContext appContext) {
private void detectResourceHandlers(ApplicationContext context) {
logger.debug("Looking for resource handler mappings");
Map<String, SimpleUrlHandlerMapping> map = appContext.getBeansOfType(SimpleUrlHandlerMapping.class);
Map<String, SimpleUrlHandlerMapping> map = context.getBeansOfType(SimpleUrlHandlerMapping.class);
List<SimpleUrlHandlerMapping> handlerMappings = new ArrayList<>(map.values());
AnnotationAwareOrderComparator.sort(handlerMappings);
for (SimpleUrlHandlerMapping hm : handlerMappings) {
for (PathPattern pattern : hm.getHandlerMap().keySet()) {
Object handler = hm.getHandlerMap().get(pattern);
handlerMappings.forEach(mapping -> {
mapping.getHandlerMap().forEach((pattern, handler) -> {
if (handler instanceof ResourceWebHandler) {
ResourceWebHandler resourceHandler = (ResourceWebHandler) handler;
if (logger.isDebugEnabled()) {
@ -131,12 +123,41 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
"locations=" + resourceHandler.getLocations() + ", " +
"resolvers=" + resourceHandler.getResourceResolvers());
}
this.patternRegistry.register(pattern.getPatternString(), resourceHandler);
this.handlerMap.put(pattern, resourceHandler);
}
}
});
});
}
/**
* Manually configure the resource mappings.
* <p><strong>Note:</strong> by default resource mappings are auto-detected
* from the Spring {@code ApplicationContext}. However if this property is
* used, the auto-detection is turned off.
*/
public void registerHandlers(@Nullable Map<String, ResourceWebHandler> handlerMap) {
if (handlerMap == null) {
return;
}
this.handlerMap.clear();
handlerMap.forEach((rawPattern, resourceWebHandler) -> {
rawPattern = prependLeadingSlash(rawPattern);
PathPattern pattern = this.patternParser.parse(rawPattern);
this.handlerMap.put(pattern, resourceWebHandler);
});
this.autodetect = false;
}
private static String prependLeadingSlash(String pattern) {
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
return "/" + pattern;
}
else {
return pattern;
}
}
/**
* A variation on {@link #getForLookupPath(PathContainer)} that accepts a
* full request URL path and returns the full request URL path to expose
@ -187,19 +208,19 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
if (logger.isTraceEnabled()) {
logger.trace("Getting resource URL for lookup path \"" + lookupPath + "\"");
}
Set<PathMatchResult<ResourceWebHandler>> matches = this.patternRegistry.findMatches(lookupPath);
return Flux.fromIterable(matches).next()
.flatMap(result -> {
PathContainer path = result.getPattern().extractPathWithinPattern(lookupPath);
return this.handlerMap.entrySet().stream()
.filter(entry -> entry.getKey().matches(lookupPath))
.sorted(Comparator.comparing(Map.Entry::getKey))
.findFirst()
.map(entry -> {
PathContainer path = entry.getKey().extractPathWithinPattern(lookupPath);
int endIndex = lookupPath.elements().size() - path.elements().size();
PathContainer mapping = PathContainer.subPath(lookupPath, 0, endIndex);
if (logger.isTraceEnabled()) {
logger.trace("Invoking ResourceResolverChain for URL pattern " +
"\"" + result.getPattern() + "\"");
"\"" + entry.getKey() + "\"");
}
ResourceWebHandler handler = result.getHandler();
ResourceWebHandler handler = entry.getValue();
List<ResourceResolver> resolvers = handler.getResourceResolvers();
ResourceResolverChain chain = new DefaultResourceResolverChain(resolvers);
return chain.resolveUrlPath(path.value(), handler.getLocations())
@ -209,7 +230,9 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
}
return mapping.value() + resolvedPath;
});
});
})
.orElse(Mono.empty());
}
}

View File

@ -1,133 +0,0 @@
/*
* Copyright 2002-2017 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.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.http.server.reactive.PathContainer;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
import org.springframework.web.util.pattern.PatternParseException;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link PathPatternRegistry}
*
* @author Brian Clozel
*/
public class PathPatternRegistryTests {
private final PathPatternRegistry<Object> registry = new PathPatternRegistry();
private final PathPatternParser parser = new PathPatternParser();
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void shouldPrependPatternsWithSlash() {
this.registry.register("foo/bar", new Object());
assertThat(this.registry.getPatternsMap().keySet(), contains(pattern("/foo/bar")));
}
@Test
public void shouldNotRegisterInvalidPatterns() {
this.thrown.expect(PatternParseException.class);
this.thrown.expectMessage(Matchers.containsString("Expected close capture character after variable name"));
this.registry.register("/{invalid", new Object());
}
@Test
public void registerPatternsWithSameSpecificity() {
PathPattern fooOne = this.parser.parse("/fo?");
PathPattern fooTwo = this.parser.parse("/f?o");
assertThat(fooOne.compareTo(fooTwo), is(0));
this.registry.register("/fo?", new Object());
this.registry.register("/f?o", new Object());
PathContainer path = PathContainer.parse("/foo", StandardCharsets.UTF_8);
Set<PathMatchResult<Object>> matches = this.registry.findMatches(path);
assertThat(toPatterns(matches), contains(pattern("/f?o"), pattern("/fo?")));
}
@Test
public void findNoMatch() {
this.registry.register("/foo/{bar}", new Object());
PathContainer path = PathContainer.parse("/other", StandardCharsets.UTF_8);
assertThat(this.registry.findMatches(path), hasSize(0));
}
@Test
public void orderMatchesBySpecificity() {
this.registry.register("/foo/{*baz}", new Object());
this.registry.register("/foo/bar/baz", new Object());
this.registry.register("/foo/bar/{baz}", new Object());
PathContainer path = PathContainer.parse("/foo/bar/baz", StandardCharsets.UTF_8);
Set<PathMatchResult<Object>> matches = this.registry.findMatches(path);
assertThat(toPatterns(matches), contains(pattern("/foo/bar/baz"), pattern("/foo/bar/{baz}"),
pattern("/foo/{*baz}")));
}
private List<PathPattern> toPatterns(Collection<PathMatchResult<Object>> results) {
return results.stream().map(PathMatchResult::getPattern).collect(Collectors.toList());
}
private static PathPatternMatcher pattern(String pattern) {
return new PathPatternMatcher(pattern);
}
private static class PathPatternMatcher extends BaseMatcher<PathPattern> {
private final String pattern;
public PathPatternMatcher(String pattern) {
this.pattern = pattern;
}
@Override
public boolean matches(Object item) {
if(item != null && item instanceof PathPattern) {
return ((PathPattern) item).getPatternString().equals(pattern);
}
return false;
}
@Override
public void describeTo(Description description) {
}
}
}

View File

@ -55,7 +55,7 @@ public class AppCacheManifestTransformerTests {
ClassPathResource allowedLocation = new ClassPathResource("test/", getClass());
ResourceWebHandler resourceHandler = new ResourceWebHandler();
ResourceUrlProvider resourceUrlProvider = new ResourceUrlProvider();
resourceUrlProvider.setHandlerMap(Collections.singletonMap("/static/**", resourceHandler));
resourceUrlProvider.registerHandlers(Collections.singletonMap("/static/**", resourceHandler));
VersionResourceResolver versionResolver = new VersionResourceResolver();
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));

View File

@ -54,7 +54,7 @@ public class CssLinkResourceTransformerTests {
ResourceWebHandler resourceHandler = new ResourceWebHandler();
ResourceUrlProvider resourceUrlProvider = new ResourceUrlProvider();
resourceUrlProvider.setHandlerMap(Collections.singletonMap("/static/**", resourceHandler));
resourceUrlProvider.registerHandlers(Collections.singletonMap("/static/**", resourceHandler));
VersionResourceResolver versionResolver = new VersionResourceResolver();
versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy()));

View File

@ -64,7 +64,7 @@ public class ResourceTransformerSupportTests {
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
handler.setResourceResolvers(resolvers);
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
urlProvider.setHandlerMap(Collections.singletonMap("/resources/**", handler));
urlProvider.registerHandlers(Collections.singletonMap("/resources/**", handler));
return urlProvider;
}

View File

@ -69,7 +69,7 @@ public class ResourceUrlProviderTests {
this.handler.setLocations(locations);
this.handler.afterPropertiesSet();
this.handlerMap.put("/resources/**", this.handler);
this.urlProvider.setHandlerMap(this.handlerMap);
this.urlProvider.registerHandlers(this.handlerMap);
}
@ -125,7 +125,7 @@ public class ResourceUrlProviderTests {
otherHandler.setResourceResolvers(resolvers);
this.handlerMap.put("/resources/*.css", otherHandler);
this.urlProvider.setHandlerMap(this.handlerMap);
this.urlProvider.registerHandlers(this.handlerMap);
PathContainer path = PathContainer.parse("/resources/foo.css", StandardCharsets.UTF_8);
String url = this.urlProvider.getForLookupPath(path).block(Duration.ofSeconds(5));