Dedicated specificity comparator in PathPattern

The PathPattern compareTo method is now consistent with equals when
two patterns are of the same specificity but otherwise different.

Separately PathPattern now exposes a Comparator by specificity that
offers the current functionality of compareTo. This can be used for
actual sorting where we only care about specificity.
This commit is contained in:
Rossen Stoyanchev
2017-08-02 18:11:36 +02:00
parent 62fa20fd6f
commit 08dfce2cb5
7 changed files with 58 additions and 48 deletions

View File

@@ -118,7 +118,8 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
return this.handlerMap.entrySet().stream()
.filter(entry -> entry.getKey().matches(lookupPath))
.sorted(Comparator.comparing(Map.Entry::getKey))
.sorted((entry1, entry2) ->
PathPattern.SPECIFICITY_COMPARATOR.compare(entry1.getKey(), entry2.getKey()))
.findFirst()
.map(entry -> {
PathPattern pattern = entry.getKey();

View File

@@ -166,7 +166,8 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
private Mono<String> resolveResourceUrl(PathContainer lookupPath) {
return this.handlerMap.entrySet().stream()
.filter(entry -> entry.getKey().matches(lookupPath))
.sorted(Comparator.comparing(Map.Entry::getKey))
.sorted((entry1, entry2) ->
PathPattern.SPECIFICITY_COMPARATOR.compare(entry1.getKey(), entry2.getKey()))
.findFirst()
.map(entry -> {
PathContainer path = entry.getKey().extractPathWithinPattern(lookupPath);

View File

@@ -19,7 +19,6 @@ package org.springframework.web.reactive.result.condition;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -61,7 +60,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
}
private static SortedSet<PathPattern> toSortedSet(Collection<PathPattern> patterns) {
TreeSet<PathPattern> sorted = new TreeSet<>(getPatternComparator());
TreeSet<PathPattern> sorted = new TreeSet<>();
sorted.addAll(patterns);
return sorted;
}
@@ -70,13 +69,6 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
this.patterns = patterns;
}
private static Comparator<PathPattern> getPatternComparator() {
return (p1, p2) -> {
int index = p1.compareTo(p2);
return (index != 0 ? index : p1.getPatternString().compareTo(p2.getPatternString()));
};
}
public Set<PathPattern> getPatterns() {
return this.patterns;
}
@@ -170,7 +162,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
Iterator<PathPattern> iterator = this.patterns.iterator();
Iterator<PathPattern> iteratorOther = other.getPatterns().iterator();
while (iterator.hasNext() && iteratorOther.hasNext()) {
int result = iterator.next().compareTo(iteratorOther.next());
int result = PathPattern.SPECIFICITY_COMPARATOR.compare(iterator.next(), iteratorOther.next());
if (result != 0) {
return result;
}

View File

@@ -137,7 +137,7 @@ public class PatternsRequestConditionTests {
}
@Test
public void compareEqualPatterns() throws Exception {
public void compareToConsistentWithEquals() throws Exception {
PatternsRequestCondition c1 = createPatternsCondition("/foo*");
PatternsRequestCondition c2 = createPatternsCondition("/foo*");
@@ -155,10 +155,17 @@ public class PatternsRequestConditionTests {
@Test
public void comparePatternSpecificity() throws Exception {
ServerWebExchange exchange = get("/foo").toExchange();
PatternsRequestCondition c1 = createPatternsCondition("/fo*");
PatternsRequestCondition c2 = createPatternsCondition("/foo");
assertEquals(1, c1.compareTo(c2, get("/foo").toExchange()));
assertEquals(1, c1.compareTo(c2, exchange));
c1 = createPatternsCondition("/fo*");
c2 = createPatternsCondition("/*oo");
assertEquals("Patterns are equally specific even if not the same", 0, c1.compareTo(c2, exchange));
}
@Test

View File

@@ -160,7 +160,7 @@ public class HandlerMethodMappingTests {
@Override
protected Comparator<String> getMappingComparator(ServerWebExchange exchange) {
return Comparator.comparing(o -> parser.parse(o));
return (o1, o2) -> PathPattern.SPECIFICITY_COMPARATOR.compare(parser.parse(o1), parser.parse(o2));
}
}