Added Pattern comparitor

This commit is contained in:
Arjen Poutsma 2009-01-21 17:06:37 +00:00
parent 61c9397c01
commit 5d5e41269b
3 changed files with 181 additions and 1 deletions

View File

@ -16,6 +16,7 @@
package org.springframework.util;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
@ -52,6 +53,7 @@ import java.util.Map;
* @author Alef Arendsen
* @author Juergen Hoeller
* @author Rob Harrop
* @author Arjen Poutsma
* @since 16.07.2003
*/
public class AntPathMatcher implements PathMatcher {
@ -288,4 +290,73 @@ public class AntPathMatcher implements PathMatcher {
return variables;
}
/**
* Given a full path, returns a {@link Comparator} suitable for sorting patterns in order of explicitness.
*
* <p>The returned <code>Comparator</code> will {@linkplain java.util.Collections#sort(java.util.List,
* java.util.Comparator) sort} a list so that more specific patterns (without uri templates or wild cards) come before
* generic patterns. So given a list with the following patterns:
* <ol>
* <li><code>/hotels/new</code></li>
* <li><code>/hotels/{hotel}</code></li>
* <li><code>/hotels/*</code></li>
* </ol>
* the returned comparator will sort this list so that the order will be as indicated.
*
* @param path the full path to use for comparison
* @return a comparator capable of sorting patterns in order of explicitness
*/
public Comparator<String> getPatternComparator(String path) {
return new AntPatternComparator(path);
}
private static class AntPatternComparator implements Comparator<String>{
private final String path;
private AntPatternComparator(String path) {
this.path = path;
}
public int compare(String pattern1, String pattern2) {
if (pattern1 == null && pattern2 == null) {
return 0;
}
else if (pattern1 == null) {
return 1;
}
else if (pattern2 == null) {
return -1;
}
boolean pattern1EqualsPath = pattern1.equals(path);
boolean pattern2EqualsPath = pattern2.equals(path);
if (pattern1EqualsPath && pattern2EqualsPath) {
return 0;
}
else if (pattern1EqualsPath) {
return -1;
}
else if (pattern2EqualsPath) {
return 1;
}
int wildCardCount1 = StringUtils.countOccurrencesOf(pattern1, "*");
int wildCardCount2 = StringUtils.countOccurrencesOf(pattern2, "*");
if (wildCardCount1 < wildCardCount2) {
return -1;
}
else if (wildCardCount2 < wildCardCount1) {
return 1;
}
int bracketCount1 = StringUtils.countOccurrencesOf(pattern1, "{");
int bracketCount2 = StringUtils.countOccurrencesOf(pattern1, "{");
if (bracketCount1 < bracketCount2) {
return -1;
}
else if (bracketCount1 < bracketCount2) {
return 1;
}
return 0;
}
}
}

View File

@ -16,11 +16,12 @@
package org.springframework.util;
import java.util.Comparator;
import java.util.Map;
/**
* Strategy interface for <code>String</code>-based path matching.
*
*
* <p>Used by {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver},
* {@link org.springframework.web.servlet.handler.AbstractUrlHandlerMapping},
* {@link org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver},
@ -102,4 +103,16 @@ public interface PathMatcher {
* @return a map, containing variable names as keys; variables values as values
*/
Map<String, String> extractUriTemplateVariables(String pattern, String path);
/**
* Given a full path, returns a {@link Comparator} suitable for sorting patterns in order of explicitness.
*
* <p>The full algorithm used depends on the underlying implementation, but generally, the returned
* <code>Comparator</code> will {@linkplain java.util.Collections#sort(java.util.List, java.util.Comparator) sort} a
* list so that more specific patterns come before generic patterns.
*
* @param path the full path to use for comparison
* @return a comparator capable of sorting patterns in order of explicitness
*/
Comparator<String> getPatternComparator(String path);
}

View File

@ -16,8 +16,11 @@
package org.springframework.util;
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 static org.junit.Assert.*;
@ -320,5 +323,98 @@ public class AntPathMatcherTests {
assertEquals(Collections.singletonMap("B", "b"), result);
}
@Test
public void patternComparator() {
Comparator<String> comparator = pathMatcher.getPatternComparator("/hotels/new");
assertEquals(0, comparator.compare(null, null));
assertEquals(1, comparator.compare(null, "/hotels/new"));
assertEquals(-1, comparator.compare("/hotels/new", null));
assertEquals(0, comparator.compare("/hotels/new", "/hotels/new"));
assertEquals(-1, comparator.compare("/hotels/new", "/hotels/*"));
assertEquals(1, comparator.compare("/hotels/*", "/hotels/new"));
assertEquals(0, comparator.compare("/hotels/*", "/hotels/*"));
assertEquals(-1, comparator.compare("/hotels/new", "/hotels/{hotel}"));
assertEquals(1, comparator.compare("/hotels/{hotel}", "/hotels/new"));
assertEquals(0, comparator.compare("/hotels/{hotel}", "/hotels/{hotel}"));
assertEquals(-1, comparator.compare("/hotels/{hotel}", "/hotels/*"));
assertEquals(1, comparator.compare("/hotels/*", "/hotels/{hotel}"));
}
@Test
public void patternComparatorSort() {
Comparator<String> comparator = pathMatcher.getPatternComparator("/hotels/new");
List<String> paths = new ArrayList<String>(3);
paths.add(null);
paths.add("/hotels/new");
Collections.sort(paths, comparator);
assertEquals("/hotels/new", paths.get(0));
assertNull(paths.get(1));
paths.clear();
paths.add("/hotels/new");
paths.add(null);
Collections.sort(paths, comparator);
assertEquals("/hotels/new", paths.get(0));
assertNull(paths.get(1));
paths.clear();
paths.add("/hotels/*");
paths.add("/hotels/new");
Collections.sort(paths, comparator);
assertEquals("/hotels/new", paths.get(0));
assertEquals("/hotels/*", paths.get(1));
paths.clear();
paths.add("/hotels/new");
paths.add("/hotels/*");
Collections.sort(paths, comparator);
assertEquals("/hotels/new", paths.get(0));
assertEquals("/hotels/*", paths.get(1));
paths.clear();
paths.add("/hotels/**");
paths.add("/hotels/*");
Collections.sort(paths, comparator);
assertEquals("/hotels/*", paths.get(0));
assertEquals("/hotels/**", paths.get(1));
paths.clear();
paths.add("/hotels/*");
paths.add("/hotels/**");
Collections.sort(paths, comparator);
assertEquals("/hotels/*", paths.get(0));
assertEquals("/hotels/**", paths.get(1));
paths.clear();
paths.add("/hotels/{hotel}");
paths.add("/hotels/new");
Collections.sort(paths, comparator);
assertEquals("/hotels/new", paths.get(0));
assertEquals("/hotels/{hotel}", paths.get(1));
paths.clear();
paths.add("/hotels/new");
paths.add("/hotels/{hotel}");
Collections.sort(paths, comparator);
assertEquals("/hotels/new", paths.get(0));
assertEquals("/hotels/{hotel}", paths.get(1));
paths.clear();
paths.add("/hotels/*");
paths.add("/hotels/{hotel}");
paths.add("/hotels/new");
Collections.shuffle(paths);
Collections.sort(paths, comparator);
assertEquals("/hotels/new", paths.get(0));
assertEquals("/hotels/{hotel}", paths.get(1));
assertEquals("/hotels/*", paths.get(2));
paths.clear();
}
}