|
19 | 19 | import com.google.api.client.util.Preconditions;
|
20 | 20 | import com.google.api.client.util.Types;
|
21 | 21 | import com.google.api.client.util.escape.CharEscapers;
|
| 22 | +import com.google.common.base.Splitter; |
| 23 | +import com.google.common.collect.ImmutableList; |
22 | 24 |
|
23 | 25 | import java.util.HashMap;
|
24 | 26 | import java.util.Iterator;
|
25 | 27 | import java.util.LinkedHashMap;
|
| 28 | +import java.util.ListIterator; |
26 | 29 | import java.util.Map;
|
27 | 30 |
|
28 | 31 | /**
|
|
37 | 40 | * keys := [("semi", ";"),("dot", "."),("comma", ",")]
|
38 | 41 | *
|
39 | 42 | * The following templates results in the following expansions:
|
40 |
| - * {var} -> value |
41 |
| - * {list} -> red,green,blue |
42 |
| - * {list*} -> red,green,blue |
43 |
| - * {keys} -> semi,%3B,dot,.,comma,%2C |
44 |
| - * {keys*} -> semi=%3B,dot=.,comma=%2C |
45 |
| - * {+list} -> red,green,blue |
46 |
| - * {+list*} -> red,green,blue |
47 |
| - * {+keys} -> semi,;,dot,.,comma,, |
48 |
| - * {+keys*} -> semi=;,dot=.,comma=, |
49 |
| - * {#list} -> #red,green,blue |
50 |
| - * {#list*} -> #red,green,blue |
51 |
| - * {#keys} -> #semi,;,dot,.,comma,, |
52 |
| - * {#keys*} -> #semi=;,dot=.,comma=, |
53 |
| - * X{.list} -> X.red,green,blue |
54 |
| - * X{.list*} -> X.red.green.blue |
55 |
| - * X{.keys} -> X.semi,%3B,dot,.,comma,%2C |
56 |
| - * X{.keys*} -> X.semi=%3B.dot=..comma=%2C |
57 |
| - * {/list} -> /red,green,blue |
58 |
| - * {/list*} -> /red/green/blue |
59 |
| - * {/keys} -> /semi,%3B,dot,.,comma,%2C |
60 |
| - * {/keys*} -> /semi=%3B/dot=./comma=%2C |
61 |
| - * {;list} -> ;list=red,green,blue |
62 |
| - * {;list*} -> ;list=red;list=green;list=blue |
63 |
| - * {;keys} -> ;keys=semi,%3B,dot,.,comma,%2C |
64 |
| - * {;keys*} -> ;semi=%3B;dot=.;comma=%2C |
65 |
| - * {?list} -> ?list=red,green,blue |
66 |
| - * {?list*} -> ?list=red&list=green&list=blue |
67 |
| - * {?keys} -> ?keys=semi,%3B,dot,.,comma,%2C |
68 |
| - * {?keys*} -> ?semi=%3B&dot=.&comma=%2C |
69 |
| - * {&list} -> &list=red,green,blue |
70 |
| - * {&list*} -> &list=red&list=green&list=blue |
71 |
| - * {&keys} -> &keys=semi,%3B,dot,.,comma,%2C |
72 |
| - * {&keys*} -> &semi=%3B&dot=.&comma=%2C |
| 43 | + * {var} -> value |
| 44 | + * {list} -> red,green,blue |
| 45 | + * {list*} -> red,green,blue |
| 46 | + * {keys} -> semi,%3B,dot,.,comma,%2C |
| 47 | + * {keys*} -> semi=%3B,dot=.,comma=%2C |
| 48 | + * {+list} -> red,green,blue |
| 49 | + * {+list*} -> red,green,blue |
| 50 | + * {+keys} -> semi,;,dot,.,comma,, |
| 51 | + * {+keys*} -> semi=;,dot=.,comma=, |
| 52 | + * {#list} -> #red,green,blue |
| 53 | + * {#list*} -> #red,green,blue |
| 54 | + * {#keys} -> #semi,;,dot,.,comma,, |
| 55 | + * {#keys*} -> #semi=;,dot=.,comma=, |
| 56 | + * X{.list} -> X.red,green,blue |
| 57 | + * X{.list*} -> X.red.green.blue |
| 58 | + * X{.keys} -> X.semi,%3B,dot,.,comma,%2C |
| 59 | + * X{.keys*} -> X.semi=%3B.dot=..comma=%2C |
| 60 | + * {/list} -> /red,green,blue |
| 61 | + * {/list*} -> /red/green/blue |
| 62 | + * {/keys} -> /semi,%3B,dot,.,comma,%2C |
| 63 | + * {/keys*} -> /semi=%3B/dot=./comma=%2C |
| 64 | + * {;list} -> ;list=red,green,blue |
| 65 | + * {;list*} -> ;list=red;list=green;list=blue |
| 66 | + * {;keys} -> ;keys=semi,%3B,dot,.,comma,%2C |
| 67 | + * {;keys*} -> ;semi=%3B;dot=.;comma=%2C |
| 68 | + * {?list} -> ?list=red,green,blue |
| 69 | + * {?list*} -> ?list=red&list=green&list=blue |
| 70 | + * {?keys} -> ?keys=semi,%3B,dot,.,comma,%2C |
| 71 | + * {?keys*} -> ?semi=%3B&dot=.&comma=%2C |
| 72 | + * {&list} -> &list=red,green,blue |
| 73 | + * {&list*} -> &list=red&list=green&list=blue |
| 74 | + * {&keys} -> &keys=semi,%3B,dot,.,comma,%2C |
| 75 | + * {&keys*} -> &semi=%3B&dot=.&comma=%2C |
| 76 | + * {?var,list} -> ?var=value&list=red,green,blue |
73 | 77 | *
|
74 | 78 | * @since 1.6
|
75 | 79 | * @author Ravi Mistry
|
@@ -294,52 +298,71 @@ public static String expand(String pathUri, Object parameters,
|
294 | 298 | }
|
295 | 299 | pathBuf.append(pathUri.substring(cur, next));
|
296 | 300 | int close = pathUri.indexOf('}', next + 2);
|
297 |
| - String template = pathUri.substring(next + 1, close); |
298 | 301 | cur = close + 1;
|
299 | 302 |
|
300 |
| - boolean containsExplodeModifier = template.endsWith("*"); |
301 |
| - CompositeOutput compositeOutput = getCompositeOutput(template); |
302 |
| - |
303 |
| - int varNameStartIndex = compositeOutput.getVarNameStartIndex(); |
304 |
| - int varNameEndIndex = template.length(); |
305 |
| - if (containsExplodeModifier) { |
306 |
| - // The expression contains an explode modifier '*' at the end, update end index. |
307 |
| - varNameEndIndex = varNameEndIndex - 1; |
308 |
| - } |
309 |
| - // Now get varName devoid of any prefixes and explode modifiers. |
310 |
| - String varName = template.substring(varNameStartIndex, varNameEndIndex); |
| 303 | + String templates = pathUri.substring(next + 1, close); |
| 304 | + CompositeOutput compositeOutput = getCompositeOutput(templates); |
| 305 | + ListIterator<String> templateIterator = |
| 306 | + ImmutableList.copyOf(Splitter.on(',').split(templates)).listIterator(); |
| 307 | + boolean isFirstParameter = true; |
| 308 | + while (templateIterator.hasNext()) { |
| 309 | + String template = templateIterator.next(); |
| 310 | + boolean containsExplodeModifier = template.endsWith("*"); |
| 311 | + |
| 312 | + int varNameStartIndex = templateIterator.nextIndex() == 1 |
| 313 | + ? compositeOutput.getVarNameStartIndex() : 0; |
| 314 | + int varNameEndIndex = template.length(); |
| 315 | + if (containsExplodeModifier) { |
| 316 | + // The expression contains an explode modifier '*' at the end, update end index. |
| 317 | + varNameEndIndex = varNameEndIndex - 1; |
| 318 | + } |
| 319 | + // Now get varName devoid of any prefixes and explode modifiers. |
| 320 | + String varName = template.substring(varNameStartIndex, varNameEndIndex); |
311 | 321 |
|
312 |
| - Object value = variableMap.remove(varName); |
313 |
| - if (value == null) { |
314 |
| - // The value for this variable is undefined. continue with the next template. |
315 |
| - continue; |
316 |
| - } |
317 |
| - if (value instanceof Iterator<?>) { |
318 |
| - // Get the list property value. |
319 |
| - Iterator<?> iterator = (Iterator<?>) value; |
320 |
| - value = getListPropertyValue(varName, iterator, containsExplodeModifier, compositeOutput); |
321 |
| - } else if (value instanceof Iterable<?> || value.getClass().isArray()) { |
322 |
| - // Get the list property value. |
323 |
| - Iterator<?> iterator = Types.iterableOf(value).iterator(); |
324 |
| - value = getListPropertyValue(varName, iterator, containsExplodeModifier, compositeOutput); |
325 |
| - } else if (value.getClass().isEnum()) { |
326 |
| - String name = FieldInfo.of((Enum<?>) value).getName(); |
327 |
| - if (name != null) { |
328 |
| - value = CharEscapers.escapeUriPath(name); |
| 322 | + Object value = variableMap.remove(varName); |
| 323 | + if (value == null) { |
| 324 | + // The value for this variable is undefined. continue with the next template. |
| 325 | + continue; |
329 | 326 | }
|
330 |
| - } else if (!Data.isValueOfPrimitiveType(value)) { |
331 |
| - // Parse the value as a key/value map. |
332 |
| - Map<String, Object> map = getMap(value); |
333 |
| - value = getMapPropertyValue(varName, map, containsExplodeModifier, compositeOutput); |
334 |
| - } else { |
335 |
| - // For everything else... |
336 |
| - if (compositeOutput.getReservedExpansion()) { |
337 |
| - value = CharEscapers.escapeUriPathWithoutReserved(value.toString()); |
| 327 | + if (!isFirstParameter) { |
| 328 | + pathBuf.append(compositeOutput.getExplodeJoiner()); |
| 329 | + } else { |
| 330 | + pathBuf.append(compositeOutput.getOutputPrefix()); |
| 331 | + isFirstParameter = false; |
| 332 | + } |
| 333 | + if (value instanceof Iterator<?>) { |
| 334 | + // Get the list property value. |
| 335 | + Iterator<?> iterator = (Iterator<?>) value; |
| 336 | + value = getListPropertyValue(varName, iterator, containsExplodeModifier, compositeOutput); |
| 337 | + } else if (value instanceof Iterable<?> || value.getClass().isArray()) { |
| 338 | + // Get the list property value. |
| 339 | + Iterator<?> iterator = Types.iterableOf(value).iterator(); |
| 340 | + value = getListPropertyValue(varName, iterator, containsExplodeModifier, compositeOutput); |
| 341 | + } else if (value.getClass().isEnum()) { |
| 342 | + String name = FieldInfo.of((Enum<?>) value).getName(); |
| 343 | + if (name != null) { |
| 344 | + if (compositeOutput.requiresVarAssignment()) { |
| 345 | + value = String.format("%s=%s", varName, value); |
| 346 | + } |
| 347 | + value = CharEscapers.escapeUriPath(value.toString()); |
| 348 | + } |
| 349 | + } else if (!Data.isValueOfPrimitiveType(value)) { |
| 350 | + // Parse the value as a key/value map. |
| 351 | + Map<String, Object> map = getMap(value); |
| 352 | + value = getMapPropertyValue(varName, map, containsExplodeModifier, compositeOutput); |
338 | 353 | } else {
|
339 |
| - value = CharEscapers.escapeUriPath(value.toString()); |
| 354 | + // For everything else... |
| 355 | + if (compositeOutput.requiresVarAssignment()) { |
| 356 | + value = String.format("%s=%s", varName, value); |
| 357 | + } |
| 358 | + if (compositeOutput.getReservedExpansion()) { |
| 359 | + value = CharEscapers.escapeUriPathWithoutReserved(value.toString()); |
| 360 | + } else { |
| 361 | + value = CharEscapers.escapeUriPath(value.toString()); |
| 362 | + } |
340 | 363 | }
|
| 364 | + pathBuf.append(value); |
341 | 365 | }
|
342 |
| - pathBuf.append(value); |
343 | 366 | }
|
344 | 367 | if (addUnusedParamsAsQueryParams) {
|
345 | 368 | // Add the parameters remaining in the variableMap as query parameters.
|
@@ -367,7 +390,6 @@ private static String getListPropertyValue(String varName, Iterator<?> iterator,
|
367 | 390 | return "";
|
368 | 391 | }
|
369 | 392 | StringBuilder retBuf = new StringBuilder();
|
370 |
| - retBuf.append(compositeOutput.getOutputPrefix()); |
371 | 393 | String joiner;
|
372 | 394 | if (containsExplodeModifier) {
|
373 | 395 | joiner = compositeOutput.getExplodeJoiner();
|
@@ -410,7 +432,6 @@ private static String getMapPropertyValue(String varName, Map<String, Object> ma
|
410 | 432 | return "";
|
411 | 433 | }
|
412 | 434 | StringBuilder retBuf = new StringBuilder();
|
413 |
| - retBuf.append(compositeOutput.getOutputPrefix()); |
414 | 435 | String joiner;
|
415 | 436 | String mapElementsJoiner;
|
416 | 437 | if (containsExplodeModifier) {
|
|
0 commit comments