From 69b8831cbed58b00ad5895ee3fc03775097a9c24 Mon Sep 17 00:00:00 2001 From: Mathieu Lemoine Date: Fri, 27 Dec 2019 03:37:29 -0500 Subject: [PATCH] [Kotlin] enumPropertyNaming UPPERCASE should separate words with _ (#4062) * [Kotlin] enumPropertyNaming UPPERCASE should separate words with _ * Add unit cases for issue 4062 Co-authored-by: William Cheng --- bin/kotlin-uppercase-enum.sh | 34 ++++ .../languages/AbstractKotlinCodegen.java | 2 +- .../src/test/resources/3_0/issue-4062.yaml | 33 ++++ .../.openapi-generator-ignore | 23 +++ .../.openapi-generator/VERSION | 1 + .../petstore/kotlin-uppercase-enum/README.md | 50 ++++++ .../kotlin-uppercase-enum/build.gradle | 37 +++++ .../kotlin-uppercase-enum/docs/EnumApi.md | 50 ++++++ .../kotlin-uppercase-enum/docs/PetEnum.md | 12 ++ .../kotlin-uppercase-enum/settings.gradle | 2 + .../org/openapitools/client/apis/EnumApi.kt | 60 +++++++ .../client/infrastructure/ApiAbstractions.kt | 23 +++ .../client/infrastructure/ApiClient.kt | 153 ++++++++++++++++++ .../ApiInfrastructureResponse.kt | 40 +++++ .../infrastructure/ApplicationDelegates.kt | 29 ++++ .../client/infrastructure/ByteArrayAdapter.kt | 12 ++ .../client/infrastructure/Errors.kt | 42 +++++ .../client/infrastructure/LocalDateAdapter.kt | 19 +++ .../infrastructure/LocalDateTimeAdapter.kt | 19 +++ .../client/infrastructure/RequestConfig.kt | 16 ++ .../client/infrastructure/RequestMethod.kt | 8 + .../infrastructure/ResponseExtensions.kt | 23 +++ .../client/infrastructure/Serializer.kt | 18 +++ .../client/infrastructure/UUIDAdapter.kt | 13 ++ .../org/openapitools/client/models/PetEnum.kt | 35 ++++ 25 files changed, 753 insertions(+), 1 deletion(-) create mode 100755 bin/kotlin-uppercase-enum.sh create mode 100644 modules/openapi-generator/src/test/resources/3_0/issue-4062.yaml create mode 100644 samples/client/petstore/kotlin-uppercase-enum/.openapi-generator-ignore create mode 100644 samples/client/petstore/kotlin-uppercase-enum/.openapi-generator/VERSION create mode 100644 samples/client/petstore/kotlin-uppercase-enum/README.md create mode 100644 samples/client/petstore/kotlin-uppercase-enum/build.gradle create mode 100644 samples/client/petstore/kotlin-uppercase-enum/docs/EnumApi.md create mode 100644 samples/client/petstore/kotlin-uppercase-enum/docs/PetEnum.md create mode 100644 samples/client/petstore/kotlin-uppercase-enum/settings.gradle create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/apis/EnumApi.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiInfrastructureResponse.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApplicationDelegates.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt create mode 100644 samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/models/PetEnum.kt diff --git a/bin/kotlin-uppercase-enum.sh b/bin/kotlin-uppercase-enum.sh new file mode 100755 index 00000000000..49f690283f4 --- /dev/null +++ b/bin/kotlin-uppercase-enum.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +SCRIPT="$0" +echo "# START SCRIPT: $SCRIPT" + +while [ -h "$SCRIPT" ] ; do + ls=$(ls -ld "$SCRIPT") + link=$(expr "$ls" : '.*-> \(.*\)$') + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=$(dirname "$SCRIPT")/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=$(dirname "$SCRIPT")/.. + APP_DIR=$(cd "${APP_DIR}"; pwd) +fi + +executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar" + +if [ ! -f "$executable" ] +then + mvn -B clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="generate -t modules/openapi-generator/src/main/resources/kotlin-client -i modules/openapi-generator/src/test/resources/3_0/issue-4062.yaml -g kotlin --artifact-id kotlin-uppercase-enum --additional-properties enumPropertyNaming=UPPERCASE -o samples/client/petstore/kotlin-uppercase-enum $@" + +java ${JAVA_OPTS} -jar ${executable} ${ags} + +cp CI/samples.ci/client/petstore/kotlin-uppercase-enum/pom.xml samples/client/petstore/kotlin-uppercase-enum/pom.xml \ No newline at end of file diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java index bed71307d4d..b0227feae16 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractKotlinCodegen.java @@ -530,7 +530,7 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co modified = underscore(modified); break; case UPPERCASE: - modified = modified.toUpperCase(Locale.ROOT); + modified = underscore(modified).toUpperCase(Locale.ROOT); break; } diff --git a/modules/openapi-generator/src/test/resources/3_0/issue-4062.yaml b/modules/openapi-generator/src/test/resources/3_0/issue-4062.yaml new file mode 100644 index 00000000000..2ad7665265c --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/issue-4062.yaml @@ -0,0 +1,33 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: Test for issue 4062 + version: 1.0.0 + title: OpenAPI Petstore + license: + name: Apache-2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +paths: + /enum: + get: + tags: + - enum + summary: Get enums + description: '' + operationId: getEnum + responses: + '200': + description: success + content: + application/json: + schema: + $ref: '#/components/schemas/PetEnum' +components: + schemas: + PetEnum: + type: string + description: An enum with complex-ish naming + enum: + - myFirstValue + - MY_SECOND_VALUE \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/.openapi-generator-ignore b/samples/client/petstore/kotlin-uppercase-enum/.openapi-generator-ignore new file mode 100644 index 00000000000..7484ee590a3 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/samples/client/petstore/kotlin-uppercase-enum/.openapi-generator/VERSION b/samples/client/petstore/kotlin-uppercase-enum/.openapi-generator/VERSION new file mode 100644 index 00000000000..c3a2c7076fa --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/.openapi-generator/VERSION @@ -0,0 +1 @@ +4.2.0-SNAPSHOT \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/README.md b/samples/client/petstore/kotlin-uppercase-enum/README.md new file mode 100644 index 00000000000..9d5f9e7e33e --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/README.md @@ -0,0 +1,50 @@ +# org.openapitools.client - Kotlin client library for OpenAPI Petstore + +## Requires + +* Kotlin 1.3.41 +* Gradle 4.9 + +## Build + +First, create the gradle wrapper script: + +``` +gradle wrapper +``` + +Then, run: + +``` +./gradlew check assemble +``` + +This runs all tests and packages the library. + +## Features/Implementation Notes + +* Supports JSON inputs/outputs, File inputs, and Form inputs. +* Supports collection formats for query parameters: csv, tsv, ssv, pipes. +* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in OpenAPI definitions. +* Implementation of ApiClient is intended to reduce method counts, specifically to benefit Android targets. + + +## Documentation for API Endpoints + +All URIs are relative to *http://petstore.swagger.io/v2* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*EnumApi* | [**getEnum**](docs/EnumApi.md#getenum) | **GET** /enum | Get enums + + + +## Documentation for Models + + - [org.openapitools.client.models.PetEnum](docs/PetEnum.md) + + + +## Documentation for Authorization + +All endpoints do not require authorization. diff --git a/samples/client/petstore/kotlin-uppercase-enum/build.gradle b/samples/client/petstore/kotlin-uppercase-enum/build.gradle new file mode 100644 index 00000000000..c09f7912cfe --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/build.gradle @@ -0,0 +1,37 @@ +group 'org.openapitools' +version '1.0.0' + +wrapper { + gradleVersion = '4.9' + distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" +} + +buildscript { + ext.kotlin_version = '1.3.41' + + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: 'kotlin' + +repositories { + mavenCentral() +} + +test { + useJUnitPlatform() +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + compile "com.squareup.moshi:moshi-kotlin:1.8.0" + compile "com.squareup.moshi:moshi-adapters:1.8.0" + compile "com.squareup.okhttp3:okhttp:4.0.1" + testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0" +} diff --git a/samples/client/petstore/kotlin-uppercase-enum/docs/EnumApi.md b/samples/client/petstore/kotlin-uppercase-enum/docs/EnumApi.md new file mode 100644 index 00000000000..7eaa182a4a5 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/docs/EnumApi.md @@ -0,0 +1,50 @@ +# EnumApi + +All URIs are relative to *http://petstore.swagger.io/v2* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**getEnum**](EnumApi.md#getEnum) | **GET** /enum | Get enums + + + +# **getEnum** +> PetEnum getEnum() + +Get enums + +### Example +```kotlin +// Import classes: +//import org.openapitools.client.infrastructure.* +//import org.openapitools.client.models.* + +val apiInstance = EnumApi() +try { + val result : PetEnum = apiInstance.getEnum() + println(result) +} catch (e: ClientException) { + println("4xx response calling EnumApi#getEnum") + e.printStackTrace() +} catch (e: ServerException) { + println("5xx response calling EnumApi#getEnum") + e.printStackTrace() +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**PetEnum**](PetEnum.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + diff --git a/samples/client/petstore/kotlin-uppercase-enum/docs/PetEnum.md b/samples/client/petstore/kotlin-uppercase-enum/docs/PetEnum.md new file mode 100644 index 00000000000..d970c3dd862 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/docs/PetEnum.md @@ -0,0 +1,12 @@ + +# PetEnum + +## Enum + + + * `MY_FIRST_VALUE` (value: `"myFirstValue"`) + + * `MY_SECOND_VALUE` (value: `"MY_SECOND_VALUE"`) + + + diff --git a/samples/client/petstore/kotlin-uppercase-enum/settings.gradle b/samples/client/petstore/kotlin-uppercase-enum/settings.gradle new file mode 100644 index 00000000000..cc08df3bfdc --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/settings.gradle @@ -0,0 +1,2 @@ + +rootProject.name = 'kotlin-uppercase-enum' \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/apis/EnumApi.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/apis/EnumApi.kt new file mode 100644 index 00000000000..dcd526a91c3 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/apis/EnumApi.kt @@ -0,0 +1,60 @@ +/** +* OpenAPI Petstore +* Test for issue 4062 +* +* The version of the OpenAPI document: 1.0.0 +* +* +* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +package org.openapitools.client.apis + +import org.openapitools.client.models.PetEnum + +import org.openapitools.client.infrastructure.ApiClient +import org.openapitools.client.infrastructure.ClientException +import org.openapitools.client.infrastructure.ClientError +import org.openapitools.client.infrastructure.ServerException +import org.openapitools.client.infrastructure.ServerError +import org.openapitools.client.infrastructure.MultiValueMap +import org.openapitools.client.infrastructure.RequestConfig +import org.openapitools.client.infrastructure.RequestMethod +import org.openapitools.client.infrastructure.ResponseType +import org.openapitools.client.infrastructure.Success +import org.openapitools.client.infrastructure.toMultiValue + +class EnumApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { + + /** + * Get enums + * + * @return PetEnum + */ + @Suppress("UNCHECKED_CAST") + fun getEnum() : PetEnum { + val localVariableBody: kotlin.Any? = null + val localVariableQuery: MultiValueMap = mapOf() + val localVariableHeaders: MutableMap = mutableMapOf() + val localVariableConfig = RequestConfig( + RequestMethod.GET, + "/enum", + query = localVariableQuery, + headers = localVariableHeaders + ) + val response = request( + localVariableConfig, + localVariableBody + ) + + return when (response.responseType) { + ResponseType.Success -> (response as Success<*>).data as PetEnum + ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.") + ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.") + ResponseType.ClientError -> throw ClientException((response as ClientError<*>).body as? String ?: "Client error") + ResponseType.ServerError -> throw ServerException((response as ServerError<*>).message ?: "Server error") + } + } + +} diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt new file mode 100644 index 00000000000..f97cb88d233 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt @@ -0,0 +1,23 @@ +package org.openapitools.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: Array, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter) + = toMultiValue(items.asIterable(), collectionFormat, map) + +fun toMultiValue(items: Iterable, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List { + return when(collectionFormat) { + "multi" -> items.map(map) + else -> listOf(items.joinToString(separator = collectionDelimiter(collectionFormat), transform = map)) + } +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt new file mode 100644 index 00000000000..4ba5be35baa --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt @@ -0,0 +1,153 @@ +package org.openapitools.client.infrastructure + +import okhttp3.OkHttpClient +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.FormBody +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.ResponseBody +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.Request +import java.io.File + +open class ApiClient(val baseUrl: String) { + companion object { + protected const val ContentType = "Content-Type" + protected const val Accept = "Accept" + protected const val Authorization = "Authorization" + protected const val JsonMediaType = "application/json" + protected const val FormDataMediaType = "multipart/form-data" + protected const val FormUrlEncMediaType = "application/x-www-form-urlencoded" + protected const val XmlMediaType = "application/xml" + + val apiKey: MutableMap = mutableMapOf() + val apiKeyPrefix: MutableMap = mutableMapOf() + var username: String? = null + var password: String? = null + var accessToken: String? = null + + @JvmStatic + val client: OkHttpClient by lazy { + builder.build() + } + + @JvmStatic + val builder: OkHttpClient.Builder = OkHttpClient.Builder() + } + + protected inline fun requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = + when { + content is File -> content.asRequestBody( + mediaType.toMediaTypeOrNull() + ) + mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> { + FormBody.Builder().apply { + // content's type *must* be Map + @Suppress("UNCHECKED_CAST") + (content as Map).forEach { (key, value) -> + add(key, value) + } + }.build() + } + mediaType == JsonMediaType -> Serializer.moshi.adapter(T::class.java).toJson(content).toRequestBody( + mediaType.toMediaTypeOrNull() + ) + mediaType == XmlMediaType -> throw UnsupportedOperationException("xml not currently supported.") + // TODO: this should be extended with other serializers + else -> throw UnsupportedOperationException("requestBody currently only supports JSON body and File body.") + } + + protected inline fun responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? { + if(body == null) { + return null + } + val bodyContent = body.string() + if (bodyContent.isEmpty()) { + return null + } + return when(mediaType) { + JsonMediaType -> Serializer.moshi.adapter(T::class.java).fromJson(bodyContent) + else -> throw UnsupportedOperationException("responseBody currently only supports JSON body.") + } + } + + + protected inline fun request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse { + val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.") + + val url = httpUrl.newBuilder() + .addPathSegments(requestConfig.path.trimStart('/')) + .apply { + requestConfig.query.forEach { query -> + query.value.forEach { queryValue -> + addQueryParameter(query.key, queryValue) + } + } + }.build() + + // take content-type/accept from spec or set to default (application/json) if not defined + if (requestConfig.headers[ContentType].isNullOrEmpty()) { + requestConfig.headers[ContentType] = JsonMediaType + } + if (requestConfig.headers[Accept].isNullOrEmpty()) { + requestConfig.headers[Accept] = JsonMediaType + } + val headers = requestConfig.headers + + if(headers[ContentType] ?: "" == "") { + throw kotlin.IllegalStateException("Missing Content-Type header. This is required.") + } + + if(headers[Accept] ?: "" == "") { + throw kotlin.IllegalStateException("Missing Accept header. This is required.") + } + + // TODO: support multiple contentType options here. + val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase() + + val request = when (requestConfig.method) { + RequestMethod.DELETE -> Request.Builder().url(url).delete() + RequestMethod.GET -> Request.Builder().url(url) + RequestMethod.HEAD -> Request.Builder().url(url).head() + RequestMethod.PATCH -> Request.Builder().url(url).patch(requestBody(body, contentType)) + RequestMethod.PUT -> Request.Builder().url(url).put(requestBody(body, contentType)) + RequestMethod.POST -> Request.Builder().url(url).post(requestBody(body, contentType)) + RequestMethod.OPTIONS -> Request.Builder().url(url).method("OPTIONS", null) + }.apply { + headers.forEach { header -> addHeader(header.key, header.value) } + }.build() + + val response = client.newCall(request).execute() + val accept = response.header(ContentType)?.substringBefore(";")?.toLowerCase() + + // TODO: handle specific mapping types. e.g. Map> + when { + response.isRedirect -> return Redirection( + response.code, + response.headers.toMultimap() + ) + response.isInformational -> return Informational( + response.message, + response.code, + response.headers.toMultimap() + ) + response.isSuccessful -> return Success( + responseBody(response.body, accept), + response.code, + response.headers.toMultimap() + ) + response.isClientError -> return ClientError( + response.body?.string(), + response.code, + response.headers.toMultimap() + ) + else -> return ServerError( + null, + response.body?.string(), + response.code, + response.headers.toMultimap() + ) + } + } +} diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiInfrastructureResponse.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiInfrastructureResponse.kt new file mode 100644 index 00000000000..f1a8aecc914 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiInfrastructureResponse.kt @@ -0,0 +1,40 @@ +package org.openapitools.client.infrastructure + +enum class ResponseType { + Success, Informational, Redirection, ClientError, ServerError +} + +abstract class ApiInfrastructureResponse(val responseType: ResponseType) { + abstract val statusCode: Int + abstract val headers: Map> +} + +class Success( + val data: T, + override val statusCode: Int = -1, + override val headers: Map> = mapOf() +): ApiInfrastructureResponse(ResponseType.Success) + +class Informational( + val statusText: String, + override val statusCode: Int = -1, + override val headers: Map> = mapOf() +) : ApiInfrastructureResponse(ResponseType.Informational) + +class Redirection( + override val statusCode: Int = -1, + override val headers: Map> = mapOf() +) : ApiInfrastructureResponse(ResponseType.Redirection) + +class ClientError( + val body: Any? = null, + override val statusCode: Int = -1, + override val headers: Map> = mapOf() +) : ApiInfrastructureResponse(ResponseType.ClientError) + +class ServerError( + val message: String? = null, + val body: Any? = null, + override val statusCode: Int = -1, + override val headers: Map> +): ApiInfrastructureResponse(ResponseType.ServerError) \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApplicationDelegates.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApplicationDelegates.kt new file mode 100644 index 00000000000..dd34bd48b2c --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApplicationDelegates.kt @@ -0,0 +1,29 @@ +package org.openapitools.client.infrastructure + +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +object ApplicationDelegates { + /** + * Provides a property delegate, allowing the property to be set once and only once. + * + * If unset (no default value), a get on the property will throw [IllegalStateException]. + */ + fun setOnce(defaultValue: T? = null) : ReadWriteProperty = SetOnce(defaultValue) + + private class SetOnce(defaultValue: T? = null) : ReadWriteProperty { + private var isSet = false + private var value: T? = defaultValue + + override fun getValue(thisRef: Any?, property: KProperty<*>): T { + return value ?: throw IllegalStateException("${property.name} not initialized") + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = synchronized(this) { + if (!isSet) { + this.value = value + isSet = true + } + } + } +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt new file mode 100644 index 00000000000..617ac3fe906 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt @@ -0,0 +1,12 @@ +package org.openapitools.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson + +class ByteArrayAdapter { + @ToJson + fun toJson(data: ByteArray): String = String(data) + + @FromJson + fun fromJson(data: String): ByteArray = data.toByteArray() +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt new file mode 100644 index 00000000000..2f3b0157ba7 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt @@ -0,0 +1,42 @@ +@file:Suppress("unused") +package org.openapitools.client.infrastructure + +import java.lang.RuntimeException + +open class ClientException : RuntimeException { + + /** + * Constructs an [ClientException] with no detail message. + */ + constructor() : super() + + /** + * Constructs an [ClientException] with the specified detail message. + + * @param message the detail message. + */ + constructor(message: kotlin.String) : super(message) + + companion object { + private const val serialVersionUID: Long = 123L + } +} + +open class ServerException : RuntimeException { + + /** + * Constructs an [ServerException] with no detail message. + */ + constructor() : super() + + /** + * Constructs an [ServerException] with the specified detail message. + + * @param message the detail message. + */ + constructor(message: kotlin.String) : super(message) + + companion object { + private const val serialVersionUID: Long = 456L + } +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt new file mode 100644 index 00000000000..b2e1654479a --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt @@ -0,0 +1,19 @@ +package org.openapitools.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +class LocalDateAdapter { + @ToJson + fun toJson(value: LocalDate): String { + return DateTimeFormatter.ISO_LOCAL_DATE.format(value) + } + + @FromJson + fun fromJson(value: String): LocalDate { + return LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE) + } + +} diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt new file mode 100644 index 00000000000..e082db94811 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt @@ -0,0 +1,19 @@ +package org.openapitools.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + +class LocalDateTimeAdapter { + @ToJson + fun toJson(value: LocalDateTime): String { + return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(value) + } + + @FromJson + fun fromJson(value: String): LocalDateTime { + return LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME) + } + +} diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt new file mode 100644 index 00000000000..53e689237d7 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt @@ -0,0 +1,16 @@ +package org.openapitools.client.infrastructure + +/** + * Defines a config object for a given request. + * 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: MutableMap = mutableMapOf(), + val query: Map> = mapOf() +) \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt new file mode 100644 index 00000000000..931b12b8bd7 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt @@ -0,0 +1,8 @@ +package org.openapitools.client.infrastructure + +/** + * Provides enumerated HTTP verbs + */ +enum class RequestMethod { + GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT +} \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt new file mode 100644 index 00000000000..934962ec6b5 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt @@ -0,0 +1,23 @@ +package org.openapitools.client.infrastructure + +import okhttp3.Response + +/** + * Provides an extension to evaluation whether the response is a 1xx code + */ +val Response.isInformational : Boolean get() = this.code in 100..199 + +/** + * Provides an extension to evaluation whether the response is a 3xx code + */ +val Response.isRedirect : Boolean get() = this.code in 300..399 + +/** + * Provides an extension to evaluation whether the response is a 4xx code + */ +val Response.isClientError : Boolean get() = this.code in 400..499 + +/** + * Provides an extension to evaluation whether the response is a 5xx (Standard) through 999 (non-standard) code + */ +val Response.isServerError : Boolean get() = this.code in 500..999 \ No newline at end of file diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt new file mode 100644 index 00000000000..7c5a353e0f7 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt @@ -0,0 +1,18 @@ +package org.openapitools.client.infrastructure + +import com.squareup.moshi.Moshi +import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import java.util.Date + +object Serializer { + @JvmStatic + val moshi: Moshi = Moshi.Builder() + .add(Date::class.java, Rfc3339DateJsonAdapter().nullSafe()) + .add(LocalDateTimeAdapter()) + .add(LocalDateAdapter()) + .add(UUIDAdapter()) + .add(ByteArrayAdapter()) + .add(KotlinJsonAdapterFactory()) + .build() +} diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt new file mode 100644 index 00000000000..a4a44cc18b7 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt @@ -0,0 +1,13 @@ +package org.openapitools.client.infrastructure + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.util.UUID + +class UUIDAdapter { + @ToJson + fun toJson(uuid: UUID) = uuid.toString() + + @FromJson + fun fromJson(s: String) = UUID.fromString(s) +} diff --git a/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/models/PetEnum.kt b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/models/PetEnum.kt new file mode 100644 index 00000000000..14d9c16c408 --- /dev/null +++ b/samples/client/petstore/kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/models/PetEnum.kt @@ -0,0 +1,35 @@ +/** +* OpenAPI Petstore +* Test for issue 4062 +* +* The version of the OpenAPI document: 1.0.0 +* +* +* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). +* https://openapi-generator.tech +* Do not edit the class manually. +*/ +package org.openapitools.client.models + + +import com.squareup.moshi.Json + +/** +* An enum with complex-ish naming +* Values: MY_FIRST_VALUE,MY_SECOND_VALUE +*/ + +enum class PetEnum(val value: kotlin.String){ + + + @Json(name = "myFirstValue") + MY_FIRST_VALUE("myFirstValue"), + + + @Json(name = "MY_SECOND_VALUE") + MY_SECOND_VALUE("MY_SECOND_VALUE"); + + + +} +