Skip to content

Commit 3d322f3

Browse files
author
adriancole
committed
Skip query template parameters when corresponding java arg is null
1 parent d1650f9 commit 3d322f3

4 files changed

Lines changed: 66 additions & 6 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
### Version 4.2/3.3
22
* Document and enforce JAX-RS annotation processing from server POV
3+
* Skip query template parameters when corresponding java arg is null
34

45
### Version 4.1/3.2
56
* update to dagger 1.1

feign-core/src/main/java/feign/RequestTemplate.java

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Arrays;
2424
import java.util.Collection;
2525
import java.util.Collections;
26+
import java.util.Iterator;
2627
import java.util.LinkedHashMap;
2728
import java.util.List;
2829
import java.util.Map;
@@ -98,9 +99,7 @@ public RequestTemplate resolve(Map<String, ?> unencoded) {
9899
for (Entry<String, ?> entry : unencoded.entrySet()) {
99100
encoded.put(entry.getKey(), urlEncode(String.valueOf(entry.getValue())));
100101
}
101-
String queryLine = expand(queryLine(), encoded);
102-
queries.clear();
103-
pullAnyQueriesOutOfUrl(new StringBuilder(queryLine));
102+
replaceQueryValues(encoded);
104103
String resolvedUrl = expand(url.toString(), encoded).replace("%2F", "/");
105104
url = new StringBuilder(resolvedUrl);
106105

@@ -505,6 +504,37 @@ private static void putKV(String stringToParse, Map<String, Collection<String>>
505504
return request().toString();
506505
}
507506

507+
/**
508+
* Replaces query values which are templated with corresponding values from the {@code unencoded} map.
509+
* Any unresolved queries are removed.
510+
*/
511+
public void replaceQueryValues(Map<String, ?> unencoded) {
512+
Iterator<Entry<String, Collection<String>>> iterator = queries.entrySet().iterator();
513+
while (iterator.hasNext()) {
514+
Entry<String, Collection<String>> entry = iterator.next();
515+
if (entry.getValue() == null) {
516+
continue;
517+
}
518+
Collection<String> values = new ArrayList<String>();
519+
for (String value : entry.getValue()) {
520+
if (value.indexOf('{') == 0 && value.indexOf('}') == value.length() - 1) {
521+
Object variableValue = unencoded.get(value.substring(1, value.length() - 1));
522+
// only add non-null expressions
523+
if (variableValue != null) {
524+
values.add(String.valueOf(variableValue));
525+
}
526+
} else {
527+
values.add(value);
528+
}
529+
}
530+
if (values.isEmpty()) {
531+
iterator.remove();
532+
} else {
533+
entry.setValue(values);
534+
}
535+
}
536+
}
537+
508538
public String queryLine() {
509539
if (queries.isEmpty())
510540
return "";
@@ -524,6 +554,5 @@ public String queryLine() {
524554
return queryBuilder.insert(0, '?').toString();
525555
}
526556

527-
528557
private static final long serialVersionUID = 1L;
529558
}

feign-core/src/test/java/feign/RequestTemplateTest.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import com.google.common.collect.ImmutableList;
1919
import com.google.common.collect.ImmutableListMultimap;
2020
import com.google.common.collect.ImmutableMap;
21-
2221
import org.testng.annotations.Test;
2322

2423
import static feign.RequestTemplate.expand;
@@ -133,4 +132,35 @@ public class RequestTemplateTest {
133132
+ "\n" //
134133
+ "{\"customer_name\": \"netflix\", \"user_name\": \"denominator\", \"password\": \"password\"}");
135134
}
135+
136+
@Test public void skipUnresolvedQueries() throws Exception {
137+
RequestTemplate template = new RequestTemplate().method("GET")//
138+
.append("/domains/{domainId}/records")//
139+
.query("optional", "{optional}")//
140+
.query("name", "{nameVariable}");
141+
142+
template = template.resolve(ImmutableMap.<String, Object>builder()//
143+
.put("domainId", 1001)//
144+
.put("nameVariable", "denominator.io")//
145+
.build()
146+
);
147+
148+
assertEquals(template.toString(), ""//
149+
+ "GET /domains/1001/records?name=denominator.io HTTP/1.1\n");
150+
}
151+
152+
@Test public void allQueriesUnresolvable() throws Exception {
153+
RequestTemplate template = new RequestTemplate().method("GET")//
154+
.append("/domains/{domainId}/records")//
155+
.query("optional", "{optional}")//
156+
.query("optional2", "{optional2}");
157+
158+
template = template.resolve(ImmutableMap.<String, Object>builder()//
159+
.put("domainId", 1001)//
160+
.build()
161+
);
162+
163+
assertEquals(template.toString(), ""//
164+
+ "GET /domains/1001/records HTTP/1.1\n");
165+
}
136166
}

feign-jaxrs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Adds the first value as the `Content-Type` header.
3030
#### `@PathParam`
3131
Links the value of the corresponding parameter to a template variable declared in the path.
3232
#### `@QueryParam`
33-
Links the value of the corresponding parameter to a query parameter.
33+
Links the value of the corresponding parameter to a query parameter. When invoked, null will skip the query param.
3434
#### `@HeaderParam`
3535
Links the value of the corresponding parameter to a header.
3636
#### `@FormParam`

0 commit comments

Comments
 (0)