Skip to content

Commit

Permalink
[kotlin][client] fix temp file name and remove old deprecated jvm-okh…
Browse files Browse the repository at this point in the history
…ttp3 (#19064)

* [kotlin][client] fix temp file name and remove old deprecated jvm-okhttp3

* [kotlin][client] fix temp file name and remove old deprecated jvm-okhttp3

* [kotlin][client] fix temp file name and remove old deprecated jvm-okhttp3
  • Loading branch information
4brunu committed Jul 3, 2024
1 parent ff2e173 commit 21ad242
Show file tree
Hide file tree
Showing 26 changed files with 926 additions and 267 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,6 @@ dependencies {
implementation "io.ktor:ktor-serialization-jackson:$ktor_version"
{{/jackson}}
{{/jvm-ktor}}
{{#jvm-okhttp3}}
implementation "com.squareup.okhttp3:okhttp:3.14.9"
{{/jvm-okhttp3}}
{{#jvm-okhttp4}}
implementation "com.squareup.okhttp3:okhttp:4.12.0"
{{/jvm-okhttp4}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,6 @@ import {{packageName}}.infrastructure.toMultiValue
{{/operation}}

private fun encodeURIComponent(uriComponent: kotlin.String): kotlin.String =
HttpUrl.Builder().scheme("http").host("localhost").addPathSegment(uriComponent).build().encodedPathSegments{{#jvm-okhttp3}}(){{/jvm-okhttp3}}[0]
HttpUrl.Builder().scheme("http").host("localhost").addPathSegment(uriComponent).build().encodedPathSegments[0]
}
{{/operations}}
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,19 @@ import android.os.Build
{{/supportAndroidApiLevel25AndBelow}}
import okhttp3.OkHttpClient
import okhttp3.RequestBody
{{#jvm-okhttp3}}
import okhttp3.MediaType
{{/jvm-okhttp3}}
{{#jvm-okhttp4}}
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
{{/jvm-okhttp4}}
import okhttp3.FormBody
{{#jvm-okhttp3}}
import okhttp3.HttpUrl
{{/jvm-okhttp3}}
{{#jvm-okhttp4}}
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
{{/jvm-okhttp4}}
import okhttp3.ResponseBody
{{#jvm-okhttp4}}
import okhttp3.MediaType.Companion.toMediaTypeOrNull
{{/jvm-okhttp4}}
import okhttp3.Request
import okhttp3.Headers
{{#jvm-okhttp4}}
import okhttp3.Headers.Companion.toHeaders
{{/jvm-okhttp4}}
import okhttp3.MultipartBody
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Response
{{#jvm-okhttp3}}
import okhttp3.internal.Util.EMPTY_REQUEST
{{/jvm-okhttp3}}
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
Expand All @@ -48,6 +31,7 @@ import java.time.OffsetDateTime
import java.time.OffsetTime
{{/threetenbp}}
import java.util.Locale
import java.util.regex.Pattern
{{#useCoroutines}}
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
Expand All @@ -74,9 +58,7 @@ import com.fasterxml.jackson.core.type.TypeReference
import com.squareup.moshi.adapter
{{/moshi}}

{{#jvm-okhttp4}}
{{#nonPublicApi}}internal {{/nonPublicApi}} val EMPTY_REQUEST: RequestBody = ByteArray(0).toRequestBody()
{{/jvm-okhttp4}}
{{#nonPublicApi}}internal {{/nonPublicApi}}val EMPTY_REQUEST: RequestBody = ByteArray(0).toRequestBody()

{{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClient) {
{{#nonPublicApi}}internal {{/nonPublicApi}}companion object {
Expand Down Expand Up @@ -118,12 +100,7 @@ import com.squareup.moshi.adapter

protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when {
{{#jvm-okhttp3}}
content is File -> RequestBody.create(MediaType.parse(mediaType ?: guessContentTypeFromFile(content)), content)
{{/jvm-okhttp3}}
{{#jvm-okhttp4}}
content is File -> content.asRequestBody((mediaType ?: guessContentTypeFromFile(content)).toMediaTypeOrNull())
{{/jvm-okhttp4}}
mediaType == FormDataMediaType ->
MultipartBody.Builder()
.setType(MultipartBody.FORM)
Expand All @@ -134,35 +111,18 @@ import com.squareup.moshi.adapter
if (part.body is File) {
val partHeaders = part.headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"")
{{#jvm-okhttp3}}
val fileMediaType = MediaType.parse(guessContentTypeFromFile(part.body))
addPart(
Headers.of(partHeaders),
RequestBody.create(fileMediaType, part.body)
)
{{/jvm-okhttp3}}
{{#jvm-okhttp4}}
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
part.body.asRequestBody(fileMediaType)
)
{{/jvm-okhttp4}}
} else {
val partHeaders = part.headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
{{#jvm-okhttp3}}
addPart(
Headers.of(partHeaders),
RequestBody.create(null, parameterToString(part.body))
)
{{/jvm-okhttp3}}
{{#jvm-okhttp4}}
addPart(
partHeaders.toHeaders(),
parameterToString(part.body).toRequestBody(null)
)
{{/jvm-okhttp4}}
}
}
}.build()
Expand All @@ -176,27 +136,6 @@ import com.squareup.moshi.adapter
}.build()
}
mediaType == null || mediaType.startsWith("application/") && mediaType.endsWith("json") ->
{{#jvm-okhttp3}}
if (content == null) {
EMPTY_REQUEST
} else {
RequestBody.create(
{{#moshi}}
MediaType.parse(mediaType ?: JsonMediaType), Serializer.moshi.adapter(T::class.java).toJson(content)
{{/moshi}}
{{#gson}}
MediaType.parse(mediaType ?: JsonMediaType), Serializer.gson.toJson(content, T::class.java)
{{/gson}}
{{#jackson}}
MediaType.parse(mediaType ?: JsonMediaType), Serializer.jacksonObjectMapper.writeValueAsString(content)
{{/jackson}}
{{#kotlinx_serialization}}
MediaType.parse(mediaType ?: JsonMediaType), Serializer.kotlinxSerializationJson.encodeToString(content)
{{/kotlinx_serialization}}
)
}
{{/jvm-okhttp3}}
{{#jvm-okhttp4}}
if (content == null) {
EMPTY_REQUEST
} else {
Expand All @@ -214,38 +153,70 @@ import com.squareup.moshi.adapter
{{/kotlinx_serialization}}
.toRequestBody((mediaType ?: JsonMediaType).toMediaTypeOrNull())
}
{{/jvm-okhttp4}}
mediaType == XmlMediaType -> throw UnsupportedOperationException("xml not currently supported.")
mediaType == OctetMediaType && content is ByteArray ->
{{#jvm-okhttp3}}
RequestBody.create(MediaType.parse(OctetMediaType), content)
{{/jvm-okhttp3}}
{{#jvm-okhttp4}}
content.toRequestBody(OctetMediaType.toMediaTypeOrNull())
{{/jvm-okhttp4}}
// TODO: this should be extended with other serializers
else -> throw UnsupportedOperationException("requestBody currently only supports JSON body, byte body and File body.")
}

{{#moshi}}
@OptIn(ExperimentalStdlibApi::class)
{{/moshi}}
protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? {
protected inline fun <reified T: Any?> responseBody(response: Response, mediaType: String? = JsonMediaType): T? {
val body = response.body
if(body == null) {
return null
}
if (T::class.java == File::class.java) {
// return tempFile
val contentDisposition = response.header("Content-Disposition")
val fileName = if (contentDisposition != null) {
// Get filename from the Content-Disposition header.
val pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?")
val matcher = pattern.matcher(contentDisposition)
if (matcher.find()) {
matcher.group(1)
?.replace(".*[/\\\\]", "")
?.replace(";", "")
} else {
null
}
} else {
null
}

var prefix: String?
val suffix: String?
if (fileName == null) {
prefix = "download"
suffix = ""
} else {
val pos = fileName.lastIndexOf(".")
if (pos == -1) {
prefix = fileName
suffix = null
} else {
prefix = fileName.substring(0, pos)
suffix = fileName.substring(pos)
}
// Files.createTempFile requires the prefix to be at least three characters long
if (prefix.length < 3) {
prefix = "download"
}
}

{{^supportAndroidApiLevel25AndBelow}}
// Attention: if you are developing an android app that supports API Level 25 and bellow, please check flag supportAndroidApiLevel25AndBelow in https://openapi-generator.tech/docs/generators/kotlin#config-options
val tempFile = java.nio.file.Files.createTempFile("tmp.{{packageName}}", null).toFile()
val tempFile = java.nio.file.Files.createTempFile(prefix, suffix).toFile()
{{/supportAndroidApiLevel25AndBelow}}
{{#supportAndroidApiLevel25AndBelow}}
val tempFile = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
java.nio.file.Files.createTempFile("tmp.net.medicineone.teleconsultationandroid.openapi.openapicommon", null).toFile()
java.nio.file.Files.createTempFile(prefix, suffix).toFile()
} else {
@Suppress("DEPRECATION")
createTempFile("tmp.net.medicineone.teleconsultationandroid.openapi.openapicommon", null)
createTempFile(prefix, suffix)
}
{{/supportAndroidApiLevel25AndBelow}}
tempFile.deleteOnExit()
Expand Down Expand Up @@ -337,12 +308,7 @@ import com.squareup.moshi.adapter
{{/hasAuthMethods}}

protected {{#useCoroutines}}suspend {{/useCoroutines}}inline fun <reified I, reified T: Any?> request(requestConfig: RequestConfig<I>): ApiResponse<T?> {
{{#jvm-okhttp3}}
val httpUrl = HttpUrl.parse(baseUrl) ?: throw IllegalStateException("baseUrl is invalid.")
{{/jvm-okhttp3}}
{{#jvm-okhttp4}}
val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.")
{{/jvm-okhttp4}}
{{#hasAuthMethods}}

// take authMethod from operation
Expand Down Expand Up @@ -416,30 +382,30 @@ import com.squareup.moshi.adapter
return response.use {
when {
it.isRedirect -> Redirection(
it.code{{#jvm-okhttp3}}(){{/jvm-okhttp3}},
it.headers{{#jvm-okhttp3}}(){{/jvm-okhttp3}}.toMultimap()
it.code,
it.headers.toMultimap()
)
it.isInformational -> Informational(
it.message{{#jvm-okhttp3}}(){{/jvm-okhttp3}},
it.code{{#jvm-okhttp3}}(){{/jvm-okhttp3}},
it.headers{{#jvm-okhttp3}}(){{/jvm-okhttp3}}.toMultimap()
it.message,
it.code,
it.headers.toMultimap()
)
it.isSuccessful -> Success(
responseBody(it.body{{#jvm-okhttp3}}(){{/jvm-okhttp3}}, accept),
it.code{{#jvm-okhttp3}}(){{/jvm-okhttp3}},
it.headers{{#jvm-okhttp3}}(){{/jvm-okhttp3}}.toMultimap()
responseBody(it, accept),
it.code,
it.headers.toMultimap()
)
it.isClientError -> ClientError(
it.message{{#jvm-okhttp3}}(){{/jvm-okhttp3}},
it.body{{#jvm-okhttp3}}(){{/jvm-okhttp3}}?.string(),
it.code{{#jvm-okhttp3}}(){{/jvm-okhttp3}},
it.headers{{#jvm-okhttp3}}(){{/jvm-okhttp3}}.toMultimap()
it.message,
it.body?.string(),
it.code,
it.headers.toMultimap()
)
else -> ServerError(
it.message{{#jvm-okhttp3}}(){{/jvm-okhttp3}},
it.body{{#jvm-okhttp3}}(){{/jvm-okhttp3}}?.string(),
it.code{{#jvm-okhttp3}}(){{/jvm-okhttp3}},
it.headers{{#jvm-okhttp3}}(){{/jvm-okhttp3}}.toMultimap()
it.message,
it.body?.string(),
it.code,
it.headers.toMultimap()
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ import okhttp3.Response
/**
* Provides an extension to evaluation whether the response is a 1xx code
*/
{{#nonPublicApi}}internal {{/nonPublicApi}}val Response.isInformational : Boolean get() = this.code{{#jvm-okhttp3}}(){{/jvm-okhttp3}} in 100..199
{{#nonPublicApi}}internal {{/nonPublicApi}}val Response.isInformational : Boolean get() = this.code in 100..199

/**
* Provides an extension to evaluation whether the response is a 3xx code
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
{{#nonPublicApi}}internal {{/nonPublicApi}}val Response.isRedirect : Boolean get() = this.code{{#jvm-okhttp3}}(){{/jvm-okhttp3}} in 300..399
{{#nonPublicApi}}internal {{/nonPublicApi}}val Response.isRedirect : Boolean get() = this.code in 300..399

/**
* Provides an extension to evaluation whether the response is a 4xx code
*/
{{#nonPublicApi}}internal {{/nonPublicApi}}val Response.isClientError : Boolean get() = this.code{{#jvm-okhttp3}}(){{/jvm-okhttp3}} in 400..499
{{#nonPublicApi}}internal {{/nonPublicApi}}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
*/
{{#nonPublicApi}}internal {{/nonPublicApi}}val Response.isServerError : Boolean get() = this.code{{#jvm-okhttp3}}(){{/jvm-okhttp3}} in 500..999
{{#nonPublicApi}}internal {{/nonPublicApi}}val Response.isServerError : Boolean get() = this.code in 500..999
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ import java.time.LocalTime
import java.time.OffsetDateTime
import java.time.OffsetTime
import java.util.Locale
import java.util.regex.Pattern
import com.squareup.moshi.adapter

val EMPTY_REQUEST: RequestBody = ByteArray(0).toRequestBody()
val EMPTY_REQUEST: RequestBody = ByteArray(0).toRequestBody()

open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClient) {
companion object {
Expand Down Expand Up @@ -120,14 +121,52 @@ open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClie
}

@OptIn(ExperimentalStdlibApi::class)
protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? {
protected inline fun <reified T: Any?> responseBody(response: Response, mediaType: String? = JsonMediaType): T? {
val body = response.body
if(body == null) {
return null
}
if (T::class.java == File::class.java) {
// return tempFile
val contentDisposition = response.header("Content-Disposition")

val fileName = if (contentDisposition != null) {
// Get filename from the Content-Disposition header.
val pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?")
val matcher = pattern.matcher(contentDisposition)
if (matcher.find()) {
matcher.group(1)
?.replace(".*[/\\\\]", "")
?.replace(";", "")
} else {
null
}
} else {
null
}

var prefix: String?
val suffix: String?
if (fileName == null) {
prefix = "download"
suffix = ""
} else {
val pos = fileName.lastIndexOf(".")
if (pos == -1) {
prefix = fileName
suffix = null
} else {
prefix = fileName.substring(0, pos)
suffix = fileName.substring(pos)
}
// Files.createTempFile requires the prefix to be at least three characters long
if (prefix.length < 3) {
prefix = "download"
}
}

// Attention: if you are developing an android app that supports API Level 25 and bellow, please check flag supportAndroidApiLevel25AndBelow in https://openapi-generator.tech/docs/generators/kotlin#config-options
val tempFile = java.nio.file.Files.createTempFile("tmp.org.openapitools.client", null).toFile()
val tempFile = java.nio.file.Files.createTempFile(prefix, suffix).toFile()
tempFile.deleteOnExit()
body.byteStream().use { inputStream ->
tempFile.outputStream().use { tempFileOutputStream ->
Expand Down Expand Up @@ -214,7 +253,7 @@ open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClie
it.headers.toMultimap()
)
it.isSuccessful -> Success(
responseBody(it.body, accept),
responseBody(it, accept),
it.code,
it.headers.toMultimap()
)
Expand Down
Loading

0 comments on commit 21ad242

Please sign in to comment.