Skip to content

Commit bb3b1f2

Browse files
committed
Additional convenience methods in UriUtils
The generic encode method in UriUtils that encodes any character outside the reserved character set for a URI is meant for "strict" encoding of URI variable values. This commit adds a couple more conveninence methods that accept a Map or array of URI variable values to encode. This facilitates the use case where the URI template is assumed to be encoded while URI variables are encoded strictly to avoid any possibility for unwanted reserved characters: Map<String, ?> encodedUriVars = UriUtils.encodeUriVariables(uriVars); uriComponentsBuilder.build(true).expand(encodedUriVars).toUri(); Issue: SPR-14970
1 parent f2e293a commit bb3b1f2

File tree

2 files changed

+54
-22
lines changed

2 files changed

+54
-22
lines changed

spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -16,10 +16,8 @@
1616

1717
package org.springframework.web.util;
1818

19-
import java.io.UnsupportedEncodingException;
2019
import java.net.URI;
2120
import java.net.URISyntaxException;
22-
import java.util.HashMap;
2321
import java.util.List;
2422
import java.util.Map;
2523

@@ -127,10 +125,7 @@ protected UriComponents expandAndEncode(UriComponentsBuilder builder, Map<String
127125
return builder.buildAndExpand(uriVariables).encode();
128126
}
129127
else {
130-
Map<String, Object> encodedUriVars = new HashMap<>(uriVariables.size());
131-
for (Map.Entry<String, ?> entry : uriVariables.entrySet()) {
132-
encodedUriVars.put(entry.getKey(), applyStrictEncoding(entry.getValue()));
133-
}
128+
Map<String, ?> encodedUriVars = UriUtils.encodeUriVariables(uriVariables);
134129
return builder.buildAndExpand(encodedUriVars);
135130
}
136131
}
@@ -140,25 +135,11 @@ protected UriComponents expandAndEncode(UriComponentsBuilder builder, Object[] u
140135
return builder.buildAndExpand(uriVariables).encode();
141136
}
142137
else {
143-
Object[] encodedUriVars = new Object[uriVariables.length];
144-
for (int i = 0; i < uriVariables.length; i++) {
145-
encodedUriVars[i] = applyStrictEncoding(uriVariables[i]);
146-
}
138+
Object[] encodedUriVars = UriUtils.encodeUriVariables(uriVariables);
147139
return builder.buildAndExpand(encodedUriVars);
148140
}
149141
}
150142

151-
private String applyStrictEncoding(Object value) {
152-
String stringValue = (value != null ? value.toString() : "");
153-
try {
154-
return UriUtils.encode(stringValue, "UTF-8");
155-
}
156-
catch (UnsupportedEncodingException ex) {
157-
// Should never happen
158-
throw new IllegalStateException("Failed to encode URI variable", ex);
159-
}
160-
}
161-
162143
private URI createUri(UriComponents uriComponents) {
163144
try {
164145
// Avoid further encoding (in the case of strictEncoding=true)

spring-web/src/main/java/org/springframework/web/util/UriUtils.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818

1919
import java.io.UnsupportedEncodingException;
2020
import java.nio.charset.Charset;
21+
import java.nio.charset.StandardCharsets;
22+
import java.util.Arrays;
23+
import java.util.LinkedHashMap;
24+
import java.util.Map;
25+
import java.util.stream.Collectors;
2126

2227
import org.springframework.util.StringUtils;
2328

@@ -165,6 +170,52 @@ public static String encode(String source, String encoding) throws UnsupportedEn
165170
return HierarchicalUriComponents.encodeUriComponent(source, encoding, type);
166171
}
167172

173+
/**
174+
* Encode characters outside the unreserved character set as defined in
175+
* <a href="https://tools.ietf.org/html/rfc3986#section-2">RFC 3986 Section 2</a>.
176+
* <p>This can be used to ensure the given String will not contain any
177+
* characters with reserved URI meaning regardless of URI component.
178+
* @param source the String to be encoded
179+
* @param charset the character encoding to encode to
180+
* @return the encoded String
181+
*/
182+
public static String encode(String source, Charset charset) {
183+
HierarchicalUriComponents.Type type = HierarchicalUriComponents.Type.URI;
184+
return HierarchicalUriComponents.encodeUriComponent(source, charset, type);
185+
}
186+
187+
/**
188+
* Apply {@link #encode(String, String)} to the values in the given URI
189+
* variables and return a new Map containing the encoded values.
190+
* @param uriVariables the URI variable values to be encoded
191+
* @return the encoded String
192+
* @since 5.0
193+
*/
194+
public static Map<String, String> encodeUriVariables(Map<String, ?> uriVariables) {
195+
Map<String, String> result = new LinkedHashMap<>(uriVariables.size());
196+
uriVariables.entrySet().stream().forEach(entry -> {
197+
String stringValue = (entry.getValue() != null ? entry.getValue().toString() : "");
198+
result.put(entry.getKey(), encode(stringValue, StandardCharsets.UTF_8));
199+
});
200+
return result;
201+
}
202+
203+
/**
204+
* Apply {@link #encode(String, String)} to the values in the given URI
205+
* variables and return a new array containing the encoded values.
206+
* @param uriVariables the URI variable values to be encoded
207+
* @return the encoded String
208+
* @since 5.0
209+
*/
210+
public static Object[] encodeUriVariables(Object... uriVariables) {
211+
return Arrays.stream(uriVariables)
212+
.map(value -> {
213+
String stringValue = (value != null ? value.toString() : "");
214+
return encode(stringValue, StandardCharsets.UTF_8);
215+
})
216+
.collect(Collectors.toList()).toArray();
217+
}
218+
168219
/**
169220
* Decode the given encoded URI component.
170221
* <p>See {@link StringUtils#uriDecode(String, Charset) for the decoding rules.

0 commit comments

Comments
 (0)