Skip to content

Commit 33becd8

Browse files
committed
Allow separator configuration in PathPatternParser
This commit allows to configure a custom path separator when parsing and matching path patterns with `PathPatternParser`, but also when parsing incoming paths as `PathContainer` instances. Closes gh-23092
1 parent ec91934 commit 33becd8

File tree

5 files changed

+62
-17
lines changed

5 files changed

+62
-17
lines changed

spring-web/src/main/java/org/springframework/http/server/DefaultPathContainer.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -89,11 +89,13 @@ public String toString() {
8989
}
9090

9191

92-
static PathContainer createFromUrlPath(String path) {
92+
static PathContainer createFromUrlPath(String path, String separator) {
9393
if (path.equals("")) {
9494
return EMPTY_PATH;
9595
}
96-
String separator = "/";
96+
if (separator.length() == 0) {
97+
throw new IllegalArgumentException("separator should not be empty");
98+
}
9799
Separator separatorElement = separator.equals(SEPARATOR.value()) ? SEPARATOR : () -> separator;
98100
List<Element> elements = new ArrayList<>();
99101
int begin;

spring-web/src/main/java/org/springframework/http/server/PathContainer.java

+15-3
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,26 @@ default PathContainer subPath(int startIndex, int endIndex) {
6565
}
6666

6767

68+
/**
69+
* Parse the path value into a sequence of {@code "/"} {@link Separator Separator}
70+
* and {@link PathSegment PathSegment} elements.
71+
* @param path the encoded, raw path value to parse
72+
* @return the parsed path
73+
*/
74+
static PathContainer parsePath(String path) {
75+
return DefaultPathContainer.createFromUrlPath(path, "/");
76+
}
77+
6878
/**
6979
* Parse the path value into a sequence of {@link Separator Separator} and
7080
* {@link PathSegment PathSegment} elements.
71-
* @param path the encoded, raw URL path value to parse
81+
* @param path the encoded, raw path value to parse
82+
* @param separator the decoded separator for parsing patterns
7283
* @return the parsed path
84+
* @since 5.2
7385
*/
74-
static PathContainer parsePath(String path) {
75-
return DefaultPathContainer.createFromUrlPath(path);
86+
static PathContainer parsePath(String path, String separator) {
87+
return DefaultPathContainer.createFromUrlPath(path, separator);
7688
}
7789

7890

spring-web/src/main/java/org/springframework/web/util/pattern/PathPatternParser.java

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,6 +36,8 @@ public class PathPatternParser {
3636

3737
private boolean caseSensitive = true;
3838

39+
private char separator = '/';
40+
3941

4042
/**
4143
* Whether a {@link PathPattern} produced by this parser should should
@@ -75,14 +77,20 @@ public boolean isCaseSensitive() {
7577
}
7678

7779
/**
78-
* Accessor used for the separator to use.
79-
* <p>Currently not exposed for configuration with URI path patterns and
80-
* mainly for use in InternalPathPatternParser and PathPattern. If required
81-
* in the future, a similar option would also need to be exposed in
82-
* {@link org.springframework.http.server.PathContainer PathContainer}.
80+
* Char that represents the separator to use in the patterns.
81+
* <p>The default is {@code '/'}.
82+
* @since 5.2
83+
*/
84+
public void setSeparator(char separator) {
85+
this.separator = separator;
86+
}
87+
88+
/**
89+
* Char that represents the separator to use in the patterns.
90+
* @since 5.2
8391
*/
84-
char getSeparator() {
85-
return '/';
92+
public char getSeparator() {
93+
return this.separator;
8694
}
8795

8896

spring-web/src/test/java/org/springframework/http/server/DefaultPathContainerTests.java

+17-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.util.MultiValueMap;
2828

2929
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
3031

3132
/**
3233
* Unit tests for {@link DefaultPathContainer}.
@@ -111,15 +112,18 @@ public void path() throws Exception {
111112
testPath("//%20/%20", "//%20/%20", Arrays.asList("/", "/", "%20", "/", "%20"));
112113
}
113114

114-
private void testPath(String input, String value, List<String> expectedElements) {
115-
116-
PathContainer path = PathContainer.parsePath(input);
115+
private void testPath(String input, String separator, String value, List<String> expectedElements) {
116+
PathContainer path = PathContainer.parsePath(input, separator);
117117

118118
assertThat(path.value()).as("value: '" + input + "'").isEqualTo(value);
119119
assertThat(path.elements().stream()
120120
.map(PathContainer.Element::value).collect(Collectors.toList())).as("elements: " + input).isEqualTo(expectedElements);
121121
}
122122

123+
private void testPath(String input, String value, List<String> expectedElements) {
124+
testPath(input, "/", value, expectedElements);
125+
}
126+
123127
@Test
124128
public void subPath() throws Exception {
125129
// basic
@@ -137,4 +141,14 @@ public void subPath() throws Exception {
137141
assertThat(path.subPath(2).value()).isEqualTo("/b/");
138142
}
139143

144+
@Test
145+
public void pathWithCustomSeparator() throws Exception {
146+
testPath("a.b.c", ".", "a.b.c", Arrays.asList("a", ".", "b", ".", "c"));
147+
}
148+
149+
@Test
150+
public void emptySeparator() {
151+
assertThatIllegalArgumentException().isThrownBy(() -> PathContainer.parsePath("path", ""));
152+
}
153+
140154
}

spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternParserTests.java

+9
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,15 @@ public void compareTests() {
408408
assertThat(patterns.get(1)).isEqualTo(p2);
409409
}
410410

411+
@Test
412+
public void separatorTests() {
413+
PathPatternParser parser = new PathPatternParser();
414+
parser.setSeparator('.');
415+
String rawPattern = "first.second.{last}";
416+
PathPattern pattern = parser.parse(rawPattern);
417+
assertThat(pattern.computePatternString()).isEqualTo(rawPattern);
418+
}
419+
411420
private PathPattern parse(String pattern) {
412421
PathPatternParser patternParser = new PathPatternParser();
413422
return patternParser.parse(pattern);

0 commit comments

Comments
 (0)