diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/KotlinClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/KotlinClientCodegen.java index 7e52a1c65541..2df436d195a3 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/KotlinClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/KotlinClientCodegen.java @@ -125,16 +125,16 @@ public class KotlinClientCodegen extends DefaultCodegen implements CodegenConfig typeMapping.put("date-time", "java.time.LocalDateTime"); typeMapping.put("date", "java.time.LocalDateTime"); typeMapping.put("file", "java.io.File"); - typeMapping.put("array", "kotlin.collections.List"); - typeMapping.put("list", "kotlin.collections.List"); + typeMapping.put("array", "kotlin.Array"); + typeMapping.put("list", "kotlin.Array"); typeMapping.put("map", "kotlin.collections.Map"); typeMapping.put("object", "kotlin.Any"); typeMapping.put("binary", "kotlin.Array"); typeMapping.put("Date", "java.time.LocalDateTime"); typeMapping.put("DateTime", "java.time.LocalDateTime"); - instantiationTypes.put("array", "listOf"); - instantiationTypes.put("list", "listOf"); + instantiationTypes.put("array", "arrayOf"); + instantiationTypes.put("list", "arrayOf"); instantiationTypes.put("map", "mapOf"); importMapping = new HashMap(); @@ -241,6 +241,7 @@ public class KotlinClientCodegen extends DefaultCodegen implements CodegenConfig final String infrastructureFolder = (sourceFolder + File.separator + packageName + File.separator + "infrastructure").replace(".", "/"); supportingFiles.add(new SupportingFile("infrastructure/ApiClient.kt.mustache", infrastructureFolder, "ApiClient.kt")); + supportingFiles.add(new SupportingFile("infrastructure/ApiAbstractions.kt.mustache", infrastructureFolder, "ApiAbstractions.kt")); supportingFiles.add(new SupportingFile("infrastructure/ApiInfrastructureResponse.kt.mustache", infrastructureFolder, "ApiInfrastructureResponse.kt")); supportingFiles.add(new SupportingFile("infrastructure/ApplicationDelegates.kt.mustache", infrastructureFolder, "ApplicationDelegates.kt")); supportingFiles.add(new SupportingFile("infrastructure/RequestConfig.kt.mustache", infrastructureFolder, "RequestConfig.kt")); diff --git a/modules/swagger-codegen/src/main/resources/kotlin-client/api.mustache b/modules/swagger-codegen/src/main/resources/kotlin-client/api.mustache index 545cd29e6916..cae4e8cb62b6 100644 --- a/modules/swagger-codegen/src/main/resources/kotlin-client/api.mustache +++ b/modules/swagger-codegen/src/main/resources/kotlin-client/api.mustache @@ -19,7 +19,7 @@ class {{classname}}(basePath: kotlin.String = "{{{basePath}}}") : ApiClient(base @Suppress("UNCHECKED_CAST"){{/returnType}} fun {{operationId}}({{#allParams}}{{paramName}}: {{{dataType}}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) : {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}} { val localVariableBody: kotlin.Any? = {{#hasBodyParam}}{{#bodyParams}}{{paramName}}{{/bodyParams}}{{/hasBodyParam}}{{^hasBodyParam}}{{^hasFormParams}}null{{/hasFormParams}}{{#hasFormParams}}mapOf({{#formParams}}"{{{baseName}}}" to "${{paramName}}"{{#hasMore}}, {{/hasMore}}{{/formParams}}){{/hasFormParams}}{{/hasBodyParam}} - val localVariableQuery: kotlin.collections.Map = {{^hasQueryParams}}mapOf(){{/hasQueryParams}}{{#hasQueryParams}}mapOf({{#queryParams}}"{{paramName}}" to {{#isContainer}}{{paramName}}.joinToString(separator = collectionDelimiter("{{collectionFormat}}")){{/isContainer}}{{^isContainer}}{{paramName}}{{/isContainer}}{{#hasMore}}, {{/hasMore}}{{/queryParams}}){{/hasQueryParams}} + val localVariableQuery: MultiValueMap = {{^hasQueryParams}}mapOf(){{/hasQueryParams}}{{#hasQueryParams}}mapOf({{#queryParams}}"{{paramName}}" to {{#isContainer}}toMultiValue({{paramName}}.toList(), "{{collectionFormat}}"){{/isContainer}}{{^isContainer}}listOf("${{paramName}}"){{/isContainer}}{{#hasMore}}, {{/hasMore}}{{/queryParams}}){{/hasQueryParams}} val localVariableHeaders: kotlin.collections.Map = {{^headerParams}}mapOf({{#hasFormParams}}"Content-Type" to "multipart/form-data"{{/hasFormParams}}){{/headerParams}}{{#headerParams}}mapOf("{{paramName}}" to {{#isContainer}}{{paramName}}.joinToString(separator = collectionDelimiter("{{collectionFormat}}")){{/isContainer}}{{^isContainer}}{{paramName}}{{/isContainer}}){{/headerParams}} val localVariableConfig = RequestConfig( RequestMethod.{{httpMethod}}, @@ -43,13 +43,5 @@ class {{classname}}(basePath: kotlin.String = "{{{basePath}}}") : ApiClient(base } {{/operation}} - - private fun collectionDelimiter(collectionFormat: kotlin.String) = when(collectionFormat) { - "csv" -> "," - "tsv" -> "\t" - "pipes" -> "|" - "ssv" -> " " - else -> "" - } } {{/operations}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/ApiAbstractions.kt.mustache b/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/ApiAbstractions.kt.mustache new file mode 100644 index 000000000000..0a42ce534d3d --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/ApiAbstractions.kt.mustache @@ -0,0 +1,20 @@ +package {{packageName}}.infrastructure + +typealias MultiValueMap = Map> + +fun collectionDelimiter(collectionFormat: String) = when(collectionFormat) { + "csv" -> "," + "tsv" -> "\t" + "pipes" -> "|" + "ssv" -> " " + else -> "" +} + +val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" } + +fun toMultiValue(items: List, collectionFormat: String, map: (item: Any?) -> String = defaultMultiValueConverter): List { + return when(collectionFormat) { + "multi" -> items.map(map) + else -> listOf(items.map(map).joinToString(separator = collectionDelimiter(collectionFormat))) + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/ApiClient.kt.mustache b/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/ApiClient.kt.mustache index 7480a80fce9a..49517bd15927 100644 --- a/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/ApiClient.kt.mustache +++ b/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/ApiClient.kt.mustache @@ -60,7 +60,11 @@ open class ApiClient(val baseUrl: String) { var urlBuilder = httpUrl.newBuilder() .addPathSegments(requestConfig.path.trimStart('/')) - requestConfig.query.forEach { k, v -> urlBuilder = urlBuilder.addQueryParameter(k,v) } + requestConfig.query.forEach { k, v -> + v.forEach { queryValue -> + urlBuilder = urlBuilder.addQueryParameter(k,queryValue) + } + } val url = urlBuilder.build() val headers = requestConfig.headers + defaultHeaders @@ -73,6 +77,7 @@ open class ApiClient(val baseUrl: String) { throw kotlin.IllegalStateException("Missing Accept header. This is required.") } + // TODO: support multiple contentType,accept options here. val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase() val accept = (headers[Accept] as String).substringBefore(";").toLowerCase() diff --git a/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/RequestConfig.kt.mustache b/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/RequestConfig.kt.mustache index 913b42b648ed..58a3d605aa11 100644 --- a/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/RequestConfig.kt.mustache +++ b/modules/swagger-codegen/src/main/resources/kotlin-client/infrastructure/RequestConfig.kt.mustache @@ -5,9 +5,11 @@ package {{packageName}}.infrastructure * NOTE: This object doesn't include 'body' because it * allows for caching of the constructed object * for many request definitions. + * NOTE: Headers is a Map because rfc2616 defines + * multi-valued headers as csv-only. */ data class RequestConfig( val method: RequestMethod, val path: String, val headers: Map = mapOf(), - val query: Map = mapOf()) \ No newline at end of file + val query: Map> = mapOf()) \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/kotlin/KotlinClientCodegenModelTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/kotlin/KotlinClientCodegenModelTest.java index 474806638d67..23bf434bf3fb 100644 --- a/modules/swagger-codegen/src/test/java/io/swagger/codegen/kotlin/KotlinClientCodegenModelTest.java +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/kotlin/KotlinClientCodegenModelTest.java @@ -104,10 +104,10 @@ public class KotlinClientCodegenModelTest { Assert.assertEquals(property.baseName, "examples"); Assert.assertEquals(property.getter, "getExamples"); Assert.assertEquals(property.setter, "setExamples"); - Assert.assertEquals(property.datatype, "kotlin.collections.List"); + Assert.assertEquals(property.datatype, "kotlin.Array"); Assert.assertEquals(property.name, "examples"); Assert.assertEquals(property.defaultValue, "null"); - Assert.assertEquals(property.baseType, "kotlin.collections.List"); + Assert.assertEquals(property.baseType, "kotlin.Array"); Assert.assertEquals(property.containerType, "array"); Assert.assertFalse(property.required); Assert.assertTrue(property.isContainer); diff --git a/samples/client/petstore/kotlin/docs/Pet.md b/samples/client/petstore/kotlin/docs/Pet.md index 73963abeb042..ec7756007379 100644 --- a/samples/client/petstore/kotlin/docs/Pet.md +++ b/samples/client/petstore/kotlin/docs/Pet.md @@ -7,8 +7,8 @@ Name | Type | Description | Notes **id** | **kotlin.Long** | | [optional] **category** | [**Category**](Category.md) | | [optional] **name** | **kotlin.String** | | -**photoUrls** | **kotlin.collections.List<kotlin.String>** | | -**tags** | [**kotlin.collections.List<Tag>**](Tag.md) | | [optional] +**photoUrls** | **kotlin.Array<kotlin.String>** | | +**tags** | [**kotlin.Array<Tag>**](Tag.md) | | [optional] **status** | [**inline**](#StatusEnum) | pet status in the store | [optional] diff --git a/samples/client/petstore/kotlin/docs/PetApi.md b/samples/client/petstore/kotlin/docs/PetApi.md index 39803d4af412..29fb5bd0eeb8 100644 --- a/samples/client/petstore/kotlin/docs/PetApi.md +++ b/samples/client/petstore/kotlin/docs/PetApi.md @@ -110,7 +110,7 @@ null (empty response body) # **findPetsByStatus** -> kotlin.collections.List<Pet> findPetsByStatus(status) +> kotlin.Array<Pet> findPetsByStatus(status) Finds Pets by status @@ -123,9 +123,9 @@ Multiple status values can be provided with comma separated strings //import io.swagger.client.models.* val apiInstance = PetApi() -val status : kotlin.collections.List = // kotlin.collections.List | Status values that need to be considered for filter +val status : kotlin.Array = // kotlin.Array | Status values that need to be considered for filter try { - val result : kotlin.collections.List = apiInstance.findPetsByStatus(status) + val result : kotlin.Array = apiInstance.findPetsByStatus(status) println(result) } catch (e: ClientException) { println("4xx response calling PetApi#findPetsByStatus") @@ -140,11 +140,11 @@ try { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **status** | [**kotlin.collections.List<kotlin.String>**](kotlin.String.md)| Status values that need to be considered for filter | [enum: available, pending, sold] + **status** | [**kotlin.Array<kotlin.String>**](kotlin.String.md)| Status values that need to be considered for filter | [enum: available, pending, sold] ### Return type -[**kotlin.collections.List<Pet>**](Pet.md) +[**kotlin.Array<Pet>**](Pet.md) ### Authorization @@ -157,7 +157,7 @@ Name | Type | Description | Notes # **findPetsByTags** -> kotlin.collections.List<Pet> findPetsByTags(tags) +> kotlin.Array<Pet> findPetsByTags(tags) Finds Pets by tags @@ -170,9 +170,9 @@ Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 //import io.swagger.client.models.* val apiInstance = PetApi() -val tags : kotlin.collections.List = // kotlin.collections.List | Tags to filter by +val tags : kotlin.Array = // kotlin.Array | Tags to filter by try { - val result : kotlin.collections.List = apiInstance.findPetsByTags(tags) + val result : kotlin.Array = apiInstance.findPetsByTags(tags) println(result) } catch (e: ClientException) { println("4xx response calling PetApi#findPetsByTags") @@ -187,11 +187,11 @@ try { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **tags** | [**kotlin.collections.List<kotlin.String>**](kotlin.String.md)| Tags to filter by | + **tags** | [**kotlin.Array<kotlin.String>**](kotlin.String.md)| Tags to filter by | ### Return type -[**kotlin.collections.List<Pet>**](Pet.md) +[**kotlin.Array<Pet>**](Pet.md) ### Authorization diff --git a/samples/client/petstore/kotlin/docs/UserApi.md b/samples/client/petstore/kotlin/docs/UserApi.md index 0974c7f83cb4..d15aae23da39 100644 --- a/samples/client/petstore/kotlin/docs/UserApi.md +++ b/samples/client/petstore/kotlin/docs/UserApi.md @@ -75,7 +75,7 @@ Creates list of users with given input array //import io.swagger.client.models.* val apiInstance = UserApi() -val body : kotlin.collections.List = // kotlin.collections.List | List of user object +val body : kotlin.Array = // kotlin.Array | List of user object try { apiInstance.createUsersWithArrayInput(body) } catch (e: ClientException) { @@ -91,7 +91,7 @@ try { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **body** | [**kotlin.collections.List<User>**](User.md)| List of user object | + **body** | [**kotlin.Array<User>**](User.md)| List of user object | ### Return type @@ -121,7 +121,7 @@ Creates list of users with given input array //import io.swagger.client.models.* val apiInstance = UserApi() -val body : kotlin.collections.List = // kotlin.collections.List | List of user object +val body : kotlin.Array = // kotlin.Array | List of user object try { apiInstance.createUsersWithListInput(body) } catch (e: ClientException) { @@ -137,7 +137,7 @@ try { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **body** | [**kotlin.collections.List<User>**](User.md)| List of user object | + **body** | [**kotlin.Array<User>**](User.md)| List of user object | ### Return type diff --git a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/PetApi.kt b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/PetApi.kt index a01400aa9d97..c716883b3407 100644 --- a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/PetApi.kt +++ b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/PetApi.kt @@ -26,7 +26,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli */ fun addPet(body: Pet) : Unit { val localVariableBody: kotlin.Any? = body - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.POST, @@ -58,7 +58,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli */ fun deletePet(petId: kotlin.Long, apiKey: kotlin.String) : Unit { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf("apiKey" to apiKey) val localVariableConfig = RequestConfig( RequestMethod.DELETE, @@ -85,12 +85,12 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli * Finds Pets by status * Multiple status values can be provided with comma separated strings * @param status Status values that need to be considered for filter - * @return kotlin.collections.List + * @return kotlin.Array */ @Suppress("UNCHECKED_CAST") - fun findPetsByStatus(status: kotlin.collections.List) : kotlin.collections.List { + fun findPetsByStatus(status: kotlin.Array) : kotlin.Array { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf("status" to status.joinToString(separator = collectionDelimiter("csv"))) + val localVariableQuery: MultiValueMap = mapOf("status" to toMultiValue(status.toList(), "csv")) val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.GET, @@ -98,13 +98,13 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli query = localVariableQuery, headers = localVariableHeaders ) - val response = request>( + val response = request>( localVariableConfig, localVariableBody ) return when (response.responseType) { - ResponseType.Success -> (response as Success<*>).data as kotlin.collections.List + ResponseType.Success -> (response as Success<*>).data as kotlin.Array ResponseType.Informational -> TODO() ResponseType.Redirection -> TODO() ResponseType.ClientError -> throw ClientException((response as ClientError<*>).body as? String ?: "Client error") @@ -117,12 +117,12 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli * Finds Pets by tags * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. * @param tags Tags to filter by - * @return kotlin.collections.List + * @return kotlin.Array */ @Suppress("UNCHECKED_CAST") - fun findPetsByTags(tags: kotlin.collections.List) : kotlin.collections.List { + fun findPetsByTags(tags: kotlin.Array) : kotlin.Array { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf("tags" to tags.joinToString(separator = collectionDelimiter("csv"))) + val localVariableQuery: MultiValueMap = mapOf("tags" to toMultiValue(tags.toList(), "csv")) val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.GET, @@ -130,13 +130,13 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli query = localVariableQuery, headers = localVariableHeaders ) - val response = request>( + val response = request>( localVariableConfig, localVariableBody ) return when (response.responseType) { - ResponseType.Success -> (response as Success<*>).data as kotlin.collections.List + ResponseType.Success -> (response as Success<*>).data as kotlin.Array ResponseType.Informational -> TODO() ResponseType.Redirection -> TODO() ResponseType.ClientError -> throw ClientException((response as ClientError<*>).body as? String ?: "Client error") @@ -154,7 +154,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli @Suppress("UNCHECKED_CAST") fun getPetById(petId: kotlin.Long) : Pet { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.GET, @@ -185,7 +185,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli */ fun updatePet(body: Pet) : Unit { val localVariableBody: kotlin.Any? = body - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.PUT, @@ -218,7 +218,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli */ fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String, status: kotlin.String) : Unit { val localVariableBody: kotlin.Any? = mapOf("name" to "$name", "status" to "$status") - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf("Content-Type" to "multipart/form-data") val localVariableConfig = RequestConfig( RequestMethod.POST, @@ -252,7 +252,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli @Suppress("UNCHECKED_CAST") fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String, file: java.io.File) : ApiResponse { val localVariableBody: kotlin.Any? = mapOf("additionalMetadata" to "$additionalMetadata", "file" to "$file") - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf("Content-Type" to "multipart/form-data") val localVariableConfig = RequestConfig( RequestMethod.POST, @@ -275,12 +275,4 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli } } - - private fun collectionDelimiter(collectionFormat: kotlin.String) = when(collectionFormat) { - "csv" -> "," - "tsv" -> "\t" - "pipes" -> "|" - "ssv" -> " " - else -> "" - } } diff --git a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/StoreApi.kt b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/StoreApi.kt index 9dabfdb3b66f..53e3813f4dc2 100644 --- a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/StoreApi.kt +++ b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/StoreApi.kt @@ -25,7 +25,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC */ fun deleteOrder(orderId: kotlin.String) : Unit { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.DELETE, @@ -56,7 +56,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC @Suppress("UNCHECKED_CAST") fun getInventory() : kotlin.collections.Map { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.GET, @@ -88,7 +88,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC @Suppress("UNCHECKED_CAST") fun getOrderById(orderId: kotlin.Long) : Order { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.GET, @@ -120,7 +120,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC @Suppress("UNCHECKED_CAST") fun placeOrder(body: Order) : Order { val localVariableBody: kotlin.Any? = body - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.POST, @@ -143,12 +143,4 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC } } - - private fun collectionDelimiter(collectionFormat: kotlin.String) = when(collectionFormat) { - "csv" -> "," - "tsv" -> "\t" - "pipes" -> "|" - "ssv" -> " " - else -> "" - } } diff --git a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/UserApi.kt b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/UserApi.kt index e703c71bcddc..d3d80fe76ab6 100644 --- a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/UserApi.kt +++ b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/apis/UserApi.kt @@ -25,7 +25,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl */ fun createUser(body: User) : Unit { val localVariableBody: kotlin.Any? = body - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.POST, @@ -54,9 +54,9 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl * @param body List of user object * @return void */ - fun createUsersWithArrayInput(body: kotlin.collections.List) : Unit { + fun createUsersWithArrayInput(body: kotlin.Array) : Unit { val localVariableBody: kotlin.Any? = body - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.POST, @@ -85,9 +85,9 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl * @param body List of user object * @return void */ - fun createUsersWithListInput(body: kotlin.collections.List) : Unit { + fun createUsersWithListInput(body: kotlin.Array) : Unit { val localVariableBody: kotlin.Any? = body - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.POST, @@ -118,7 +118,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl */ fun deleteUser(username: kotlin.String) : Unit { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.DELETE, @@ -150,7 +150,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl @Suppress("UNCHECKED_CAST") fun getUserByName(username: kotlin.String) : User { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.GET, @@ -183,7 +183,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl @Suppress("UNCHECKED_CAST") fun loginUser(username: kotlin.String, password: kotlin.String) : kotlin.String { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf("username" to username, "password" to password) + val localVariableQuery: MultiValueMap = mapOf("username" to listOf("$username"), "password" to listOf("$password")) val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.GET, @@ -213,7 +213,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl */ fun logoutUser() : Unit { val localVariableBody: kotlin.Any? = null - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.GET, @@ -245,7 +245,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl */ fun updateUser(username: kotlin.String, body: User) : Unit { val localVariableBody: kotlin.Any? = body - val localVariableQuery: kotlin.collections.Map = mapOf() + val localVariableQuery: MultiValueMap = mapOf() val localVariableHeaders: kotlin.collections.Map = mapOf() val localVariableConfig = RequestConfig( RequestMethod.PUT, @@ -268,12 +268,4 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl } } - - private fun collectionDelimiter(collectionFormat: kotlin.String) = when(collectionFormat) { - "csv" -> "," - "tsv" -> "\t" - "pipes" -> "|" - "ssv" -> " " - else -> "" - } } diff --git a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/ApiAbstractions.kt b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/ApiAbstractions.kt new file mode 100644 index 000000000000..87cc13d045b2 --- /dev/null +++ b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/ApiAbstractions.kt @@ -0,0 +1,20 @@ +package io.swagger.client.infrastructure + +typealias MultiValueMap = Map> + +fun collectionDelimiter(collectionFormat: String) = when(collectionFormat) { + "csv" -> "," + "tsv" -> "\t" + "pipes" -> "|" + "ssv" -> " " + else -> "" +} + +val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" } + +fun toMultiValue(items: List, collectionFormat: String, map: (item: Any?) -> String = defaultMultiValueConverter): List { + return when(collectionFormat) { + "multi" -> items.map(map) + else -> listOf(items.map(map).joinToString(separator = collectionDelimiter(collectionFormat))) + } +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/ApiClient.kt index 05ff12c0f94e..40d771e475d7 100644 --- a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/ApiClient.kt +++ b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/ApiClient.kt @@ -60,7 +60,11 @@ open class ApiClient(val baseUrl: String) { var urlBuilder = httpUrl.newBuilder() .addPathSegments(requestConfig.path.trimStart('/')) - requestConfig.query.forEach { k, v -> urlBuilder = urlBuilder.addQueryParameter(k,v) } + requestConfig.query.forEach { k, v -> + v.forEach { queryValue -> + urlBuilder = urlBuilder.addQueryParameter(k,queryValue) + } + } val url = urlBuilder.build() val headers = requestConfig.headers + defaultHeaders @@ -73,6 +77,7 @@ open class ApiClient(val baseUrl: String) { throw kotlin.IllegalStateException("Missing Accept header. This is required.") } + // TODO: support multiple contentType,accept options here. val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase() val accept = (headers[Accept] as String).substringBefore(";").toLowerCase() diff --git a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/RequestConfig.kt b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/RequestConfig.kt index 1df8b769db56..3825588ce4af 100644 --- a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/RequestConfig.kt +++ b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/infrastructure/RequestConfig.kt @@ -5,9 +5,11 @@ package io.swagger.client.infrastructure * NOTE: This object doesn't include 'body' because it * allows for caching of the constructed object * for many request definitions. + * NOTE: Headers is a Map because rfc2616 defines + * multi-valued headers as csv-only. */ data class RequestConfig( val method: RequestMethod, val path: String, val headers: Map = mapOf(), - val query: Map = mapOf()) \ No newline at end of file + val query: Map> = mapOf()) \ No newline at end of file diff --git a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/models/Pet.kt b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/models/Pet.kt index 5fe800afe777..68ee9be1b4bd 100644 --- a/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/models/Pet.kt +++ b/samples/client/petstore/kotlin/src/main/kotlin/io/swagger/client/models/Pet.kt @@ -25,10 +25,10 @@ import io.swagger.client.models.Tag */ data class Pet ( val name: kotlin.String, - val photoUrls: kotlin.collections.List, + val photoUrls: kotlin.Array, val id: kotlin.Long? = null, val category: Category? = null, - val tags: kotlin.collections.List? = null, + val tags: kotlin.Array? = null, /* pet status in the store */ val status: Pet.Status? = null ) { diff --git a/samples/client/petstore/kotlin/src/test/kotlin/io/swagger/client/functional/EvaluateTest.kt b/samples/client/petstore/kotlin/src/test/kotlin/io/swagger/client/functional/EvaluateTest.kt index 955560fb798d..db40b04f2ef7 100644 --- a/samples/client/petstore/kotlin/src/test/kotlin/io/swagger/client/functional/EvaluateTest.kt +++ b/samples/client/petstore/kotlin/src/test/kotlin/io/swagger/client/functional/EvaluateTest.kt @@ -2,16 +2,21 @@ package io.swagger.client.functional import io.kotlintest.matchers.should import io.kotlintest.matchers.beGreaterThan +import io.kotlintest.matchers.shouldEqual import io.kotlintest.specs.ShouldSpec import io.swagger.client.apis.PetApi +import io.swagger.client.models.Pet class EvaluateTest : ShouldSpec() { init { should("query against pet statuses") { val api = PetApi() - val results = api.findPetsByStatus(listOf("sold")) + val results = api.findPetsByStatus(arrayOf("sold")) results.size should beGreaterThan(1) + + // Pet is lazily deserialized here. Need to iterate to verify all "sold" statuses. + results.all { it.status == Pet.Status.sold } shouldEqual true } // TODO: Handle default (200) response