Skip to content

Commit 298e7bb

Browse files
committed
Add fix for kotlinx serialisation issue
1 parent 4e1607e commit 298e7bb

28 files changed

Lines changed: 487 additions & 151 deletions

File tree

  • modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-okhttp/infrastructure
  • samples/client
    • echo_api/kotlin-jvm-okhttp/src/main/kotlin/org/openapitools/client/infrastructure
    • others
      • kotlin-integer-enum/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-jvm-okhttp-non-ascii-headers/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-jvm-okhttp-parameter-tests/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-jvm-okhttp-path-comments/src/main/kotlin/org/openapitools/client/infrastructure
    • petstore
      • kotlin-allOf-discriminator-kotlinx-serialization/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-allOf-discriminator/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-array-integer-enum/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-array-simple-string-jvm-okhttp4/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-bigdecimal-default-okhttp4/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-default-values-jvm-okhttp4/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-enum-default-value/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-explicit/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-gson/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-jackson/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-json-request-string/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-jvm-okhttp4-coroutines/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-kotlinx-datetime/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-modelMutable/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-moshi-codegen/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-name-parameter-mappings/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-nonpublic/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-nullable/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-string/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-threetenbp/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin-uppercase-enum/src/main/kotlin/org/openapitools/client/infrastructure
      • kotlin/src/main/kotlin/org/openapitools/client/infrastructure

modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -139,24 +139,15 @@ import com.squareup.moshi.adapter
139139
}
140140

141141
/**
142-
* Adds any type to a MultipartBody.Builder
143-
* Defined a helper in the requestBody method to not duplicate code
144-
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
142+
* Serializes a multipart body part based on its content type.
143+
* Uses JSON serialization for application/json content types, otherwise converts to string.
145144
*
146-
* @param name The field name to add in the request
147-
* @param headers The headers that are in the PartConfig
148-
* @param obj The field name to add in the request
149-
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
150-
* @see requestBody
145+
* @param obj The object to serialize
146+
* @param contentType The Content-Type header value, if any
147+
* @return The serialized string representation
151148
*/
152-
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
153-
val partContentType = headers["Content-Type"]
154-
val partMediaType = partContentType?.toMediaTypeOrNull()
155-
// Filter out Content-Type from headers as OkHttp requires it to be passed
156-
// separately via toRequestBody(mediaType), not in the headers map
157-
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
158-
("Content-Disposition" to "form-data; name=\"$name\"")
159-
val partBody = if (partContentType?.contains("json") == true) {
149+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
150+
return if (contentType?.contains("json") == true) {
160151
{{#moshi}}
161152
Serializer.moshi.adapter(Any::class.java).toJson(obj)
162153
{{/moshi}}
@@ -172,6 +163,27 @@ import com.squareup.moshi.adapter
172163
} else {
173164
parameterToString(obj)
174165
}
166+
}
167+
168+
/**
169+
* Adds any type to a MultipartBody.Builder
170+
* Defined a helper in the requestBody method to not duplicate code
171+
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
172+
*
173+
* @param name The field name to add in the request
174+
* @param headers The headers that are in the PartConfig
175+
* @param obj The field name to add in the request
176+
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
177+
* @see requestBody
178+
*/
179+
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
180+
val partContentType = headers["Content-Type"]
181+
val partMediaType = partContentType?.toMediaTypeOrNull()
182+
// Filter out Content-Type from headers as OkHttp requires it to be passed
183+
// separately via toRequestBody(mediaType), not in the headers map
184+
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
185+
("Content-Disposition" to "form-data; name=\"$name\"")
186+
val partBody = serializePartBody(obj, partContentType)
175187
addPart(
176188
partHeaders.toHeaders(),
177189
partBody.toRequestBody(partMediaType)

samples/client/echo_api/kotlin-jvm-okhttp/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
109109
)
110110
}
111111

112+
/**
113+
* Serializes a multipart body part based on its content type.
114+
* Uses JSON serialization for application/json content types, otherwise converts to string.
115+
*
116+
* @param obj The object to serialize
117+
* @param contentType The Content-Type header value, if any
118+
* @return The serialized string representation
119+
*/
120+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
121+
return if (contentType?.contains("json") == true) {
122+
Serializer.moshi.adapter(Any::class.java).toJson(obj)
123+
} else {
124+
parameterToString(obj)
125+
}
126+
}
127+
112128
/**
113129
* Adds any type to a MultipartBody.Builder
114130
* Defined a helper in the requestBody method to not duplicate code
@@ -127,11 +143,7 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
127143
// separately via toRequestBody(mediaType), not in the headers map
128144
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
129145
("Content-Disposition" to "form-data; name=\"$name\"")
130-
val partBody = if (partContentType?.contains("json") == true) {
131-
Serializer.moshi.adapter(Any::class.java).toJson(obj)
132-
} else {
133-
parameterToString(obj)
134-
}
146+
val partBody = serializePartBody(obj, partContentType)
135147
addPart(
136148
partHeaders.toHeaders(),
137149
partBody.toRequestBody(partMediaType)

samples/client/others/kotlin-integer-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
109109
)
110110
}
111111

112+
/**
113+
* Serializes a multipart body part based on its content type.
114+
* Uses JSON serialization for application/json content types, otherwise converts to string.
115+
*
116+
* @param obj The object to serialize
117+
* @param contentType The Content-Type header value, if any
118+
* @return The serialized string representation
119+
*/
120+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
121+
return if (contentType?.contains("json") == true) {
122+
Serializer.moshi.adapter(Any::class.java).toJson(obj)
123+
} else {
124+
parameterToString(obj)
125+
}
126+
}
127+
112128
/**
113129
* Adds any type to a MultipartBody.Builder
114130
* Defined a helper in the requestBody method to not duplicate code
@@ -127,11 +143,7 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
127143
// separately via toRequestBody(mediaType), not in the headers map
128144
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
129145
("Content-Disposition" to "form-data; name=\"$name\"")
130-
val partBody = if (partContentType?.contains("json") == true) {
131-
Serializer.moshi.adapter(Any::class.java).toJson(obj)
132-
} else {
133-
parameterToString(obj)
134-
}
146+
val partBody = serializePartBody(obj, partContentType)
135147
addPart(
136148
partHeaders.toHeaders(),
137149
partBody.toRequestBody(partMediaType)

samples/client/others/kotlin-jvm-okhttp-non-ascii-headers/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
109109
)
110110
}
111111

112+
/**
113+
* Serializes a multipart body part based on its content type.
114+
* Uses JSON serialization for application/json content types, otherwise converts to string.
115+
*
116+
* @param obj The object to serialize
117+
* @param contentType The Content-Type header value, if any
118+
* @return The serialized string representation
119+
*/
120+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
121+
return if (contentType?.contains("json") == true) {
122+
Serializer.moshi.adapter(Any::class.java).toJson(obj)
123+
} else {
124+
parameterToString(obj)
125+
}
126+
}
127+
112128
/**
113129
* Adds any type to a MultipartBody.Builder
114130
* Defined a helper in the requestBody method to not duplicate code
@@ -127,11 +143,7 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
127143
// separately via toRequestBody(mediaType), not in the headers map
128144
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
129145
("Content-Disposition" to "form-data; name=\"$name\"")
130-
val partBody = if (partContentType?.contains("json") == true) {
131-
Serializer.moshi.adapter(Any::class.java).toJson(obj)
132-
} else {
133-
parameterToString(obj)
134-
}
146+
val partBody = serializePartBody(obj, partContentType)
135147
addPart(
136148
partHeaders.toHeaders(),
137149
partBody.toRequestBody(partMediaType)

samples/client/others/kotlin-jvm-okhttp-parameter-tests/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
109109
)
110110
}
111111

112+
/**
113+
* Serializes a multipart body part based on its content type.
114+
* Uses JSON serialization for application/json content types, otherwise converts to string.
115+
*
116+
* @param obj The object to serialize
117+
* @param contentType The Content-Type header value, if any
118+
* @return The serialized string representation
119+
*/
120+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
121+
return if (contentType?.contains("json") == true) {
122+
Serializer.moshi.adapter(Any::class.java).toJson(obj)
123+
} else {
124+
parameterToString(obj)
125+
}
126+
}
127+
112128
/**
113129
* Adds any type to a MultipartBody.Builder
114130
* Defined a helper in the requestBody method to not duplicate code
@@ -127,11 +143,7 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
127143
// separately via toRequestBody(mediaType), not in the headers map
128144
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
129145
("Content-Disposition" to "form-data; name=\"$name\"")
130-
val partBody = if (partContentType?.contains("json") == true) {
131-
Serializer.moshi.adapter(Any::class.java).toJson(obj)
132-
} else {
133-
parameterToString(obj)
134-
}
146+
val partBody = serializePartBody(obj, partContentType)
135147
addPart(
136148
partHeaders.toHeaders(),
137149
partBody.toRequestBody(partMediaType)

samples/client/others/kotlin-jvm-okhttp-path-comments/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
109109
)
110110
}
111111

112+
/**
113+
* Serializes a multipart body part based on its content type.
114+
* Uses JSON serialization for application/json content types, otherwise converts to string.
115+
*
116+
* @param obj The object to serialize
117+
* @param contentType The Content-Type header value, if any
118+
* @return The serialized string representation
119+
*/
120+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
121+
return if (contentType?.contains("json") == true) {
122+
Serializer.moshi.adapter(Any::class.java).toJson(obj)
123+
} else {
124+
parameterToString(obj)
125+
}
126+
}
127+
112128
/**
113129
* Adds any type to a MultipartBody.Builder
114130
* Defined a helper in the requestBody method to not duplicate code
@@ -127,11 +143,7 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
127143
// separately via toRequestBody(mediaType), not in the headers map
128144
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
129145
("Content-Disposition" to "form-data; name=\"$name\"")
130-
val partBody = if (partContentType?.contains("json") == true) {
131-
Serializer.moshi.adapter(Any::class.java).toJson(obj)
132-
} else {
133-
parameterToString(obj)
134-
}
146+
val partBody = serializePartBody(obj, partContentType)
135147
addPart(
136148
partHeaders.toHeaders(),
137149
partBody.toRequestBody(partMediaType)

samples/client/petstore/kotlin-allOf-discriminator-kotlinx-serialization/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,22 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
110110
)
111111
}
112112

113+
/**
114+
* Serializes a multipart body part based on its content type.
115+
* Uses JSON serialization for application/json content types, otherwise converts to string.
116+
*
117+
* @param obj The object to serialize
118+
* @param contentType The Content-Type header value, if any
119+
* @return The serialized string representation
120+
*/
121+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
122+
return if (contentType?.contains("json") == true) {
123+
Serializer.kotlinxSerializationJson.encodeToString(obj)
124+
} else {
125+
parameterToString(obj)
126+
}
127+
}
128+
113129
/**
114130
* Adds any type to a MultipartBody.Builder
115131
* Defined a helper in the requestBody method to not duplicate code
@@ -128,11 +144,7 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
128144
// separately via toRequestBody(mediaType), not in the headers map
129145
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
130146
("Content-Disposition" to "form-data; name=\"$name\"")
131-
val partBody = if (partContentType?.contains("json") == true) {
132-
Serializer.kotlinxSerializationJson.encodeToString(obj)
133-
} else {
134-
parameterToString(obj)
135-
}
147+
val partBody = serializePartBody(obj, partContentType)
136148
addPart(
137149
partHeaders.toHeaders(),
138150
partBody.toRequestBody(partMediaType)

samples/client/petstore/kotlin-allOf-discriminator/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
109109
)
110110
}
111111

112+
/**
113+
* Serializes a multipart body part based on its content type.
114+
* Uses JSON serialization for application/json content types, otherwise converts to string.
115+
*
116+
* @param obj The object to serialize
117+
* @param contentType The Content-Type header value, if any
118+
* @return The serialized string representation
119+
*/
120+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
121+
return if (contentType?.contains("json") == true) {
122+
Serializer.moshi.adapter(Any::class.java).toJson(obj)
123+
} else {
124+
parameterToString(obj)
125+
}
126+
}
127+
112128
/**
113129
* Adds any type to a MultipartBody.Builder
114130
* Defined a helper in the requestBody method to not duplicate code
@@ -127,11 +143,7 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
127143
// separately via toRequestBody(mediaType), not in the headers map
128144
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
129145
("Content-Disposition" to "form-data; name=\"$name\"")
130-
val partBody = if (partContentType?.contains("json") == true) {
131-
Serializer.moshi.adapter(Any::class.java).toJson(obj)
132-
} else {
133-
parameterToString(obj)
134-
}
146+
val partBody = serializePartBody(obj, partContentType)
135147
addPart(
136148
partHeaders.toHeaders(),
137149
partBody.toRequestBody(partMediaType)

samples/client/petstore/kotlin-array-integer-enum/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
109109
)
110110
}
111111

112+
/**
113+
* Serializes a multipart body part based on its content type.
114+
* Uses JSON serialization for application/json content types, otherwise converts to string.
115+
*
116+
* @param obj The object to serialize
117+
* @param contentType The Content-Type header value, if any
118+
* @return The serialized string representation
119+
*/
120+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
121+
return if (contentType?.contains("json") == true) {
122+
Serializer.moshi.adapter(Any::class.java).toJson(obj)
123+
} else {
124+
parameterToString(obj)
125+
}
126+
}
127+
112128
/**
113129
* Adds any type to a MultipartBody.Builder
114130
* Defined a helper in the requestBody method to not duplicate code
@@ -127,11 +143,7 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
127143
// separately via toRequestBody(mediaType), not in the headers map
128144
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
129145
("Content-Disposition" to "form-data; name=\"$name\"")
130-
val partBody = if (partContentType?.contains("json") == true) {
131-
Serializer.moshi.adapter(Any::class.java).toJson(obj)
132-
} else {
133-
parameterToString(obj)
134-
}
146+
val partBody = serializePartBody(obj, partContentType)
135147
addPart(
136148
partHeaders.toHeaders(),
137149
partBody.toRequestBody(partMediaType)

samples/client/petstore/kotlin-array-simple-string-jvm-okhttp4/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
109109
)
110110
}
111111

112+
/**
113+
* Serializes a multipart body part based on its content type.
114+
* Uses JSON serialization for application/json content types, otherwise converts to string.
115+
*
116+
* @param obj The object to serialize
117+
* @param contentType The Content-Type header value, if any
118+
* @return The serialized string representation
119+
*/
120+
protected inline fun <reified T> serializePartBody(obj: T?, contentType: String?): String {
121+
return if (contentType?.contains("json") == true) {
122+
Serializer.moshi.adapter(Any::class.java).toJson(obj)
123+
} else {
124+
parameterToString(obj)
125+
}
126+
}
127+
112128
/**
113129
* Adds any type to a MultipartBody.Builder
114130
* Defined a helper in the requestBody method to not duplicate code
@@ -127,11 +143,7 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
127143
// separately via toRequestBody(mediaType), not in the headers map
128144
val partHeaders = headers.filterKeys { it != "Content-Type" }.toMutableMap() +
129145
("Content-Disposition" to "form-data; name=\"$name\"")
130-
val partBody = if (partContentType?.contains("json") == true) {
131-
Serializer.moshi.adapter(Any::class.java).toJson(obj)
132-
} else {
133-
parameterToString(obj)
134-
}
146+
val partBody = serializePartBody(obj, partContentType)
135147
addPart(
136148
partHeaders.toHeaders(),
137149
partBody.toRequestBody(partMediaType)

0 commit comments

Comments
 (0)