8000 Correctly expand {?foo} to foo=bar rather than just bar. Support · robccan/google-http-java-client@9fa68d9 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9fa68d9

Browse files
jroitgrundejona86
authored andcommitted
Correctly expand {?foo} to foo=bar rather than just bar. Support
{multiple,variables}. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=113932917
1 parent 0c9c2f0 commit 9fa68d9

File tree

2 files changed

+125
-75
lines changed

2 files changed

+125
-75
lines changed

google-http-client/src/main/java/com/google/api/client/http/UriTemplate.java

Lines changed: 95 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@
1919
import com.google.api.client.util.Preconditions;
2020
import com.google.api.client.util.Types;
2121
import com.google.api.client.util.escape.CharEscapers;
22+
import com.google.common.base.Splitter;
23+
import com.google.common.collect.ImmutableList;
2224

2325
import java.util.HashMap;
2426
import java.util.Iterator;
2527
import java.util.LinkedHashMap;
28+
import java.util.ListIterator;
2629
import java.util.Map;
2730

2831
/**
@@ -37,39 +40,40 @@
3740
* keys := [("semi", ";"),("dot", "."),("comma", ",")]
3841
*
3942
* 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
7377
*
7478
* @since 1.6
7579
* @author Ravi Mistry
@@ -294,52 +298,71 @@ public static String expand(String pathUri, Object parameters,
294298
}
295299
pathBuf.append(pathUri.substring(cur, next));
296300
int close = pathUri.indexOf('}', next + 2);
297-
String template = pathUri.substring(next + 1, close);
298301
cur = close + 1;
299302

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);
311321

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;
329326
}
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);
338353
} 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+
}
340363
}
364+
pathBuf.append(value);
341365
}
342-
pathBuf.append(value);
343366
}
344367
if (addUnusedParamsAsQueryParams) {
345368
// Add the parameters remaining in the variableMap as query parameters.
@@ -367,7 +390,6 @@ private static String getListPropertyValue(String varName, Iterator<?> iterator,
367390
return "";
368391
}
369392
StringBuilder retBuf = new StringBuilder();
370-
retBuf.append(compositeOutput.getOutputPrefix());
371393
String joiner;
372394
if (containsExplodeModifier) {
373395
joiner = compositeOutput.getExplodeJoiner();
@@ -410,7 +432,6 @@ private static String getMapPropertyValue(String varName, Map<String, Object> ma
410432
return "";
411433
}
412434
StringBuilder retBuf = new StringBuilder();
413-
retBuf.append(compositeOutput.getOutputPrefix());
414435
String joiner;
415436
String mapElementsJoiner;
416437
if (containsExplodeModifier) {

google-http-client/src/test/java/com/google/api/client/http/UriTemplateTest.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ public void testExpandTemplates_mixedBagParameters() {
238238
requestMap.put("unused2", "unused=param");
239239
assertEquals(
240240
"foo/xyz/red/green/blue&iterable=red&iterable=green&iterable=blue&map=semi,%3B,dot,.,comma"
241-
+ ",%2CONE?unused1=unused%20param&unused2=unused%3Dparam",
241+
+ ",%2C&enum=ONE?unused1=unused%20param&unused2=unused%3Dparam",
242242
UriTemplate.expand("foo/{abc}{/iterator*}{&iterable*}{&map}{&enum}", requestMap, true));
243243
// Assert the map has not changed.
244244
assertEquals(7, requestMap.size());
@@ -275,4 +275,33 @@ public void testExpandNonReservedNonComposite() {
275275
assertEquals("foo/xyz/bar/a/b?c",
276276
UriTemplate.expand("foo/{abc}/bar/{+def}", requestMap, false));
277277
}
278+
279+
public void testExpandSeveralTemplates() {
280+
SortedMap<String, Object> map = Maps.newTreeMap();
281+
map.put("id", "a");
282+
map.put("uid", "b");
283+
284+
assertEquals("?id=a&uid=b", UriTemplate.expand("{?id,uid}", map, false));
285+
}
286+
287+
public void testExpandSeveralTemplatesUnusedParameterInMiddle() {
288+
SortedMap<String, Object> map = Maps.newTreeMap();
289+
map.put("id", "a");
290+
map.put("uid", "b");
291+
292+
assertEquals("?id=a&uid=b", UriTemplate.expand("{?id,foo,bar,uid}", map, false));
293+
}
294+
295+
public void testExpandSeveralTemplatesFirstParameterUnused() {
296+
SortedMap<String, Object> map = Maps.newTreeMap();
297+
map.put("id", "a");
298+
map.put("uid", "b");
299+
300+
assertEquals("?id=a&uid=b", UriTemplate.expand("{?foo,id,uid}", map, false));
301+
}
302+
303+
public void testExpandSeveralTemplatesNoParametersUsed() {
304+
SortedMap<String, Object> map = Maps.newTreeMap();
305+
assertEquals("", UriTemplate.expand("{?id,uid}", map, false));
306+
}
278307
}

0 commit comments

Comments
 (0)
0