1.1.1
Netty, Client
Android, Multiplatform
HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer()
}
defaultRequest {
accept(ContentType.Application.Json)
contentType(ContentType.Application.Json)
url {
port = instance(Http.Tags.PORT)
host = instance(Http.Tags.HOST)
protocol = URLProtocol.HTTP
}
}
}
val call = client.call {
method = HttpMethod.Get
url { path("registration", "available", handle.value) }
}
2019-01-06 18:04:23.959 10001-10001/io.sellmair.link E/AndroidRuntime: FATAL EXCEPTION: main
Process: io.sellmair.link, PID: 10001
kotlinx.serialization.SerializationException: Can't locate argument-less serializer for class io.ktor.client.utils.EmptyContent. For generic classes, such as lists, please provide serializer explicitly.
at kotlinx.serialization.PlatformUtilsKt.serializer(PlatformUtils.kt:28)
at io.ktor.client.features.json.serializer.KotlinxSerializer.lookupSerializerByData(KotlinxSerializer.kt:91)
at io.ktor.client.features.json.serializer.KotlinxSerializer.write(KotlinxSerializer.kt:67)
at io.ktor.client.features.json.JsonFeature$Feature$install$1.invokeSuspend(JsonFeature.kt:56)
at io.ktor.client.features.json.JsonFeature$Feature$install$1.invoke(Unknown Source:12)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:24)
at io.ktor.client.HttpClient.execute(HttpClient.kt:151)
at io.ktor.client.call.HttpClientCallKt.call(HttpClientCall.kt:80)
at io.sellmair.link.backend.registration.internal.ApiRegistrationService.isHandleAvailable(ApiRegistrationService.kt:27)
at io.sellmair.link.backend.registration.internal.OwnerRegistrationFunctions$setHandle$1.invokeSuspend(OwnerRegistrationFunctions.kt:51)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
val call = client.call {
method = HttpMethod.Get
body = ""
url { path("registration", "available", handle.value) }
}
Still sends a post request to the server.
Ktor server side logging:
18:06:44.554 [nettyCallPool-4-2] DEBUG ktor.application - Unhandled: POST - /registration/available/b
Hi @sellmair, it looks like the side effect from HttpUrlConnection: the request type automatically changes to post depends on body configuration.
Could you reproduce it with OkHttp engine?
I noticed a similar effect which could explain the Exception, but the post change:
The JsonFeature only takes into account the Content-Type of the request, whether it should serialize the payload or not.
If the payload is already instance of OutgoingContent (like EmptyContent) this does not make any sense and will fail with the exception above. (see here)
I think it's totally valid to have another guard to check the payload instance here. Something like:
if (payload is OutgoingContent) {
return@intercept
}
Not sure if this solves your problem, I have written the following workaround
class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate {
override fun write(data: Any): OutgoingContent {
if (data is OutgoingContent) {
return data
}
return delegate.write(data)
}
}
fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this)
val client = HttpClient(OkHttp) {
install(JsonFeature) {
serializer = KotlinxSerializer().ignoreOutgoingContent()
}
}
Most helpful comment
I noticed a similar effect which could explain the
Exception, but the post change:The
JsonFeatureonly takes into account theContent-Typeof the request, whether it should serialize the payload or not.If the payload is already instance of
OutgoingContent(likeEmptyContent) this does not make any sense and will fail with the exception above. (see here)I think it's totally valid to have another guard to check the payload instance here. Something like:
Not sure if this solves your problem, I have written the following workaround