Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Post request body serialization doesn't work #202

Closed
alapshin opened this issue Mar 15, 2023 · 10 comments · Fixed by #204
Closed

[Bug]: Post request body serialization doesn't work #202

alapshin opened this issue Mar 15, 2023 · 10 comments · Fixed by #204
Assignees
Labels
bug Something isn't working

Comments

@alapshin
Copy link

alapshin commented Mar 15, 2023

Ktorfit version

1.0.0

What happened and how can we reproduce this issue?

Sample repo
https://github.com/alapshin/multiplayground/tree/aa09943fb7cf180ac57a28e8c9db95874da9f0b6

See LoginComponent class.
There are two implementation of LoginService interface. One generated by Ktorfit (enabled by default) and one written by hand using Ktor directly (commented out).

When sample app is launched and Login button is pressed login request is sent using LoginService.

When LoginService implementation generated by Ktorfit is used post request body serialization fails with following stacktrace

FATAL EXCEPTION: main
Process: com.example.multiplayground.android, PID: 3824
kotlinx.serialization.SerializationException: Serializer for class 'Any' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
	at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:92)
	at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:207)
	at kotlinx.serialization.SerializersKt.serializer(Unknown Source:1)
	at io.ktor.serialization.kotlinx.SerializerLookupKt.serializerFromTypeInfo(SerializerLookup.kt:24)
	at io.ktor.serialization.kotlinx.KotlinxSerializationBase.serialize$ktor_serialization_kotlinx(KotlinxSerializationBase.kt:20)
	at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.serializeNullable(KotlinxSerializationConverter.kt:54)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation.convertRequest$ktor_client_content_negotiation(ContentNegotiation.kt:180)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$1.invokeSuspend(ContentNegotiation.kt:251)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$1.invoke(Unknown Source:11)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$1.invoke(Unknown Source:4)
	at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80)
	at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
	at io.ktor.util.pipeline.DebugPipelineContext.proceedWith(DebugPipelineContext.kt:42)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invokeSuspend(HttpCallValidator.kt:130)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(Unknown Source:13)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(Unknown Source:4)
	at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80)
	at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invokeSuspend(HttpRequestLifecycle.kt:38)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(Unknown Source:11)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(Unknown Source:4)
	at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80)
	at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
	at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
	at io.ktor.client.HttpClient.execute$ktor_client_core(HttpClient.kt:191)
	at io.ktor.client.statement.HttpStatement.executeUnsafe(HttpStatement.kt:108)
	at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:47)
	at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:62)
	at de.jensklingenberg.ktorfit.internal.KtorfitClient.suspendRequest(KtorfitClient.kt:367)
	at com.alapshin.multiplayground.login.data._LoginServiceImpl.login(_LoginServiceImpl.kt:22)
	at com.alapshin.multiplayground.login.data.LoginManagerImpl.login(LoginManagerImpl.kt:10)
	at com.alapshin.multiplayground.login.domain.LoginStoreFactory$ExecutorImpl$executeIntent$1$1.invokeSuspend(LoginStoreFactory.kt:58)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)

But if I switch implementation to one wirtten by hand then request post body is serialized correctly.

HttpClient configuration is identical in both cases (see NetworkComponent). It seems that for some reasons Ktorfit doesn't set correct bodyType on HttpRequest but I can't figure why it happens.

What did you expect to happen?

I expect implementation generated by Ktorfit serialize post body correctly.

Is there anything else we need to know about?

No response

@alapshin alapshin added the bug Something isn't working label Mar 15, 2023
@alapshin alapshin changed the title [Bug]: Post request body type is not detected [Bug]: Post request body serialization doesn't work Mar 15, 2023
alapshin added a commit to alapshin/wildpetproject that referenced this issue Mar 15, 2023
@ahmadmssm
Copy link

I'm facing the same issue.

@ahmadmssm
Copy link

@Foso

@Foso
Copy link
Owner

Foso commented Mar 16, 2023

Thank you for the bug report

@Foso Foso self-assigned this Mar 16, 2023
Foso added a commit that referenced this issue Mar 16, 2023
Foso added a commit that referenced this issue Mar 16, 2023
@Foso Foso linked a pull request Mar 16, 2023 that will close this issue
2 tasks
@Foso
Copy link
Owner

Foso commented Mar 16, 2023

I fixed it, i'm planning to release a new version on the weekend

@Foso Foso closed this as completed in #204 Mar 16, 2023
@ahmadmssm
Copy link

Do you expect to have a new release soon ?

@ahmadmssm
Copy link

I found that if you set the body as a string, it would work, but with data classes, it fails, maybe the inferred type is being lost for some reason?!

@Foso
Copy link
Owner

Foso commented Mar 24, 2023

Have you tried it with 1.0.1 ?

@ahmadmssm
Copy link

Just tried with v1.0.1 and I can see that the issue is now fixed.
Thank you.

@terrakok
Copy link

terrakok commented Feb 9, 2025

ktorfit = "2.2.0"
Kotlin Multiplatform project.

@POST("api/v1/statuses")
    suspend fun createPost(
        @Body createPostDto: CreatePostDto
    ): Call<PostDto>

@Serializable
data class CreatePostDto(...)

I receive an error

java.lang.IllegalStateException: Fail to prepare request body for sending. 
The body type is: class com.[package].CreatePostDto (Kotlin reflection is not available), with Content-Type: null.

If you expect serialized body, please check that you have installed the corresponding plugin(like `ContentNegotiation`) and set `Content-Type` header.

The content negotiation plugin is installed:

HttpClient {
        install(ContentNegotiation) { json(json) }
}

@terrakok
Copy link

terrakok commented Feb 9, 2025

It works only if I convert the body object to JSON and add a content-type header

@Headers("Content-Type: application/json")
@POST("api/v1/statuses")
suspend fun createPost(
    @Body createPostDto: String
): Call<PostDto>

A similar problem is here: https://stackoverflow.com/questions/75672624/is-it-possible-to-use-a-serializable-data-class-as-post-request-body-in-ktorfit

terrakok added a commit to terrakok/pixelix that referenced this issue Feb 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants