1313 */
1414package feign .template ;
1515
16- import feign .CollectionFormat ;
17- import feign .Util ;
1816import java .nio .charset .Charset ;
17+ import java .nio .charset .StandardCharsets ;
1918import java .util .ArrayList ;
2019import java .util .Arrays ;
2120import java .util .Collection ;
22- import java .util .Iterator ;
21+ import java .util .Collections ;
2322import java .util .List ;
2423import java .util .Map ;
25- import java .util .Objects ;
24+ import java .util .concurrent . CopyOnWriteArrayList ;
2625import java .util .stream .Collectors ;
2726import java .util .stream .StreamSupport ;
27+ import feign .CollectionFormat ;
28+ import feign .Util ;
29+ import feign .template .Template .EncodingOptions ;
30+ import feign .template .Template .ExpansionOptions ;
2831
2932/**
3033 * Template for a Query String parameter.
3134 */
32- public final class QueryTemplate extends Template {
35+ public final class QueryTemplate {
3336
3437 private static final String UNDEF = "undef" ;
35- private List <String > values ;
38+ private List <Template > values ;
3639 private final Template name ;
3740 private final CollectionFormat collectionFormat ;
3841 private boolean pure = false ;
@@ -75,16 +78,7 @@ public static QueryTemplate create(String name,
7578 .filter (Util ::isNotBlank )
7679 .collect (Collectors .toList ());
7780
78- StringBuilder template = new StringBuilder ();
79- Iterator <String > iterator = remaining .iterator ();
80- while (iterator .hasNext ()) {
81- template .append (iterator .next ());
82- if (iterator .hasNext ()) {
83- template .append (COLLECTION_DELIMITER );
84- }
85- }
86-
87- return new QueryTemplate (template .toString (), name , remaining , charset , collectionFormat );
81+ return new QueryTemplate (name , remaining , charset , collectionFormat );
8882 }
8983
9084 /**
@@ -101,31 +95,43 @@ public static QueryTemplate append(QueryTemplate queryTemplate,
10195 queryValues .addAll (StreamSupport .stream (values .spliterator (), false )
10296 .filter (Util ::isNotBlank )
10397 .collect (Collectors .toList ()));
104- return create (queryTemplate .getName (), queryValues , queryTemplate . getCharset () ,
98+ return create (queryTemplate .getName (), queryValues , StandardCharsets . UTF_8 ,
10599 collectionFormat );
106100 }
107101
108102 /**
109103 * Create a new Query Template.
110104 *
111- * @param template for the Query String.
112105 * @param name of the query parameter.
113106 * @param values for the parameter.
114107 * @param collectionFormat to use.
115108 */
116109 private QueryTemplate (
117- String template ,
118110 String name ,
119111 Iterable <String > values ,
120112 Charset charset ,
121113 CollectionFormat collectionFormat ) {
122- super ( template , ExpansionOptions . REQUIRED , EncodingOptions . REQUIRED , true , charset );
114+ this . values = new CopyOnWriteArrayList <>( );
123115 this .name = new Template (name , ExpansionOptions .ALLOW_UNRESOLVED , EncodingOptions .REQUIRED ,
124116 false , charset );
125117 this .collectionFormat = collectionFormat ;
126- this .values = StreamSupport .stream (values .spliterator (), false )
127- .filter (Util ::isNotBlank )
128- .collect (Collectors .toList ());
118+
119+ /* parse each value into a template chunk for resolution later */
120+ for (String value : values ) {
121+ if (value .isEmpty ()) {
122+ /* skip */
123+ continue ;
124+ }
125+
126+ this .values .add (
127+ new Template (
128+ value ,
129+ ExpansionOptions .REQUIRED ,
130+ EncodingOptions .REQUIRED ,
131+ false ,
132+ charset ));
133+ }
134+
129135 if (this .values .isEmpty ()) {
130136 /* in this case, we have a pure parameter */
131137 this .pure = true ;
@@ -134,7 +140,17 @@ private QueryTemplate(
134140 }
135141
136142 public List <String > getValues () {
137- return values ;
143+ return Collections .unmodifiableList (this .values .stream ()
144+ .map (Template ::toString )
145+ .collect (Collectors .toList ()));
146+ }
147+
148+ public List <String > getVariables () {
149+ List <String > variables = new ArrayList <>();
150+ for (Template template : this .values ) {
151+ variables .addAll (template .getVariables ());
152+ }
153+ return Collections .unmodifiableList (variables );
138154 }
139155
140156 public String getName () {
@@ -143,7 +159,7 @@ public String getName() {
143159
144160 @ Override
145161 public String toString () {
146- return this .queryString (this .name .toString (), super . toString ());
162+ return this .queryString (this .name .toString (), this . getValues ());
147163 }
148164
149165 /**
@@ -153,39 +169,43 @@ public String toString() {
153169 * @param variables containing the values for expansion.
154170 * @return the expanded template.
155171 */
156- @ Override
157172 public String expand (Map <String , ?> variables ) {
158173 String name = this .name .expand (variables );
159- return this .queryString (name , super .expand (variables ));
160- }
161174
162- @ Override
163- protected String resolveExpression (Expression expression , Map <String , ?> variables ) {
164- if (variables .containsKey (expression .getName ())) {
165- if (variables .get (expression .getName ()) == null ) {
166- /* explicit undefined */
167- return UNDEF ;
175+ if (this .pure ) {
176+ return name ;
177+ }
178+
179+ List <String > expanded = new ArrayList <>();
180+ for (Template template : this .values ) {
181+ String result = template .expand (variables );
182+ if (result == null ) {
183+ continue ;
184+ }
185+
186+ /*
187+ * check for an iterable result, and if one is there, we need to split it into individual
188+ * values
189+ */
190+ if (result .contains ("," )) {
191+ /* we need to split it */
192+ expanded .addAll (Arrays .asList (result .split ("," )));
193+ } else {
194+ expanded .add (result );
168195 }
169- return super .resolveExpression (expression , variables );
170196 }
171197
172- /* mark the variable as undefined */
173- return UNDEF ;
198+ return this .queryString (name , Collections .unmodifiableList (expanded ));
174199 }
175200
176- private String queryString (String name , String values ) {
201+
202+ private String queryString (String name , List <String > values ) {
177203 if (this .pure ) {
178204 return name ;
179205 }
180206
181- /* covert the comma separated values into a value query string */
182- List <String > resolved = Arrays .stream (values .split (COLLECTION_DELIMITER ))
183- .filter (Objects ::nonNull )
184- .filter (s -> !UNDEF .equalsIgnoreCase (s ))
185- .collect (Collectors .toList ());
186-
187- if (!resolved .isEmpty ()) {
188- return this .collectionFormat .join (name , resolved , this .getCharset ()).toString ();
207+ if (!values .isEmpty ()) {
208+ return this .collectionFormat .join (name , values , StandardCharsets .UTF_8 ).toString ();
189209 }
190210
191211 /* nothing to return, all values are unresolved */
0 commit comments