diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java
index 8c6236ba038..326b13a41b3 100644
--- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java
+++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java
@@ -176,6 +176,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
if ("feign".equals(getLibrary())) {
additionalProperties.put("jackson", "true");
supportingFiles.add(new SupportingFile("ParamExpander.mustache", invokerFolder, "ParamExpander.java"));
+ supportingFiles.add(new SupportingFile("EncodingUtils.mustache", invokerFolder, "EncodingUtils.java"));
} else if ("okhttp-gson".equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) {
// the "okhttp-gson" library template requires "ApiCallback.mustache" for async call
supportingFiles.add(new SupportingFile("ApiCallback.mustache", invokerFolder, "ApiCallback.java"));
diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/EncodingUtils.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/EncodingUtils.mustache
new file mode 100644
index 00000000000..6f43e1c3c2a
--- /dev/null
+++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/EncodingUtils.mustache
@@ -0,0 +1,86 @@
+package {{invokerPackage}};
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+* Utilities to support Swagger encoding formats in Feign.
+*/
+public final class EncodingUtils {
+
+ /**
+ * Private constructor. Do not construct this class.
+ */
+ private EncodingUtils() {}
+
+ /**
+ *
Encodes a collection of query parameters according to the Swagger
+ * collection format.
+ *
+ * Of the various collection formats defined by Swagger ("csv", "tsv",
+ * etc), Feign only natively supports "multi". This utility generates the
+ * other format types so it will be properly processed by Feign.
+ *
+ * Note, as part of reformatting, it URL encodes the parameters as
+ * well.
+ * @param parameters The collection object to be formatted. This object will
+ * not be changed.
+ * @param collectionFormat The Swagger collection format (eg, "csv", "tsv",
+ * "pipes"). See the
+ *
+ * Swagger Spec for more details.
+ * @return An object that will be correctly formatted by Feign.
+ */
+ public static Object encodeCollection(Collection> parameters,
+ String collectionFormat) {
+ if (parameters == null) {
+ return parameters;
+ }
+ List stringValues = new ArrayList<>(parameters.size());
+ for (Object parameter : parameters) {
+ // ignore null values (same behavior as Feign)
+ if (parameter != null) {
+ stringValues.add(encode(parameter));
+ }
+ }
+ // Feign natively handles single-element lists and the "multi" format.
+ if (stringValues.size() < 2 || "multi".equals(collectionFormat)) {
+ return stringValues;
+ }
+ // Otherwise return a formatted String
+ String[] stringArray = stringValues.toArray(new String[0]);
+ switch (collectionFormat) {
+ case "csv":
+ default:
+ return StringUtil.join(stringArray, ",");
+ case "ssv":
+ return StringUtil.join(stringArray, " ");
+ case "tsv":
+ return StringUtil.join(stringArray, "\t");
+ case "pipes":
+ return StringUtil.join(stringArray, "|");
+ }
+ }
+
+ /**
+ * URL encode a single query parameter.
+ * @param parameter The query parameter to encode. This object will not be
+ * changed.
+ * @return The URL encoded string representation of the parameter. If the
+ * parameter is null, returns null.
+ */
+ public static String encode(Object parameter) {
+ if (parameter == null) {
+ return null;
+ }
+ try {
+ return URLEncoder.encode(parameter.toString(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // Should never happen, UTF-8 is always supported
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache
index 6aadf2305d1..67a772a8772 100644
--- a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache
+++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/api.mustache
@@ -1,6 +1,7 @@
package {{package}};
import {{invokerPackage}}.ApiClient;
+import {{invokerPackage}}.EncodingUtils;
{{#legacyDates}}
import {{invokerPackage}}.ParamExpander;
{{/legacyDates}}
@@ -71,7 +72,7 @@ public interface {{classname}} extends ApiClient.Api {
"{{baseName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{#hasMore}},
{{/hasMore}}{{/headerParams}}
})
- {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}}({{#allParams}}{{^isQueryParam}}{{^isBodyParam}}{{^legacyDates}}@Param("{{paramName}}") {{/legacyDates}}{{#legacyDates}}@Param(value="{{paramName}}", expander=ParamExpander.class) {{/legacyDates}}{{/isBodyParam}}{{{dataType}}} {{paramName}}, {{/isQueryParam}}{{/allParams}}@QueryMap Map queryParams);
+ {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{nickname}}({{#allParams}}{{^isQueryParam}}{{^isBodyParam}}{{^legacyDates}}@Param("{{paramName}}") {{/legacyDates}}{{#legacyDates}}@Param(value="{{paramName}}", expander=ParamExpander.class) {{/legacyDates}}{{/isBodyParam}}{{{dataType}}} {{paramName}}, {{/isQueryParam}}{{/allParams}}@QueryMap(encoded=true) Map queryParams);
/**
* A convenience class for generating query parameters for the
@@ -80,7 +81,12 @@ public interface {{classname}} extends ApiClient.Api {
public static class {{operationIdCamelCase}}QueryParams extends HashMap {
{{#queryParams}}
public {{operationIdCamelCase}}QueryParams {{paramName}}(final {{{dataType}}} value) {
- put("{{baseName}}", value);
+ {{#collectionFormat}}
+ put("{{baseName}}", EncodingUtils.encodeCollection(value, "{{collectionFormat}}"));
+ {{/collectionFormat}}
+ {{^collectionFormat}}
+ put("{{baseName}}", EncodingUtils.encode(value));
+ {{/collectionFormat}}
return this;
}
{{/queryParams}}
diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/pom.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/pom.mustache
index d823f258557..c7d253ad685 100644
--- a/modules/swagger-codegen/src/main/resources/Java/libraries/feign/pom.mustache
+++ b/modules/swagger-codegen/src/main/resources/Java/libraries/feign/pom.mustache
@@ -246,6 +246,18 @@
${junit-version}
test
+
+ com.squareup.okhttp3
+ mockwebserver
+ 3.6.0
+ test
+
+
+ org.assertj
+ assertj-core
+ 1.7.1
+ test
+
{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}
diff --git a/samples/client/petstore/java/feign/pom.xml b/samples/client/petstore/java/feign/pom.xml
index 73a08a6c53c..d21f1775565 100644
--- a/samples/client/petstore/java/feign/pom.xml
+++ b/samples/client/petstore/java/feign/pom.xml
@@ -230,6 +230,18 @@
${junit-version}
test
+
+ com.squareup.okhttp3
+ mockwebserver
+ 3.6.0
+ test
+
+
+ org.assertj
+ assertj-core
+ 1.7.1
+ test
+
1.7
diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/EncodingUtils.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/EncodingUtils.java
new file mode 100644
index 00000000000..c474fc62187
--- /dev/null
+++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/EncodingUtils.java
@@ -0,0 +1,86 @@
+package io.swagger.client;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+* Utilities to support Swagger encoding formats in Feign.
+*/
+public final class EncodingUtils {
+
+ /**
+ * Private constructor. Do not construct this class.
+ */
+ private EncodingUtils() {}
+
+ /**
+ * Encodes a collection of query parameters according to the Swagger
+ * collection format.
+ *
+ * Of the various collection formats defined by Swagger ("csv", "tsv",
+ * etc), Feign only natively supports "multi". This utility generates the
+ * other format types so it will be properly processed by Feign.
+ *
+ * Note, as part of reformatting, it URL encodes the parameters as
+ * well.
+ * @param parameters The collection object to be formatted. This object will
+ * not be changed.
+ * @param collectionFormat The Swagger collection format (eg, "csv", "tsv",
+ * "pipes"). See the
+ *
+ * Swagger Spec for more details.
+ * @return An object that will be correctly formatted by Feign.
+ */
+ public static Object encodeCollection(Collection> parameters,
+ String collectionFormat) {
+ if (parameters == null) {
+ return parameters;
+ }
+ List stringValues = new ArrayList<>(parameters.size());
+ for (Object parameter : parameters) {
+ // ignore null values (same behavior as Feign)
+ if (parameter != null) {
+ stringValues.add(encode(parameter));
+ }
+ }
+ // Feign natively handles single-element lists and the "multi" format.
+ if (stringValues.size() < 2 || "multi".equals(collectionFormat)) {
+ return stringValues;
+ }
+ // Otherwise return a formatted String
+ String[] stringArray = stringValues.toArray(new String[0]);
+ switch (collectionFormat) {
+ case "csv":
+ default:
+ return StringUtil.join(stringArray, ",");
+ case "ssv":
+ return StringUtil.join(stringArray, " ");
+ case "tsv":
+ return StringUtil.join(stringArray, "\t");
+ case "pipes":
+ return StringUtil.join(stringArray, "|");
+ }
+ }
+
+ /**
+ * URL encode a single query parameter.
+ * @param parameter The query parameter to encode. This object will not be
+ * changed.
+ * @return The URL encoded string representation of the parameter. If the
+ * parameter is null, returns null.
+ */
+ public static String encode(Object parameter) {
+ if (parameter == null) {
+ return null;
+ }
+ try {
+ return URLEncoder.encode(parameter.toString(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // Should never happen, UTF-8 is always supported
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/FakeApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/FakeApi.java
index 1c035b3fe38..04b4b05e6bc 100644
--- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/FakeApi.java
+++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/FakeApi.java
@@ -1,6 +1,7 @@
package io.swagger.client.api;
import io.swagger.client.ApiClient;
+import io.swagger.client.EncodingUtils;
import java.math.BigDecimal;
import io.swagger.client.model.Client;
@@ -106,7 +107,7 @@ public interface FakeApi extends ApiClient.Api {
"enum_header_string: {enumHeaderString}"
})
- void testEnumParameters(@Param("enumFormStringArray") List enumFormStringArray, @Param("enumFormString") String enumFormString, @Param("enumHeaderStringArray") List enumHeaderStringArray, @Param("enumHeaderString") String enumHeaderString, @Param("enumQueryDouble") Double enumQueryDouble, @QueryMap Map queryParams);
+ void testEnumParameters(@Param("enumFormStringArray") List enumFormStringArray, @Param("enumFormString") String enumFormString, @Param("enumHeaderStringArray") List enumHeaderStringArray, @Param("enumHeaderString") String enumHeaderString, @Param("enumQueryDouble") Double enumQueryDouble, @QueryMap(encoded=true) Map queryParams);
/**
* A convenience class for generating query parameters for the
@@ -114,15 +115,15 @@ public interface FakeApi extends ApiClient.Api {
*/
public static class TestEnumParametersQueryParams extends HashMap {
public TestEnumParametersQueryParams enumQueryStringArray(final List value) {
- put("enum_query_string_array", value);
+ put("enum_query_string_array", EncodingUtils.encodeCollection(value, "csv"));
return this;
}
public TestEnumParametersQueryParams enumQueryString(final String value) {
- put("enum_query_string", value);
+ put("enum_query_string", EncodingUtils.encode(value));
return this;
}
public TestEnumParametersQueryParams enumQueryInteger(final Integer value) {
- put("enum_query_integer", value);
+ put("enum_query_integer", EncodingUtils.encode(value));
return this;
}
}
diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java
index 48987c67f38..5a6813c6198 100644
--- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java
+++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/PetApi.java
@@ -1,6 +1,7 @@
package io.swagger.client.api;
import io.swagger.client.ApiClient;
+import io.swagger.client.EncodingUtils;
import java.io.File;
import io.swagger.client.model.ModelApiResponse;
@@ -75,7 +76,7 @@ public interface PetApi extends ApiClient.Api {
"Content-Type: application/json",
"Accept: application/json",
})
- List findPetsByStatus(@QueryMap Map queryParams);
+ List findPetsByStatus(@QueryMap(encoded=true) Map queryParams);
/**
* A convenience class for generating query parameters for the
@@ -83,7 +84,7 @@ public interface PetApi extends ApiClient.Api {
*/
public static class FindPetsByStatusQueryParams extends HashMap {
public FindPetsByStatusQueryParams status(final List value) {
- put("status", value);
+ put("status", EncodingUtils.encodeCollection(value, "csv"));
return this;
}
}
@@ -121,7 +122,7 @@ public interface PetApi extends ApiClient.Api {
"Content-Type: application/json",
"Accept: application/json",
})
- List findPetsByTags(@QueryMap Map queryParams);
+ List findPetsByTags(@QueryMap(encoded=true) Map queryParams);
/**
* A convenience class for generating query parameters for the
@@ -129,7 +130,7 @@ public interface PetApi extends ApiClient.Api {
*/
public static class FindPetsByTagsQueryParams extends HashMap {
public FindPetsByTagsQueryParams tags(final List value) {
- put("tags", value);
+ put("tags", EncodingUtils.encodeCollection(value, "csv"));
return this;
}
}
diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java
index 9e1ecddbece..1ad8111d3d6 100644
--- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java
+++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/StoreApi.java
@@ -1,6 +1,7 @@
package io.swagger.client.api;
import io.swagger.client.ApiClient;
+import io.swagger.client.EncodingUtils;
import io.swagger.client.model.Order;
diff --git a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java
index c271b9deda8..e85fca41f8b 100644
--- a/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java
+++ b/samples/client/petstore/java/feign/src/main/java/io/swagger/client/api/UserApi.java
@@ -1,6 +1,7 @@
package io.swagger.client.api;
import io.swagger.client.ApiClient;
+import io.swagger.client.EncodingUtils;
import io.swagger.client.model.User;
@@ -110,7 +111,7 @@ public interface UserApi extends ApiClient.Api {
"Content-Type: application/json",
"Accept: application/json",
})
- String loginUser(@QueryMap Map queryParams);
+ String loginUser(@QueryMap(encoded=true) Map queryParams);
/**
* A convenience class for generating query parameters for the
@@ -118,11 +119,11 @@ public interface UserApi extends ApiClient.Api {
*/
public static class LoginUserQueryParams extends HashMap {
public LoginUserQueryParams username(final String value) {
- put("username", value);
+ put("username", EncodingUtils.encode(value));
return this;
}
public LoginUserQueryParams password(final String value) {
- put("password", value);
+ put("password", EncodingUtils.encode(value));
return this;
}
}
diff --git a/samples/client/petstore/java/feign/src/test/java/io/swagger/client/api/PetApiTest.java b/samples/client/petstore/java/feign/src/test/java/io/swagger/client/api/PetApiTest.java
index 4a65cc4d176..c27524de1f6 100644
--- a/samples/client/petstore/java/feign/src/test/java/io/swagger/client/api/PetApiTest.java
+++ b/samples/client/petstore/java/feign/src/test/java/io/swagger/client/api/PetApiTest.java
@@ -13,17 +13,25 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
import org.junit.*;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
public class PetApiTest {
- private ApiClient apiClient;
- private PetApi api;
+ ApiClient apiClient;
+ PetApi api;
+ MockWebServer localServer;
+ ApiClient localClient;
@Before
public void setup() {
apiClient = new ApiClient();
api = apiClient.buildClient(PetApi.class);
+ localServer = new MockWebServer();
+ localClient = new ApiClient();
}
@Test
@@ -211,6 +219,20 @@ public class PetApiTest {
assertTrue(pet1.hashCode() == pet1.hashCode());
}
+ @Test
+ public void testCSVDelimitedArray() throws Exception {
+ localServer.enqueue(new MockResponse().setBody("[{\"id\":5,\"name\":\"rocky\"}]"));
+ localServer.start();
+ PetApi api = localClient.setBasePath(localServer.url("/").toString()).buildClient(PetApi.class);
+ PetApi.FindPetsByTagsQueryParams queryParams = new PetApi.FindPetsByTagsQueryParams()
+ .tags(Arrays.asList("friendly","energetic"));
+ List pets = api.findPetsByTags(queryParams);
+ assertNotNull(pets);
+ RecordedRequest request = localServer.takeRequest();
+ assertThat(request.getPath()).contains("tags=friendly,energetic");
+ localServer.shutdown();
+ }
+
private Pet createRandomPet() {
Pet pet = new Pet();
pet.setId(TestUtils.nextId());