Fix kotlin templates (#3504)

* Fix kotlin templates to use okhttp 4.0.1.
* Fix escaping of dataType field.
* Fix handling of arrays/lists of enums.
This commit is contained in:
Andrey 2019-08-11 15:35:57 +02:00 committed by Jim Schubert
parent 22d022b2d5
commit 07381e7275
24 changed files with 140 additions and 118 deletions

View File

@ -1191,7 +1191,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
for (String key : definitions.keySet()) { for (String key : definitions.keySet()) {
Schema schema = definitions.get(key); Schema schema = definitions.get(key);
if (schema == null) if (schema == null)
throw new RuntimeException("schema cannot be null in processMoels"); throw new RuntimeException("schema cannot be null in processModels");
CodegenModel cm = config.fromModel(key, schema); CodegenModel cm = config.fromModel(key, schema);
Map<String, Object> mo = new HashMap<String, Object>(); Map<String, Object> mo = new HashMap<String, Object>();
mo.put("model", cm); mo.put("model", cm);

View File

@ -612,6 +612,7 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
StringBuilder instantiationType = new StringBuilder(arrayType); StringBuilder instantiationType = new StringBuilder(arrayType);
Schema items = arr.getItems(); Schema items = arr.getItems();
String nestedType = getTypeDeclaration(items); String nestedType = getTypeDeclaration(items);
additionalProperties.put("nestedType", nestedType);
// TODO: We may want to differentiate here between generics and primitive arrays. // TODO: We may want to differentiate here between generics and primitive arrays.
instantiationType.append("<").append(nestedType).append(">"); instantiationType.append("<").append(nestedType).append(">");
return instantiationType.toString(); return instantiationType.toString();

View File

@ -149,6 +149,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
if (CollectionType.LIST.value.equals(collectionType)) { if (CollectionType.LIST.value.equals(collectionType)) {
typeMapping.put("array", "kotlin.collections.List"); typeMapping.put("array", "kotlin.collections.List");
typeMapping.put("list", "kotlin.collections.List"); typeMapping.put("list", "kotlin.collections.List");
additionalProperties.put("isList", true);
} }
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));

View File

@ -2,7 +2,7 @@
## Requires ## Requires
* Kotlin 1.3.31 * Kotlin 1.3.41
* Gradle 4.9 * Gradle 4.9
## Build ## Build

View File

@ -7,7 +7,7 @@ wrapper {
} }
buildscript { buildscript {
ext.kotlin_version = '1.3.31' ext.kotlin_version = '1.3.41'
repositories { repositories {
mavenCentral() mavenCentral()
@ -32,7 +32,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.8.0" compile "com.squareup.moshi:moshi-kotlin:1.8.0"
compile "com.squareup.moshi:moshi-adapters:1.8.0" compile "com.squareup.moshi:moshi-adapters:1.8.0"
compile "com.squareup.okhttp3:okhttp:3.14.2" compile "com.squareup.okhttp3:okhttp:4.0.1"
{{#threetenbp}} {{#threetenbp}}
compile "org.threeten:threetenbp:1.3.8" compile "org.threeten:threetenbp:1.3.8"
{{/threetenbp}} {{/threetenbp}}

View File

@ -25,7 +25,7 @@ data class {{classname}} (
* {{{description}}} * {{{description}}}
* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
*/ */
enum class {{nameInCamelCase}}(val value: {{dataType}}){ enum class {{{nameInCamelCase}}}(val value: {{#isListContainer}}{{{ nestedType }}}{{/isListContainer}}{{^isListContainer}}{{{dataType}}}{{/isListContainer}}){
{{#allowableValues}}{{#enumVars}} {{#allowableValues}}{{#enumVars}}
@Json(name = {{{value}}}) @Json(name = {{{value}}})
{{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}

View File

@ -2,4 +2,4 @@
/* {{{description}}} */ /* {{{description}}} */
{{/description}} {{/description}}
@Json(name = "{{{baseName}}}") @Json(name = "{{{baseName}}}")
val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}} val {{{name}}}: {{#isEnum}}{{#isListContainer}}{{#isList}}kotlin.collections.List{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{classname}}.{{{nameInCamelCase}}}>{{/isListContainer}}{{^isListContainer}}{{classname}}.{{{nameInCamelCase}}}{{/isListContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}}

View File

@ -2,4 +2,4 @@
/* {{{description}}} */ /* {{{description}}} */
{{/description}} {{/description}}
@Json(name = "{{{baseName}}}") @Json(name = "{{{baseName}}}")
val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}} val {{{name}}}: {{#isEnum}}{{#isListContainer}}{{#isList}}kotlin.collections.List{{/isList}}{{^isList}}kotlin.Array{{/isList}}<{{classname}}.{{{nameInCamelCase}}}>{{/isListContainer}}{{^isListContainer}}{{classname}}.{{{nameInCamelCase}}}{{/isListContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}

View File

@ -4,9 +4,21 @@ import com.squareup.moshi.Json
* {{{description}}} * {{{description}}}
* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
*/ */
enum class {{classname}}(val value: {{dataType}}){ enum class {{classname}}(val value: {{{dataType}}}){
{{#allowableValues}}{{#enumVars}} {{#allowableValues}}{{#enumVars}}
@Json(name = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}}) @Json(name = {{^isString}}"{{/isString}}{{{value}}}{{^isString}}"{{/isString}})
{{#isListContainer}}
{{#isList}}
{{&name}}(listOf({{{value}}})){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/isList}}
{{^isList}}
{{&name}}(arrayOf({{{value}}})){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/isList}}
{{/isListContainer}}
{{^isListContainer}}
{{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/isListContainer}}
{{/enumVars}}{{/allowableValues}} {{/enumVars}}{{/allowableValues}}
} }

View File

@ -2,10 +2,12 @@ package {{packageName}}.infrastructure
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.MediaType import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.ResponseBody import okhttp3.ResponseBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request import okhttp3.Request
import java.io.File import java.io.File
@ -29,8 +31,8 @@ open class ApiClient(val baseUrl: String) {
protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody =
when { when {
content is File -> RequestBody.create( content is File -> content.asRequestBody(
MediaType.parse(mediaType), content mediaType.toMediaTypeOrNull()
) )
mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> { mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> {
FormBody.Builder().apply { FormBody.Builder().apply {
@ -41,8 +43,8 @@ open class ApiClient(val baseUrl: String) {
} }
}.build() }.build()
} }
mediaType == JsonMediaType -> RequestBody.create( mediaType == JsonMediaType -> Serializer.moshi.adapter(T::class.java).toJson(content).toRequestBody(
MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content) mediaType.toMediaTypeOrNull()
) )
mediaType == XmlMediaType -> TODO("xml not currently supported.") mediaType == XmlMediaType -> TODO("xml not currently supported.")
// TODO: this should be extended with other serializers // TODO: this should be extended with other serializers
@ -64,7 +66,7 @@ open class ApiClient(val baseUrl: String) {
} }
protected inline fun <reified T: Any?> request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse<T?> { protected inline fun <reified T: Any?> request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse<T?> {
val httpUrl = HttpUrl.parse(baseUrl) ?: throw IllegalStateException("baseUrl is invalid.") val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.")
val url = httpUrl.newBuilder() val url = httpUrl.newBuilder()
.addPathSegments(requestConfig.path.trimStart('/')) .addPathSegments(requestConfig.path.trimStart('/'))
@ -114,29 +116,29 @@ open class ApiClient(val baseUrl: String) {
// TODO: handle specific mapping types. e.g. Map<int, Class<?>> // TODO: handle specific mapping types. e.g. Map<int, Class<?>>
when { when {
response.isRedirect -> return Redirection( response.isRedirect -> return Redirection(
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isInformational -> return Informational( response.isInformational -> return Informational(
response.message(), response.message,
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isSuccessful -> return Success( response.isSuccessful -> return Success(
responseBody(response.body(), accept), responseBody(response.body, accept),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isClientError -> return ClientError( response.isClientError -> return ClientError(
response.body()?.string(), response.body?.string(),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
else -> return ServerError( else -> return ServerError(
null, null,
response.body()?.string(), response.body?.string(),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
} }
} }

View File

@ -5,19 +5,19 @@ import okhttp3.Response
/** /**
* Provides an extension to evaluation whether the response is a 1xx code * Provides an extension to evaluation whether the response is a 1xx code
*/ */
val Response.isInformational : Boolean get() = this.code() in 100..199 val Response.isInformational : Boolean get() = this.code in 100..199
/** /**
* Provides an extension to evaluation whether the response is a 3xx code * Provides an extension to evaluation whether the response is a 3xx code
*/ */
val Response.isRedirect : Boolean get() = this.code() in 300..399 val Response.isRedirect : Boolean get() = this.code in 300..399
/** /**
* Provides an extension to evaluation whether the response is a 4xx code * Provides an extension to evaluation whether the response is a 4xx code
*/ */
val Response.isClientError : Boolean get() = this.code() in 400..499 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 * 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 val Response.isServerError : Boolean get() = this.code in 500..999

View File

@ -6,6 +6,6 @@ package {{modelPackage}}
{{#models}} {{#models}}
{{#model}} {{#model}}
{{#isEnum}}{{>enum_class}}{{/isEnum}}{{^isEnum}}{{#isAlias}}typealias {{classname}} = {{dataType}}{{/isAlias}}{{^isAlias}}{{>data_class}}{{/isAlias}}{{/isEnum}} {{#isEnum}}{{>enum_class}}{{/isEnum}}{{^isEnum}}{{#isAlias}}typealias {{classname}} = {{{dataType}}}{{/isAlias}}{{^isAlias}}{{>data_class}}{{/isAlias}}{{/isEnum}}
{{/model}} {{/model}}
{{/models}} {{/models}}

View File

@ -2,7 +2,7 @@
## Requires ## Requires
* Kotlin 1.3.31 * Kotlin 1.3.41
* Gradle 4.9 * Gradle 4.9
## Build ## Build

View File

@ -7,7 +7,7 @@ wrapper {
} }
buildscript { buildscript {
ext.kotlin_version = '1.3.31' ext.kotlin_version = '1.3.41'
repositories { repositories {
mavenCentral() mavenCentral()
@ -32,6 +32,6 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.8.0" compile "com.squareup.moshi:moshi-kotlin:1.8.0"
compile "com.squareup.moshi:moshi-adapters:1.8.0" compile "com.squareup.moshi:moshi-adapters:1.8.0"
compile "com.squareup.okhttp3:okhttp:3.14.2" compile "com.squareup.okhttp3:okhttp:4.0.1"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
} }

View File

@ -2,10 +2,12 @@ package org.openapitools.client.infrastructure
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.MediaType import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.ResponseBody import okhttp3.ResponseBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request import okhttp3.Request
import java.io.File import java.io.File
@ -29,8 +31,8 @@ open class ApiClient(val baseUrl: String) {
protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody =
when { when {
content is File -> RequestBody.create( content is File -> content.asRequestBody(
MediaType.parse(mediaType), content mediaType.toMediaTypeOrNull()
) )
mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> { mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> {
FormBody.Builder().apply { FormBody.Builder().apply {
@ -41,8 +43,8 @@ open class ApiClient(val baseUrl: String) {
} }
}.build() }.build()
} }
mediaType == JsonMediaType -> RequestBody.create( mediaType == JsonMediaType -> Serializer.moshi.adapter(T::class.java).toJson(content).toRequestBody(
MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content) mediaType.toMediaTypeOrNull()
) )
mediaType == XmlMediaType -> TODO("xml not currently supported.") mediaType == XmlMediaType -> TODO("xml not currently supported.")
// TODO: this should be extended with other serializers // TODO: this should be extended with other serializers
@ -64,7 +66,7 @@ open class ApiClient(val baseUrl: String) {
} }
protected inline fun <reified T: Any?> request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse<T?> { protected inline fun <reified T: Any?> request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse<T?> {
val httpUrl = HttpUrl.parse(baseUrl) ?: throw IllegalStateException("baseUrl is invalid.") val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.")
val url = httpUrl.newBuilder() val url = httpUrl.newBuilder()
.addPathSegments(requestConfig.path.trimStart('/')) .addPathSegments(requestConfig.path.trimStart('/'))
@ -114,29 +116,29 @@ open class ApiClient(val baseUrl: String) {
// TODO: handle specific mapping types. e.g. Map<int, Class<?>> // TODO: handle specific mapping types. e.g. Map<int, Class<?>>
when { when {
response.isRedirect -> return Redirection( response.isRedirect -> return Redirection(
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isInformational -> return Informational( response.isInformational -> return Informational(
response.message(), response.message,
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isSuccessful -> return Success( response.isSuccessful -> return Success(
responseBody(response.body(), accept), responseBody(response.body, accept),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isClientError -> return ClientError( response.isClientError -> return ClientError(
response.body()?.string(), response.body?.string(),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
else -> return ServerError( else -> return ServerError(
null, null,
response.body()?.string(), response.body?.string(),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
} }
} }

View File

@ -5,19 +5,19 @@ import okhttp3.Response
/** /**
* Provides an extension to evaluation whether the response is a 1xx code * Provides an extension to evaluation whether the response is a 1xx code
*/ */
val Response.isInformational : Boolean get() = this.code() in 100..199 val Response.isInformational : Boolean get() = this.code in 100..199
/** /**
* Provides an extension to evaluation whether the response is a 3xx code * Provides an extension to evaluation whether the response is a 3xx code
*/ */
val Response.isRedirect : Boolean get() = this.code() in 300..399 val Response.isRedirect : Boolean get() = this.code in 300..399
/** /**
* Provides an extension to evaluation whether the response is a 4xx code * Provides an extension to evaluation whether the response is a 4xx code
*/ */
val Response.isClientError : Boolean get() = this.code() in 400..499 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 * 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 val Response.isServerError : Boolean get() = this.code in 500..999

View File

@ -2,7 +2,7 @@
## Requires ## Requires
* Kotlin 1.3.31 * Kotlin 1.3.41
* Gradle 4.9 * Gradle 4.9
## Build ## Build

View File

@ -7,7 +7,7 @@ wrapper {
} }
buildscript { buildscript {
ext.kotlin_version = '1.3.31' ext.kotlin_version = '1.3.41'
repositories { repositories {
mavenCentral() mavenCentral()
@ -32,7 +32,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.8.0" compile "com.squareup.moshi:moshi-kotlin:1.8.0"
compile "com.squareup.moshi:moshi-adapters:1.8.0" compile "com.squareup.moshi:moshi-adapters:1.8.0"
compile "com.squareup.okhttp3:okhttp:3.14.2" compile "com.squareup.okhttp3:okhttp:4.0.1"
compile "org.threeten:threetenbp:1.3.8" compile "org.threeten:threetenbp:1.3.8"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
} }

View File

@ -2,10 +2,12 @@ package org.openapitools.client.infrastructure
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.MediaType import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.ResponseBody import okhttp3.ResponseBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request import okhttp3.Request
import java.io.File import java.io.File
@ -29,8 +31,8 @@ open class ApiClient(val baseUrl: String) {
protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody =
when { when {
content is File -> RequestBody.create( content is File -> content.asRequestBody(
MediaType.parse(mediaType), content mediaType.toMediaTypeOrNull()
) )
mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> { mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> {
FormBody.Builder().apply { FormBody.Builder().apply {
@ -41,8 +43,8 @@ open class ApiClient(val baseUrl: String) {
} }
}.build() }.build()
} }
mediaType == JsonMediaType -> RequestBody.create( mediaType == JsonMediaType -> Serializer.moshi.adapter(T::class.java).toJson(content).toRequestBody(
MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content) mediaType.toMediaTypeOrNull()
) )
mediaType == XmlMediaType -> TODO("xml not currently supported.") mediaType == XmlMediaType -> TODO("xml not currently supported.")
// TODO: this should be extended with other serializers // TODO: this should be extended with other serializers
@ -64,7 +66,7 @@ open class ApiClient(val baseUrl: String) {
} }
protected inline fun <reified T: Any?> request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse<T?> { protected inline fun <reified T: Any?> request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse<T?> {
val httpUrl = HttpUrl.parse(baseUrl) ?: throw IllegalStateException("baseUrl is invalid.") val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.")
val url = httpUrl.newBuilder() val url = httpUrl.newBuilder()
.addPathSegments(requestConfig.path.trimStart('/')) .addPathSegments(requestConfig.path.trimStart('/'))
@ -114,29 +116,29 @@ open class ApiClient(val baseUrl: String) {
// TODO: handle specific mapping types. e.g. Map<int, Class<?>> // TODO: handle specific mapping types. e.g. Map<int, Class<?>>
when { when {
response.isRedirect -> return Redirection( response.isRedirect -> return Redirection(
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isInformational -> return Informational( response.isInformational -> return Informational(
response.message(), response.message,
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isSuccessful -> return Success( response.isSuccessful -> return Success(
responseBody(response.body(), accept), responseBody(response.body, accept),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isClientError -> return ClientError( response.isClientError -> return ClientError(
response.body()?.string(), response.body?.string(),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
else -> return ServerError( else -> return ServerError(
null, null,
response.body()?.string(), response.body?.string(),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
} }
} }

View File

@ -5,19 +5,19 @@ import okhttp3.Response
/** /**
* Provides an extension to evaluation whether the response is a 1xx code * Provides an extension to evaluation whether the response is a 1xx code
*/ */
val Response.isInformational : Boolean get() = this.code() in 100..199 val Response.isInformational : Boolean get() = this.code in 100..199
/** /**
* Provides an extension to evaluation whether the response is a 3xx code * Provides an extension to evaluation whether the response is a 3xx code
*/ */
val Response.isRedirect : Boolean get() = this.code() in 300..399 val Response.isRedirect : Boolean get() = this.code in 300..399
/** /**
* Provides an extension to evaluation whether the response is a 4xx code * Provides an extension to evaluation whether the response is a 4xx code
*/ */
val Response.isClientError : Boolean get() = this.code() in 400..499 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 * 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 val Response.isServerError : Boolean get() = this.code in 500..999

View File

@ -2,7 +2,7 @@
## Requires ## Requires
* Kotlin 1.3.31 * Kotlin 1.3.41
* Gradle 4.9 * Gradle 4.9
## Build ## Build

View File

@ -7,7 +7,7 @@ wrapper {
} }
buildscript { buildscript {
ext.kotlin_version = '1.3.31' ext.kotlin_version = '1.3.41'
repositories { repositories {
mavenCentral() mavenCentral()
@ -32,6 +32,6 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.8.0" compile "com.squareup.moshi:moshi-kotlin:1.8.0"
compile "com.squareup.moshi:moshi-adapters:1.8.0" compile "com.squareup.moshi:moshi-adapters:1.8.0"
compile "com.squareup.okhttp3:okhttp:3.14.2" compile "com.squareup.okhttp3:okhttp:4.0.1"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
} }

View File

@ -2,10 +2,12 @@ package org.openapitools.client.infrastructure
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.MediaType import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.ResponseBody import okhttp3.ResponseBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request import okhttp3.Request
import java.io.File import java.io.File
@ -29,8 +31,8 @@ open class ApiClient(val baseUrl: String) {
protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody =
when { when {
content is File -> RequestBody.create( content is File -> content.asRequestBody(
MediaType.parse(mediaType), content mediaType.toMediaTypeOrNull()
) )
mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> { mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> {
FormBody.Builder().apply { FormBody.Builder().apply {
@ -41,8 +43,8 @@ open class ApiClient(val baseUrl: String) {
} }
}.build() }.build()
} }
mediaType == JsonMediaType -> RequestBody.create( mediaType == JsonMediaType -> Serializer.moshi.adapter(T::class.java).toJson(content).toRequestBody(
MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content) mediaType.toMediaTypeOrNull()
) )
mediaType == XmlMediaType -> TODO("xml not currently supported.") mediaType == XmlMediaType -> TODO("xml not currently supported.")
// TODO: this should be extended with other serializers // TODO: this should be extended with other serializers
@ -64,7 +66,7 @@ open class ApiClient(val baseUrl: String) {
} }
protected inline fun <reified T: Any?> request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse<T?> { protected inline fun <reified T: Any?> request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse<T?> {
val httpUrl = HttpUrl.parse(baseUrl) ?: throw IllegalStateException("baseUrl is invalid.") val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.")
val url = httpUrl.newBuilder() val url = httpUrl.newBuilder()
.addPathSegments(requestConfig.path.trimStart('/')) .addPathSegments(requestConfig.path.trimStart('/'))
@ -114,29 +116,29 @@ open class ApiClient(val baseUrl: String) {
// TODO: handle specific mapping types. e.g. Map<int, Class<?>> // TODO: handle specific mapping types. e.g. Map<int, Class<?>>
when { when {
response.isRedirect -> return Redirection( response.isRedirect -> return Redirection(
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isInformational -> return Informational( response.isInformational -> return Informational(
response.message(), response.message,
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isSuccessful -> return Success( response.isSuccessful -> return Success(
responseBody(response.body(), accept), responseBody(response.body, accept),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
response.isClientError -> return ClientError( response.isClientError -> return ClientError(
response.body()?.string(), response.body?.string(),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
else -> return ServerError( else -> return ServerError(
null, null,
response.body()?.string(), response.body?.string(),
response.code(), response.code,
response.headers().toMultimap() response.headers.toMultimap()
) )
} }
} }

View File

@ -5,19 +5,19 @@ import okhttp3.Response
/** /**
* Provides an extension to evaluation whether the response is a 1xx code * Provides an extension to evaluation whether the response is a 1xx code
*/ */
val Response.isInformational : Boolean get() = this.code() in 100..199 val Response.isInformational : Boolean get() = this.code in 100..199
/** /**
* Provides an extension to evaluation whether the response is a 3xx code * Provides an extension to evaluation whether the response is a 3xx code
*/ */
val Response.isRedirect : Boolean get() = this.code() in 300..399 val Response.isRedirect : Boolean get() = this.code in 300..399
/** /**
* Provides an extension to evaluation whether the response is a 4xx code * Provides an extension to evaluation whether the response is a 4xx code
*/ */
val Response.isClientError : Boolean get() = this.code() in 400..499 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 * 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 val Response.isServerError : Boolean get() = this.code in 500..999