001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.util; 018 019import java.net.URI; 020import java.net.URISyntaxException; 021import java.util.List; 022import java.util.Map; 023 024/** 025 * Default implementation of {@link UriTemplateHandler} based on the use of 026 * {@link UriComponentsBuilder} for expanding and encoding variables. 027 * 028 * <p>There are also several properties to customize how URI template handling 029 * is performed, including a {@link #setBaseUrl baseUrl} to be used as a prefix 030 * for all URI templates and a couple of encoding related options — 031 * {@link #setParsePath parsePath} and {@link #setStrictEncoding strictEncoding} 032 * respectively. 033 * 034 * @author Rossen Stoyanchev 035 * @since 4.2 036 * @deprecated as of 5.0 in favor of {@link DefaultUriBuilderFactory}. 037 * <p><strong>Note:</strong> {@link DefaultUriBuilderFactory} has a different 038 * default for the {@link #setParsePath(boolean) parsePath} property (from 039 * false to true). 040 */ 041@Deprecated 042public class DefaultUriTemplateHandler extends AbstractUriTemplateHandler { 043 044 private boolean parsePath; 045 046 private boolean strictEncoding; 047 048 049 /** 050 * Whether to parse the path of a URI template string into path segments. 051 * <p>If set to {@code true} the URI template path is immediately decomposed 052 * into path segments any URI variables expanded into it are then subject to 053 * path segment encoding rules. In effect URI variables in the path have any 054 * "/" characters percent encoded. 055 * <p>By default this is set to {@code false} in which case the path is kept 056 * as a full path and expanded URI variables will preserve "/" characters. 057 * @param parsePath whether to parse the path into path segments 058 */ 059 public void setParsePath(boolean parsePath) { 060 this.parsePath = parsePath; 061 } 062 063 /** 064 * Whether the handler is configured to parse the path into path segments. 065 */ 066 public boolean shouldParsePath() { 067 return this.parsePath; 068 } 069 070 /** 071 * Whether to encode characters outside the unreserved set as defined in 072 * <a href="https://tools.ietf.org/html/rfc3986#section-2">RFC 3986 Section 2</a>. 073 * This ensures a URI variable value will not contain any characters with a 074 * reserved purpose. 075 * <p>By default this is set to {@code false} in which case only characters 076 * illegal for the given URI component are encoded. For example when expanding 077 * a URI variable into a path segment the "/" character is illegal and 078 * encoded. The ";" character however is legal and not encoded even though 079 * it has a reserved purpose. 080 * <p><strong>Note:</strong> this property supersedes the need to also set 081 * the {@link #setParsePath parsePath} property. 082 * @param strictEncoding whether to perform strict encoding 083 * @since 4.3 084 */ 085 public void setStrictEncoding(boolean strictEncoding) { 086 this.strictEncoding = strictEncoding; 087 } 088 089 /** 090 * Whether to strictly encode any character outside the unreserved set. 091 */ 092 public boolean isStrictEncoding() { 093 return this.strictEncoding; 094 } 095 096 097 @Override 098 protected URI expandInternal(String uriTemplate, Map<String, ?> uriVariables) { 099 UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate); 100 UriComponents uriComponents = expandAndEncode(uriComponentsBuilder, uriVariables); 101 return createUri(uriComponents); 102 } 103 104 @Override 105 protected URI expandInternal(String uriTemplate, Object... uriVariables) { 106 UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate); 107 UriComponents uriComponents = expandAndEncode(uriComponentsBuilder, uriVariables); 108 return createUri(uriComponents); 109 } 110 111 /** 112 * Create a {@code UriComponentsBuilder} from the URI template string. 113 * This implementation also breaks up the path into path segments depending 114 * on whether {@link #setParsePath parsePath} is enabled. 115 */ 116 protected UriComponentsBuilder initUriComponentsBuilder(String uriTemplate) { 117 UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(uriTemplate); 118 if (shouldParsePath() && !isStrictEncoding()) { 119 List<String> pathSegments = builder.build().getPathSegments(); 120 builder.replacePath(null); 121 for (String pathSegment : pathSegments) { 122 builder.pathSegment(pathSegment); 123 } 124 } 125 return builder; 126 } 127 128 protected UriComponents expandAndEncode(UriComponentsBuilder builder, Map<String, ?> uriVariables) { 129 if (!isStrictEncoding()) { 130 return builder.buildAndExpand(uriVariables).encode(); 131 } 132 else { 133 Map<String, ?> encodedUriVars = UriUtils.encodeUriVariables(uriVariables); 134 return builder.buildAndExpand(encodedUriVars); 135 } 136 } 137 138 protected UriComponents expandAndEncode(UriComponentsBuilder builder, Object[] uriVariables) { 139 if (!isStrictEncoding()) { 140 return builder.buildAndExpand(uriVariables).encode(); 141 } 142 else { 143 Object[] encodedUriVars = UriUtils.encodeUriVariables(uriVariables); 144 return builder.buildAndExpand(encodedUriVars); 145 } 146 } 147 148 private URI createUri(UriComponents uriComponents) { 149 try { 150 // Avoid further encoding (in the case of strictEncoding=true) 151 return new URI(uriComponents.toUriString()); 152 } 153 catch (URISyntaxException ex) { 154 throw new IllegalStateException("Could not create URI object: " + ex.getMessage(), ex); 155 } 156 } 157 158}