in grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/RegexUrlMapping.java [285:412]
private String createURLInternal(Map paramValues, String encoding, boolean includeContextPath) {
if (encoding == null) encoding = "utf-8";
String contextPath = "";
if (includeContextPath) {
GrailsWebRequest webRequest = (GrailsWebRequest) RequestContextHolder.getRequestAttributes();
if (webRequest != null) {
contextPath = webRequest.getContextPath();
}
}
if (paramValues == null) paramValues = Collections.emptyMap();
StringBuilder uri = new StringBuilder(contextPath);
Set usedParams = new HashSet();
String[] tokens = urlData.getTokens();
int paramIndex = 0;
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i];
if (i == tokens.length - 1 && urlData.hasOptionalExtension()) {
token += OPTIONAL_EXTENSION_WILDCARD;
}
Matcher m = OPTIONAL_EXTENSION_WILDCARD_PATTERN.matcher(token);
if (m.find()) {
boolean tokenSet = false;
if (token.startsWith(CAPTURED_WILDCARD)) {
ConstrainedProperty prop = constraints[paramIndex++];
String propName = prop.getPropertyName();
Object value = paramValues.get(propName);
usedParams.add(propName);
if (value != null) {
token = token.replaceFirst(DOUBLE_WILDCARD_PATTERN.pattern(), Matcher.quoteReplacement(value.toString()));
tokenSet = true;
}
else {
token = token.replaceFirst(DOUBLE_WILDCARD_PATTERN.pattern(), "");
}
}
else {
tokenSet = true;
}
if(tokenSet) {
uri.append(SLASH);
}
ConstrainedProperty prop = constraints[paramIndex++];
String propName = prop.getPropertyName();
Object value = paramValues.get(propName);
usedParams.add(propName);
if (value != null) {
String ext = "." + value;
uri.append(token.replace(OPTIONAL_EXTENSION_WILDCARD+'?', ext).replace(OPTIONAL_EXTENSION_WILDCARD, ext));
}
else {
uri.append(token.replace(OPTIONAL_EXTENSION_WILDCARD+'?', "").replace(OPTIONAL_EXTENSION_WILDCARD, ""));
}
continue;
}
if (token.endsWith("?")) {
token = token.substring(0,token.length()-1);
}
m = DOUBLE_WILDCARD_PATTERN.matcher(token);
if (m.find()) {
StringBuffer buf = new StringBuffer();
do {
ConstrainedProperty prop = constraints[paramIndex++];
String propName = prop.getPropertyName();
Object value = paramValues.get(propName);
usedParams.add(propName);
if (value == null && !prop.isNullable()) {
throw new UrlMappingException("Unable to create URL for mapping [" + this +
"] and parameters [" + paramValues + "]. Parameter [" +
prop.getPropertyName() + "] is required, but was not specified!");
}
else if (value == null) {
m.appendReplacement(buf, "");
}
else {
m.appendReplacement(buf, Matcher.quoteReplacement(value.toString()));
}
}
while (m.find());
m.appendTail(buf);
try {
String v = buf.toString();
if (v.indexOf(SLASH) > -1 && CAPTURED_DOUBLE_WILDCARD.equals(token)) {
// individually URL encode path segments
if (v.startsWith(SLASH)) {
// get rid of leading slash
v = v.substring(SLASH.length());
}
String[] segs = v.split(SLASH);
for (String segment : segs) {
uri.append(SLASH).append(encode(segment, encoding));
}
}
else if (v.length() > 0) {
// original behavior
uri.append(SLASH).append(encode(v, encoding));
}
else {
// Stop processing tokens once we hit an empty one.
break;
}
}
catch (UnsupportedEncodingException e) {
throw new ControllerExecutionException("Error creating URL for parameters [" +
paramValues + "], problem encoding URL part [" + buf + "]: " + e.getMessage(), e);
}
}
else {
uri.append(SLASH).append(token);
}
}
populateParameterList(paramValues, encoding, uri, usedParams);
if (LOG.isDebugEnabled()) {
LOG.debug("Created reverse URL mapping [" + uri.toString() + "] for parameters [" + paramValues + "]");
}
return uri.toString();
}