/*
* Copyright 2002-2018 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.util;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
Default implementation of UriTemplateHandler
based on the use of UriComponentsBuilder
for expanding and encoding variables. There are also several properties to customize how URI template handling is performed, including a baseUrl
to be used as a prefix for all URI templates and a couple of encoding related options — parsePath
and strictEncoding
respectively.
Author: Rossen Stoyanchev Since: 4.2 Deprecated: as of 5.0 in favor of DefaultUriBuilderFactory
. Note: DefaultUriBuilderFactory
has a different default for the parsePath
property (from false to true).
/**
* Default implementation of {@link UriTemplateHandler} based on the use of
* {@link UriComponentsBuilder} for expanding and encoding variables.
*
* <p>There are also several properties to customize how URI template handling
* is performed, including a {@link #setBaseUrl baseUrl} to be used as a prefix
* for all URI templates and a couple of encoding related options —
* {@link #setParsePath parsePath} and {@link #setStrictEncoding strictEncoding}
* respectively.
*
* @author Rossen Stoyanchev
* @since 4.2
* @deprecated as of 5.0 in favor of {@link DefaultUriBuilderFactory}.
* <p><strong>Note:</strong> {@link DefaultUriBuilderFactory} has a different
* default for the {@link #setParsePath(boolean) parsePath} property (from
* false to true).
*/
@Deprecated
public class DefaultUriTemplateHandler extends AbstractUriTemplateHandler {
private boolean parsePath;
private boolean strictEncoding;
Whether to parse the path of a URI template string into path segments.
If set to true
the URI template path is immediately decomposed into path segments any URI variables expanded into it are then subject to path segment encoding rules. In effect URI variables in the path have any "/" characters percent encoded.
By default this is set to false
in which case the path is kept as a full path and expanded URI variables will preserve "/" characters.
Params: - parsePath – whether to parse the path into path segments
/**
* Whether to parse the path of a URI template string into path segments.
* <p>If set to {@code true} the URI template path is immediately decomposed
* into path segments any URI variables expanded into it are then subject to
* path segment encoding rules. In effect URI variables in the path have any
* "/" characters percent encoded.
* <p>By default this is set to {@code false} in which case the path is kept
* as a full path and expanded URI variables will preserve "/" characters.
* @param parsePath whether to parse the path into path segments
*/
public void setParsePath(boolean parsePath) {
this.parsePath = parsePath;
}
Whether the handler is configured to parse the path into path segments.
/**
* Whether the handler is configured to parse the path into path segments.
*/
public boolean shouldParsePath() {
return this.parsePath;
}
Whether to encode characters outside the unreserved set as defined in
RFC 3986 Section 2.
This ensures a URI variable value will not contain any characters with a
reserved purpose.
By default this is set to false
in which case only characters illegal for the given URI component are encoded. For example when expanding a URI variable into a path segment the "/" character is illegal and encoded. The ";" character however is legal and not encoded even though it has a reserved purpose.
Note: this property supersedes the need to also set the parsePath
property.
Params: - strictEncoding – whether to perform strict encoding
Since: 4.3
/**
* Whether to encode characters outside the unreserved set as defined in
* <a href="https://tools.ietf.org/html/rfc3986#section-2">RFC 3986 Section 2</a>.
* This ensures a URI variable value will not contain any characters with a
* reserved purpose.
* <p>By default this is set to {@code false} in which case only characters
* illegal for the given URI component are encoded. For example when expanding
* a URI variable into a path segment the "/" character is illegal and
* encoded. The ";" character however is legal and not encoded even though
* it has a reserved purpose.
* <p><strong>Note:</strong> this property supersedes the need to also set
* the {@link #setParsePath parsePath} property.
* @param strictEncoding whether to perform strict encoding
* @since 4.3
*/
public void setStrictEncoding(boolean strictEncoding) {
this.strictEncoding = strictEncoding;
}
Whether to strictly encode any character outside the unreserved set.
/**
* Whether to strictly encode any character outside the unreserved set.
*/
public boolean isStrictEncoding() {
return this.strictEncoding;
}
@Override
protected URI expandInternal(String uriTemplate, Map<String, ?> uriVariables) {
UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate);
UriComponents uriComponents = expandAndEncode(uriComponentsBuilder, uriVariables);
return createUri(uriComponents);
}
@Override
protected URI expandInternal(String uriTemplate, Object... uriVariables) {
UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate);
UriComponents uriComponents = expandAndEncode(uriComponentsBuilder, uriVariables);
return createUri(uriComponents);
}
Create a UriComponentsBuilder
from the URI template string. This implementation also breaks up the path into path segments depending on whether parsePath
is enabled. /**
* Create a {@code UriComponentsBuilder} from the URI template string.
* This implementation also breaks up the path into path segments depending
* on whether {@link #setParsePath parsePath} is enabled.
*/
protected UriComponentsBuilder initUriComponentsBuilder(String uriTemplate) {
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(uriTemplate);
if (shouldParsePath() && !isStrictEncoding()) {
List<String> pathSegments = builder.build().getPathSegments();
builder.replacePath(null);
for (String pathSegment : pathSegments) {
builder.pathSegment(pathSegment);
}
}
return builder;
}
protected UriComponents expandAndEncode(UriComponentsBuilder builder, Map<String, ?> uriVariables) {
if (!isStrictEncoding()) {
return builder.buildAndExpand(uriVariables).encode();
}
else {
Map<String, ?> encodedUriVars = UriUtils.encodeUriVariables(uriVariables);
return builder.buildAndExpand(encodedUriVars);
}
}
protected UriComponents expandAndEncode(UriComponentsBuilder builder, Object[] uriVariables) {
if (!isStrictEncoding()) {
return builder.buildAndExpand(uriVariables).encode();
}
else {
Object[] encodedUriVars = UriUtils.encodeUriVariables(uriVariables);
return builder.buildAndExpand(encodedUriVars);
}
}
private URI createUri(UriComponents uriComponents) {
try {
// Avoid further encoding (in the case of strictEncoding=true)
return new URI(uriComponents.toUriString());
}
catch (URISyntaxException ex) {
throw new IllegalStateException("Could not create URI object: " + ex.getMessage(), ex);
}
}
}