Consistent support for Charset/StandardCharsets in UriUtils etc

Issue: SPR-15613
This commit is contained in:
Juergen Hoeller
2017-06-12 15:51:45 +02:00
parent 14161d1dbf
commit 3ae84d6dd8
15 changed files with 244 additions and 171 deletions

View File

@@ -71,7 +71,7 @@ public class Jaxb2XmlEncoder extends AbstractSingleValueEncoder<Object> {
@Override
protected Flux<DataBuffer> encode(Object value, DataBufferFactory dataBufferFactory,
ResolvableType type, MimeType mimeType, @Nullable Map<String, Object> hints) {
ResolvableType type, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
try {
DataBuffer buffer = dataBufferFactory.allocateBuffer(1024);
OutputStream outputStream = buffer.asOutputStream();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,8 +66,8 @@ public abstract class AbstractWireFeedHttpMessageConverter<T extends WireFeed> e
WireFeedInput feedInput = new WireFeedInput();
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset =
(contentType != null && contentType.getCharset() != null? contentType.getCharset() : DEFAULT_CHARSET);
Charset charset = (contentType != null && contentType.getCharset() != null ?
contentType.getCharset() : DEFAULT_CHARSET);
try {
Reader reader = new InputStreamReader(inputMessage.getBody(), charset);
return (T) feedInput.build(reader);
@@ -81,20 +81,17 @@ public abstract class AbstractWireFeedHttpMessageConverter<T extends WireFeed> e
protected void writeInternal(T wireFeed, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
String wireFeedEncoding = wireFeed.getEncoding();
if (!StringUtils.hasLength(wireFeedEncoding)) {
wireFeedEncoding = DEFAULT_CHARSET.name();
}
Charset charset = (StringUtils.hasLength(wireFeed.getEncoding()) ?
Charset.forName(wireFeed.getEncoding()) : DEFAULT_CHARSET);
MediaType contentType = outputMessage.getHeaders().getContentType();
if (contentType != null) {
Charset wireFeedCharset = Charset.forName(wireFeedEncoding);
contentType = new MediaType(contentType.getType(), contentType.getSubtype(), wireFeedCharset);
contentType = new MediaType(contentType.getType(), contentType.getSubtype(), charset);
outputMessage.getHeaders().setContentType(contentType);
}
WireFeedOutput feedOutput = new WireFeedOutput();
try {
Writer writer = new OutputStreamWriter(outputMessage.getBody(), wireFeedEncoding);
Writer writer = new OutputStreamWriter(outputMessage.getBody(), charset);
feedOutput.output(wireFeed, writer);
}
catch (FeedException ex) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.springframework.web.client;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
@@ -32,7 +33,7 @@ public class RestClientResponseException extends RestClientException {
private static final long serialVersionUID = -8803556342728481792L;
private static final String DEFAULT_CHARSET = "ISO-8859-1";
private static final Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
private final int rawStatusCode;
@@ -62,7 +63,7 @@ public class RestClientResponseException extends RestClientException {
this.statusText = statusText;
this.responseHeaders = responseHeaders;
this.responseBody = (responseBody != null ? responseBody : new byte[0]);
this.responseCharset = (responseCharset != null ? responseCharset.name() : DEFAULT_CHARSET);
this.responseCharset = (responseCharset != null ? responseCharset.name() : null);
}
@@ -98,6 +99,9 @@ public class RestClientResponseException extends RestClientException {
* Return the response body as a string.
*/
public String getResponseBodyAsString() {
if (this.responseCharset == null) {
return new String(this.responseBody, DEFAULT_CHARSET);
}
try {
return new String(this.responseBody, this.responseCharset);
}

View File

@@ -57,6 +57,17 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(scheme, encoding, HierarchicalUriComponents.Type.SCHEME);
}
/**
* Encode the given URI scheme with the given encoding.
* @param scheme the scheme to be encoded
* @param charset the character encoding to encode to
* @return the encoded scheme
* @since 5.0
*/
public static String encodeScheme(String scheme, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(scheme, charset, HierarchicalUriComponents.Type.SCHEME);
}
/**
* Encode the given URI authority with the given encoding.
* @param authority the authority to be encoded
@@ -68,6 +79,17 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(authority, encoding, HierarchicalUriComponents.Type.AUTHORITY);
}
/**
* Encode the given URI authority with the given encoding.
* @param authority the authority to be encoded
* @param charset the character encoding to encode to
* @return the encoded authority
* @since 5.0
*/
public static String encodeAuthority(String authority, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(authority, charset, HierarchicalUriComponents.Type.AUTHORITY);
}
/**
* Encode the given URI user info with the given encoding.
* @param userInfo the user info to be encoded
@@ -79,6 +101,17 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(userInfo, encoding, HierarchicalUriComponents.Type.USER_INFO);
}
/**
* Encode the given URI user info with the given encoding.
* @param userInfo the user info to be encoded
* @param charset the character encoding to encode to
* @return the encoded user info
* @since 5.0
*/
public static String encodeUserInfo(String userInfo, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(userInfo, charset, HierarchicalUriComponents.Type.USER_INFO);
}
/**
* Encode the given URI host with the given encoding.
* @param host the host to be encoded
@@ -90,6 +123,17 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(host, encoding, HierarchicalUriComponents.Type.HOST_IPV4);
}
/**
* Encode the given URI host with the given encoding.
* @param host the host to be encoded
* @param charset the character encoding to encode to
* @return the encoded host
* @since 5.0
*/
public static String encodeHost(String host, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(host, charset, HierarchicalUriComponents.Type.HOST_IPV4);
}
/**
* Encode the given URI port with the given encoding.
* @param port the port to be encoded
@@ -101,6 +145,17 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(port, encoding, HierarchicalUriComponents.Type.PORT);
}
/**
* Encode the given URI port with the given encoding.
* @param port the port to be encoded
* @param charset the character encoding to encode to
* @return the encoded port
* @since 5.0
*/
public static String encodePort(String port, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(port, charset, HierarchicalUriComponents.Type.PORT);
}
/**
* Encode the given URI path with the given encoding.
* @param path the path to be encoded
@@ -112,6 +167,17 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(path, encoding, HierarchicalUriComponents.Type.PATH);
}
/**
* Encode the given URI path with the given encoding.
* @param path the path to be encoded
* @param charset the character encoding to encode to
* @return the encoded path
* @since 5.0
*/
public static String encodePath(String path, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(path, charset, HierarchicalUriComponents.Type.PATH);
}
/**
* Encode the given URI path segment with the given encoding.
* @param segment the segment to be encoded
@@ -123,6 +189,17 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(segment, encoding, HierarchicalUriComponents.Type.PATH_SEGMENT);
}
/**
* Encode the given URI path segment with the given encoding.
* @param segment the segment to be encoded
* @param charset the character encoding to encode to
* @return the encoded segment
* @since 5.0
*/
public static String encodePathSegment(String segment, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(segment, charset, HierarchicalUriComponents.Type.PATH_SEGMENT);
}
/**
* Encode the given URI query with the given encoding.
* @param query the query to be encoded
@@ -134,6 +211,17 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(query, encoding, HierarchicalUriComponents.Type.QUERY);
}
/**
* Encode the given URI query with the given encoding.
* @param query the query to be encoded
* @param charset the character encoding to encode to
* @return the encoded query
* @since 5.0
*/
public static String encodeQuery(String query, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(query, charset, HierarchicalUriComponents.Type.QUERY);
}
/**
* Encode the given URI query parameter with the given encoding.
* @param queryParam the query parameter to be encoded
@@ -145,6 +233,17 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(queryParam, encoding, HierarchicalUriComponents.Type.QUERY_PARAM);
}
/**
* Encode the given URI query parameter with the given encoding.
* @param queryParam the query parameter to be encoded
* @param charset the character encoding to encode to
* @return the encoded query parameter
* @since 5.0
*/
public static String encodeQueryParam(String queryParam, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(queryParam, charset, HierarchicalUriComponents.Type.QUERY_PARAM);
}
/**
* Encode the given URI fragment with the given encoding.
* @param fragment the fragment to be encoded
@@ -156,6 +255,18 @@ public abstract class UriUtils {
return HierarchicalUriComponents.encodeUriComponent(fragment, encoding, HierarchicalUriComponents.Type.FRAGMENT);
}
/**
* Encode the given URI fragment with the given encoding.
* @param fragment the fragment to be encoded
* @param charset the character encoding to encode to
* @return the encoded fragment
* @since 5.0
*/
public static String encodeFragment(String fragment, Charset charset) {
return HierarchicalUriComponents.encodeUriComponent(fragment, charset, HierarchicalUriComponents.Type.FRAGMENT);
}
/**
* Encode characters outside the unreserved character set as defined in
* <a href="https://tools.ietf.org/html/rfc3986#section-2">RFC 3986 Section 2</a>.
@@ -179,49 +290,18 @@ public abstract class UriUtils {
* @param source the String to be encoded
* @param charset the character encoding to encode to
* @return the encoded String
* @since 5.0
*/
public static String encode(String source, Charset charset) {
HierarchicalUriComponents.Type type = HierarchicalUriComponents.Type.URI;
return HierarchicalUriComponents.encodeUriComponent(source, charset, type);
}
/**
* Apply {@link #encode(String, String)} to the values in the given URI
* variables and return a new Map containing the encoded values.
* @param uriVariables the URI variable values to be encoded
* @return the encoded String
* @since 5.0
*/
public static Map<String, String> encodeUriVariables(Map<String, ?> uriVariables) {
Map<String, String> result = new LinkedHashMap<>(uriVariables.size());
uriVariables.forEach((key, value) -> {
String stringValue = (value != null ? value.toString() : "");
result.put(key, encode(stringValue, StandardCharsets.UTF_8));
});
return result;
}
/**
* Apply {@link #encode(String, String)} to the values in the given URI
* variables and return a new array containing the encoded values.
* @param uriVariables the URI variable values to be encoded
* @return the encoded String
* @since 5.0
*/
public static Object[] encodeUriVariables(Object... uriVariables) {
return Arrays.stream(uriVariables)
.map(value -> {
String stringValue = (value != null ? value.toString() : "");
return encode(stringValue, StandardCharsets.UTF_8);
})
.collect(Collectors.toList()).toArray();
}
/**
* Decode the given encoded URI component.
* <p>See {@link StringUtils#uriDecode(String, Charset)} for the decoding rules.
* @param source the encoded String
* @param encoding the encoding
* @param encoding the character encoding to use
* @return the decoded value
* @throws IllegalArgumentException when the given source contains invalid encoded sequences
* @throws UnsupportedEncodingException when the given encoding parameter is not supported
@@ -232,6 +312,21 @@ public abstract class UriUtils {
return StringUtils.uriDecode(source, Charset.forName(encoding));
}
/**
* Decode the given encoded URI component.
* <p>See {@link StringUtils#uriDecode(String, Charset)} for the decoding rules.
* @param source the encoded String
* @param charset the character encoding to use
* @return the decoded value
* @throws IllegalArgumentException when the given source contains invalid encoded sequences
* @since 5.0
* @see StringUtils#uriDecode(String, Charset)
* @see java.net.URLDecoder#decode(String, String)
*/
public static String decode(String source, Charset charset) {
return StringUtils.uriDecode(source, charset);
}
/**
* Extract the file extension from the given URI path.
* @param path the URI path (e.g. "/products/index.html")
@@ -257,4 +352,37 @@ public abstract class UriUtils {
return null;
}
/**
* Apply {@link #encode(String, String)} to the values in the given URI
* variables and return a new Map containing the encoded values.
* @param uriVariables the URI variable values to be encoded
* @return the encoded String
* @since 5.0
*/
static Map<String, String> encodeUriVariables(Map<String, ?> uriVariables) {
Map<String, String> result = new LinkedHashMap<>(uriVariables.size());
uriVariables.forEach((key, value) -> {
String stringValue = (value != null ? value.toString() : "");
result.put(key, encode(stringValue, StandardCharsets.UTF_8));
});
return result;
}
/**
* Apply {@link #encode(String, String)} to the values in the given URI
* variables and return a new array containing the encoded values.
* @param uriVariables the URI variable values to be encoded
* @return the encoded String
* @since 5.0
*/
static Object[] encodeUriVariables(Object... uriVariables) {
return Arrays.stream(uriVariables)
.map(value -> {
String stringValue = (value != null ? value.toString() : "");
return encode(stringValue, StandardCharsets.UTF_8);
})
.collect(Collectors.toList()).toArray();
}
}

View File

@@ -16,7 +16,6 @@
package org.springframework.web.util.pattern;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -84,12 +83,7 @@ class CaptureVariablePathElement extends PathElement {
// TODO possible optimization - only regex match if rest of pattern matches? Benefit likely to vary pattern to pattern
if (includesPercent(matchingContext.candidate, candidateIndex, nextPos)) {
substringForDecoding = new String(matchingContext.candidate, candidateIndex, nextPos);
try {
candidateCapture = UriUtils.decode(substringForDecoding,StandardCharsets.UTF_8.name());
}
catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
candidateCapture = UriUtils.decode(substringForDecoding, StandardCharsets.UTF_8);
}
else {
candidateCapture = new SubSequence(matchingContext.candidate, candidateIndex, nextPos);

View File

@@ -16,7 +16,6 @@
package org.springframework.web.util.pattern;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@@ -311,15 +310,9 @@ class InternalPathPatternParser {
private char[] getPathElementText(boolean encodeElement) {
char[] pathElementText = new char[this.pos - this.pathElementStart];
if (encodeElement) {
try {
String unencoded = new String(this.pathPatternData, this.pathElementStart, this.pos - this.pathElementStart);
String encoded = UriUtils.encodeFragment(unencoded, StandardCharsets.UTF_8.name());
pathElementText = encoded.toCharArray();
}
catch (UnsupportedEncodingException ex) {
// Should never happen...
throw new IllegalStateException(ex);
}
String unencoded = new String(this.pathPatternData, this.pathElementStart, this.pos - this.pathElementStart);
String encoded = UriUtils.encodeFragment(unencoded, StandardCharsets.UTF_8);
pathElementText = encoded.toCharArray();
}
else {
System.arraycopy(this.pathPatternData, this.pathElementStart, pathElementText, 0,

View File

@@ -16,7 +16,6 @@
package org.springframework.web.util.pattern;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import org.springframework.web.util.UriUtils;
@@ -105,23 +104,18 @@ abstract class PathElement {
/**
* Decode an input CharSequence if necessary.
* @param toDecode the input char sequence that should be decoded if necessary
* @returns the decoded result
* @return the decoded result
*/
protected String decode(CharSequence toDecode) {
CharSequence decoded = toDecode;
if (includesPercent(toDecode)) {
try {
decoded = UriUtils.decode(toDecode.toString(), StandardCharsets.UTF_8.name());
}
catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
decoded = UriUtils.decode(toDecode.toString(), StandardCharsets.UTF_8);
}
return decoded.toString();
}
/**
* @param char sequence of characters
* @param chars sequence of characters
* @param from start position (included in check)
* @param to end position (excluded from check)
* @return true if the chars array includes a '%' character between the specified positions

View File

@@ -16,7 +16,6 @@
package org.springframework.web.util.pattern;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
@@ -132,13 +131,8 @@ class RegexPathElement extends PathElement {
return "";
}
String substring = s.substring(start, end);
try {
String encodedSubString = UriUtils.encodePath(substring, StandardCharsets.UTF_8.name());
encodedRegexBuilder.append(encodedSubString);
}
catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
String encodedSubString = UriUtils.encodePath(substring, StandardCharsets.UTF_8);
encodedRegexBuilder.append(encodedSubString);
return Pattern.quote(substring);
}