Polishing

This commit is contained in:
Sam Brannen 2024-03-14 14:20:59 +01:00
parent 27d5213176
commit 4a3daa7812
2 changed files with 35 additions and 49 deletions

View File

@ -31,7 +31,7 @@ import org.springframework.util.CollectionUtils;
/** /**
* Representation of a URI template that can be expanded with URI variables via * Representation of a URI template that can be expanded with URI variables via
* {@link #expand(Map)}, {@link #expand(Object[])}, or matched to a URL via * {@link #expand(Map)} or {@link #expand(Object[])}, or matched to a URL via
* {@link #match(String)}. This class is designed to be thread-safe and * {@link #match(String)}. This class is designed to be thread-safe and
* reusable, and allows any number of expand or match calls. * reusable, and allows any number of expand or match calls.
* *
@ -77,7 +77,7 @@ public class UriTemplate implements Serializable {
/** /**
* Return the names of the variables in the template, in order. * Return the names of the variables in this template, in order.
* @return the template variable names * @return the template variable names
*/ */
public List<String> getVariableNames() { public List<String> getVariableNames() {
@ -85,16 +85,16 @@ public class UriTemplate implements Serializable {
} }
/** /**
* Given the Map of variables, expands this template into a URI. The Map keys represent variable names, * Given the Map of variables, expand this template into a URI.
* the Map values variable values. The order of variables is not significant. * <p>The Map keys represent variable names, and the Map values represent
* variable values. The order of variables is not significant.
* <p>Example: * <p>Example:
* <pre class="code"> * <pre class="code">
* UriTemplate template = new UriTemplate("https://example.com/hotels/{hotel}/bookings/{booking}"); * UriTemplate template = new UriTemplate("https://example.com/hotels/{hotel}/bookings/{booking}");
* Map&lt;String, String&gt; uriVariables = new HashMap&lt;String, String&gt;(); * Map&lt;String, String&gt; uriVariables = Map.of(
* uriVariables.put("booking", "42"); * "booking", "42",
* uriVariables.put("hotel", "Rest &amp; Relax"); * "hotel", "Rest &amp; Relax");
* System.out.println(template.expand(uriVariables)); * System.out.println(template.expand(uriVariables));</pre>
* </pre>
* will print: <blockquote>{@code https://example.com/hotels/Rest%20%26%20Relax/bookings/42}</blockquote> * will print: <blockquote>{@code https://example.com/hotels/Rest%20%26%20Relax/bookings/42}</blockquote>
* @param uriVariables the map of URI variables * @param uriVariables the map of URI variables
* @return the expanded URI * @return the expanded URI
@ -108,13 +108,13 @@ public class UriTemplate implements Serializable {
} }
/** /**
* Given an array of variables, expand this template into a full URI. The array represent variable values. * Given the array of variables, expand this template into a full URI.
* The order of variables is significant. * <p>The array represents variable values, and the order of variables is
* significant.
* <p>Example: * <p>Example:
* <pre class="code"> * <pre class="code">
* UriTemplate template = new UriTemplate("https://example.com/hotels/{hotel}/bookings/{booking}"); * UriTemplate template = new UriTemplate("https://example.com/hotels/{hotel}/bookings/{booking}");
* System.out.println(template.expand("Rest &amp; Relax", 42)); * System.out.println(template.expand("Rest &amp; Relax", 42));</pre>
* </pre>
* will print: <blockquote>{@code https://example.com/hotels/Rest%20%26%20Relax/bookings/42}</blockquote> * will print: <blockquote>{@code https://example.com/hotels/Rest%20%26%20Relax/bookings/42}</blockquote>
* @param uriVariableValues the array of URI variables * @param uriVariableValues the array of URI variables
* @return the expanded URI * @return the expanded URI
@ -141,13 +141,13 @@ public class UriTemplate implements Serializable {
} }
/** /**
* Match the given URI to a map of variable values. Keys in the returned map are variable names, * Match the given URI to a map of variable values based on this template.
* values are variable values, as occurred in the given URI. * <p>Keys in the returned map are variable names, and the values in the
* returned map are variable values, as present in the given URI.
* <p>Example: * <p>Example:
* <pre class="code"> * <pre class="code">
* UriTemplate template = new UriTemplate("https://example.com/hotels/{hotel}/bookings/{booking}"); * UriTemplate template = new UriTemplate("https://example.com/hotels/{hotel}/bookings/{booking}");
* System.out.println(template.match("https://example.com/hotels/1/bookings/42")); * System.out.println(template.match("https://example.com/hotels/1/bookings/42"));</pre>
* </pre>
* will print: <blockquote>{@code {hotel=1, booking=42}}</blockquote> * will print: <blockquote>{@code {hotel=1, booking=42}}</blockquote>
* @param uri the URI to match to * @param uri the URI to match to
* @return a map of variable values * @return a map of variable values

View File

@ -17,9 +17,6 @@
package org.springframework.web.util; package org.springframework.web.util;
import java.net.URI; import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -50,7 +47,7 @@ class UriTemplateTests {
void getVariableNames() { void getVariableNames() {
UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}"); UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}");
List<String> variableNames = template.getVariableNames(); List<String> variableNames = template.getVariableNames();
assertThat(variableNames).as("Invalid variable names").isEqualTo(Arrays.asList("hotel", "booking")); assertThat(variableNames).as("Invalid variable names").containsExactly("hotel", "booking");
} }
@Test @Test
@ -72,6 +69,9 @@ class UriTemplateTests {
UriTemplate template = new UriTemplate(""); UriTemplate template = new UriTemplate("");
URI result = template.expand(); URI result = template.expand();
assertThat(result).as("Invalid expanded template").isEqualTo(URI.create("")); assertThat(result).as("Invalid expanded template").isEqualTo(URI.create(""));
result = template.expand("1", "42");
assertThat(result).as("Invalid expanded template").isEqualTo(URI.create(""));
} }
@Test // SPR-9712 @Test // SPR-9712
@ -89,9 +89,7 @@ class UriTemplateTests {
@Test @Test
void expandMap() { void expandMap() {
Map<String, String> uriVariables = new HashMap<>(2); Map<String, String> uriVariables = Map.of("booking", "42", "hotel", "1");
uriVariables.put("booking", "42");
uriVariables.put("hotel", "1");
UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}"); UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}");
URI result = template.expand(uriVariables); URI result = template.expand(uriVariables);
assertThat(result).as("Invalid expanded template").isEqualTo(URI.create("/hotels/1/bookings/42")); assertThat(result).as("Invalid expanded template").isEqualTo(URI.create("/hotels/1/bookings/42"));
@ -100,16 +98,14 @@ class UriTemplateTests {
@Test @Test
void expandMapDuplicateVariables() { void expandMapDuplicateVariables() {
UriTemplate template = new UriTemplate("/order/{c}/{c}/{c}"); UriTemplate template = new UriTemplate("/order/{c}/{c}/{c}");
assertThat(template.getVariableNames()).isEqualTo(Arrays.asList("c", "c", "c")); assertThat(template.getVariableNames()).containsExactly("c", "c", "c");
URI result = template.expand(Collections.singletonMap("c", "cheeseburger")); URI result = template.expand(Map.of("c", "cheeseburger"));
assertThat(result).isEqualTo(URI.create("/order/cheeseburger/cheeseburger/cheeseburger")); assertThat(result).isEqualTo(URI.create("/order/cheeseburger/cheeseburger/cheeseburger"));
} }
@Test @Test
void expandMapNonString() { void expandMapNonString() {
Map<String, Integer> uriVariables = new HashMap<>(2); Map<String, Integer> uriVariables = Map.of("booking", 42, "hotel", 1);
uriVariables.put("booking", 42);
uriVariables.put("hotel", 1);
UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}"); UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}");
URI result = template.expand(uriVariables); URI result = template.expand(uriVariables);
assertThat(result).as("Invalid expanded template").isEqualTo(URI.create("/hotels/1/bookings/42")); assertThat(result).as("Invalid expanded template").isEqualTo(URI.create("/hotels/1/bookings/42"));
@ -117,7 +113,7 @@ class UriTemplateTests {
@Test @Test
void expandMapEncoded() { void expandMapEncoded() {
Map<String, String> uriVariables = Collections.singletonMap("hotel", "Z\u00fcrich"); Map<String, String> uriVariables = Map.of("hotel", "Z\u00fcrich");
UriTemplate template = new UriTemplate("/hotel list/{hotel}"); UriTemplate template = new UriTemplate("/hotel list/{hotel}");
URI result = template.expand(uriVariables); URI result = template.expand(uriVariables);
assertThat(result).as("Invalid expanded template").isEqualTo(URI.create("/hotel%20list/Z%C3%BCrich")); assertThat(result).as("Invalid expanded template").isEqualTo(URI.create("/hotel%20list/Z%C3%BCrich"));
@ -125,12 +121,9 @@ class UriTemplateTests {
@Test @Test
void expandMapUnboundVariables() { void expandMapUnboundVariables() {
Map<String, String> uriVariables = new HashMap<>(2); Map<String, String> uriVariables = Map.of("booking", "42", "bar", "1");
uriVariables.put("booking", "42");
uriVariables.put("bar", "1");
UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}"); UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}");
assertThatIllegalArgumentException().isThrownBy(() -> assertThatIllegalArgumentException().isThrownBy(() -> template.expand(uriVariables));
template.expand(uriVariables));
} }
@Test @Test
@ -167,9 +160,7 @@ class UriTemplateTests {
@Test @Test
void match() { void match() {
Map<String, String> expected = new HashMap<>(2); Map<String, String> expected = Map.of("booking", "42", "hotel", "1");
expected.put("booking", "42");
expected.put("hotel", "1");
UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}"); UriTemplate template = new UriTemplate("/hotels/{hotel}/bookings/{booking}");
Map<String, String> result = template.match("/hotels/1/bookings/42"); Map<String, String> result = template.match("/hotels/1/bookings/42");
@ -185,9 +176,7 @@ class UriTemplateTests {
@Test @Test
void matchCustomRegex() { void matchCustomRegex() {
Map<String, String> expected = new HashMap<>(2); Map<String, String> expected = Map.of("booking", "42", "hotel", "1");
expected.put("booking", "42");
expected.put("hotel", "1");
UriTemplate template = new UriTemplate("/hotels/{hotel:\\d}/bookings/{booking:\\d+}"); UriTemplate template = new UriTemplate("/hotels/{hotel:\\d}/bookings/{booking:\\d+}");
Map<String, String> result = template.match("/hotels/1/bookings/42"); Map<String, String> result = template.match("/hotels/1/bookings/42");
@ -198,24 +187,21 @@ class UriTemplateTests {
void matchCustomRegexWithNestedCurlyBraces() { void matchCustomRegexWithNestedCurlyBraces() {
UriTemplate template = new UriTemplate("/site.{domain:co.[a-z]{2}}"); UriTemplate template = new UriTemplate("/site.{domain:co.[a-z]{2}}");
Map<String, String> result = template.match("/site.co.eu"); Map<String, String> result = template.match("/site.co.eu");
assertThat(result).as("Invalid match").isEqualTo(Collections.singletonMap("domain", "co.eu")); assertThat(result).as("Invalid match").isEqualTo(Map.of("domain", "co.eu"));
} }
@Test @Test
void matchDuplicate() { void matchDuplicate() {
UriTemplate template = new UriTemplate("/order/{c}/{c}/{c}"); UriTemplate template = new UriTemplate("/order/{c}/{c}/{c}");
Map<String, String> result = template.match("/order/cheeseburger/cheeseburger/cheeseburger"); Map<String, String> result = template.match("/order/cheeseburger/cheeseburger/cheeseburger");
Map<String, String> expected = Collections.singletonMap("c", "cheeseburger"); assertThat(result).as("Invalid match").isEqualTo(Map.of("c", "cheeseburger"));
assertThat(result).as("Invalid match").isEqualTo(expected);
} }
@Test @Test
void matchMultipleInOneSegment() { void matchMultipleInOneSegment() {
UriTemplate template = new UriTemplate("/{foo}-{bar}"); UriTemplate template = new UriTemplate("/{foo}-{bar}");
Map<String, String> result = template.match("/12-34"); Map<String, String> result = template.match("/12-34");
Map<String, String> expected = new HashMap<>(2); Map<String, String> expected = Map.of("foo", "12", "bar", "34");
expected.put("foo", "12");
expected.put("bar", "34");
assertThat(result).as("Invalid match").isEqualTo(expected); assertThat(result).as("Invalid match").isEqualTo(expected);
} }
@ -249,14 +235,14 @@ class UriTemplateTests {
void expandWithDollar() { void expandWithDollar() {
UriTemplate template = new UriTemplate("/{a}"); UriTemplate template = new UriTemplate("/{a}");
URI uri = template.expand("$replacement"); URI uri = template.expand("$replacement");
assertThat(uri.toString()).isEqualTo("/$replacement"); assertThat(uri).hasToString("/$replacement");
} }
@Test @Test
void expandWithAtSign() { void expandWithAtSign() {
UriTemplate template = new UriTemplate("http://localhost/query={query}"); UriTemplate template = new UriTemplate("http://localhost/query={query}");
URI uri = template.expand("foo@bar"); URI uri = template.expand("foo@bar");
assertThat(uri.toString()).isEqualTo("http://localhost/query=foo@bar"); assertThat(uri).hasToString("http://localhost/query=foo@bar");
} }
} }