From aeba9d244af263d3489b141c7a9655bc5f09380d Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Thu, 15 Sep 2011 10:24:21 +0000 Subject: [PATCH] SPR-5973: now dealing with path followed by segments (and vice-versa) correctly. --- .../web/util/UriComponents.java | 54 +++++++++++++++++-- .../web/util/UriComponentsBuilder.java | 53 ++++++++++++------ .../web/util/UriComponentsBuilderTests.java | 36 +++++++++++++ .../web/util/UriComponentsTests.java | 8 +++ 4 files changed, 131 insertions(+), 20 deletions(-) diff --git a/org.springframework.web/src/main/java/org/springframework/web/util/UriComponents.java b/org.springframework.web/src/main/java/org/springframework/web/util/UriComponents.java index 8827261dc6..d1a396d130 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/util/UriComponents.java +++ b/org.springframework.web/src/main/java/org/springframework/web/util/UriComponents.java @@ -316,10 +316,10 @@ public final class UriComponents { * @param uriVariables the map of URI variables * @return the expanded uri components */ - public UriComponents expand(Map map) { - Assert.notNull(map, "'uriVariables' must not be null"); + public UriComponents expand(Map uriVariables) { + Assert.notNull(uriVariables, "'uriVariables' must not be null"); - return expandInternal(new MapTemplateVariables(map)); + return expandInternal(new MapTemplateVariables(uriVariables)); } /** @@ -526,7 +526,7 @@ public final class UriComponents { * @author Arjen Poutsma * @see RFC 3986 */ - public static enum Type { + static enum Type { SCHEME { @Override @@ -797,6 +797,52 @@ public final class UriComponents { } + /** + * Represents a collection of PathComponents. + */ + final static class PathComponentComposite implements PathComponent { + + private final List pathComponents; + + PathComponentComposite(List pathComponents) { + this.pathComponents = pathComponents; + } + + public String getPath() { + StringBuilder pathBuilder = new StringBuilder(); + for (PathComponent pathComponent : pathComponents) { + pathBuilder.append(pathComponent.getPath()); + } + return pathBuilder.toString(); + } + + public List getPathSegments() { + List result = new ArrayList(); + for (PathComponent pathComponent : pathComponents) { + result.addAll(pathComponent.getPathSegments()); + } + return result; + } + + public PathComponent encode(String encoding) throws UnsupportedEncodingException { + List encodedComponents = new ArrayList(pathComponents.size()); + for (PathComponent pathComponent : pathComponents) { + encodedComponents.add(pathComponent.encode(encoding)); + } + return new PathComponentComposite(encodedComponents); + } + + public PathComponent expand(UriTemplateVariables uriVariables) { + List expandedComponents = new ArrayList(pathComponents.size()); + for (PathComponent pathComponent : pathComponents) { + expandedComponents.add(pathComponent.expand(uriVariables)); + } + return new PathComponentComposite(expandedComponents); + } + } + + + /** * Represents an empty path. */ diff --git a/org.springframework.web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/org.springframework.web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 48970c36f8..b6a7df9753 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/org.springframework.web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -428,20 +428,9 @@ public class UriComponentsBuilder { } public PathComponentBuilder appendPathSegments(String... pathSegments) { - for (String pathSegment : pathSegments) { - final boolean pathEndsInSlash = path.length() > 0 && path.charAt(path.length() - 1) == '/'; - final boolean segmentStartsWithSlash = pathSegment.charAt(0) == '/'; - - if (path.length() > 0 && !pathEndsInSlash && !segmentStartsWithSlash) { - path.append('/'); - } else if (pathEndsInSlash && segmentStartsWithSlash) { - pathSegment = pathSegment.substring(1); - if (pathSegment.length() == 0) - continue; - } - path.append(pathSegment); - } - return this; + PathComponentCompositeBuilder builder = new PathComponentCompositeBuilder(this); + builder.appendPathSegments(pathSegments); + return builder; } } @@ -461,13 +450,45 @@ public class UriComponentsBuilder { } public PathComponentBuilder appendPath(String path) { - String[] pathSegments = StringUtils.tokenizeToStringArray(path, "/"); + PathComponentCompositeBuilder builder = new PathComponentCompositeBuilder(this); + builder.appendPath(path); + return builder; + } + + public PathComponentBuilder appendPathSegments(String... pathSegments) { Collections.addAll(this.pathSegments, pathSegments); return this; } + } + + /** + * Represents a builder for a collection of PathComponents. + */ + private static class PathComponentCompositeBuilder implements PathComponentBuilder { + + private final List pathComponentBuilders = new ArrayList(); + + private PathComponentCompositeBuilder(PathComponentBuilder builder) { + pathComponentBuilders.add(builder); + } + + public UriComponents.PathComponent build() { + List pathComponents = + new ArrayList(pathComponentBuilders.size()); + + for (PathComponentBuilder pathComponentBuilder : pathComponentBuilders) { + pathComponents.add(pathComponentBuilder.build()); + } + return new UriComponents.PathComponentComposite(pathComponents); + } + + public PathComponentBuilder appendPath(String path) { + this.pathComponentBuilders.add(new FullPathComponentBuilder(path)); + return this; + } public PathComponentBuilder appendPathSegments(String... pathSegments) { - Collections.addAll(this.pathSegments, pathSegments); + this.pathComponentBuilders.add(new PathSegmentComponentBuilder(pathSegments)); return this; } } diff --git a/org.springframework.web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java b/org.springframework.web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java index a67f45f2be..8e1af12c5f 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java @@ -138,6 +138,42 @@ public class UriComponentsBuilderTests { assertEquals(Arrays.asList("foo", "bar"), result.getPathSegments()); } + @Test + public void pathThenPath() { + UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/foo/bar").path("ba/z"); + UriComponents result = builder.build().encode(); + + assertEquals("/foo/barba/z", result.getPath()); + assertEquals(Arrays.asList("foo", "barba", "z"), result.getPathSegments()); + } + + @Test + public void pathThenPathSegments() { + UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/foo/bar").pathSegment("ba/z"); + UriComponents result = builder.build().encode(); + + assertEquals("/foo/bar/ba%2Fz", result.getPath()); + assertEquals(Arrays.asList("foo", "bar", "ba%2Fz"), result.getPathSegments()); + } + + @Test + public void pathSegmentsThenPathSegments() { + UriComponentsBuilder builder = UriComponentsBuilder.newInstance().pathSegment("foo").pathSegment("bar"); + UriComponents result = builder.build(); + + assertEquals("/foo/bar", result.getPath()); + assertEquals(Arrays.asList("foo", "bar"), result.getPathSegments()); + } + + @Test + public void pathSegmentsThenPath() { + UriComponentsBuilder builder = UriComponentsBuilder.newInstance().pathSegment("foo").path("/"); + UriComponents result = builder.build(); + + assertEquals("/foo/", result.getPath()); + assertEquals(Arrays.asList("foo"), result.getPathSegments()); + } + @Test public void queryParams() throws URISyntaxException { UriComponentsBuilder builder = UriComponentsBuilder.newInstance(); diff --git a/org.springframework.web/src/test/java/org/springframework/web/util/UriComponentsTests.java b/org.springframework.web/src/test/java/org/springframework/web/util/UriComponentsTests.java index 7957d907db..a9824caec0 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/util/UriComponentsTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/util/UriComponentsTests.java @@ -45,5 +45,13 @@ public class UriComponentsTests { UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://example.com/hotel list/Z\u00fcrich").build(); assertEquals(new URI("http://example.com/hotel%20list/Z\u00fcrich"), uriComponents.toUri()); } + + @Test + public void expand() { + UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://example.com").path("/{foo} {bar}").build(); + uriComponents = uriComponents.expand("1 2", "3 4"); + assertEquals("/1 2 3 4", uriComponents.getPath()); + assertEquals("http://example.com/1 2 3 4", uriComponents.toUriString()); + } }