androidkotlingradleserialization

SerializationException: Serializer for class 'QuoteResponse' is not found


I am trying to show quote on my app via an api. I have updated all the dependencies, plugins and libraries. I tried with a dummy api, the result was getting updated in the app then I tried with another quote api, there i found that some issue with the api but not in my code. But when I am using this api, I am facing this error -

Error fetching quote                                                                                           
kotlinx.serialization.SerializationException: Serializer for class 'QuoteResponse' 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:90 undefined)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:299 undefined)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source:1)
at io.ktor.serialization.kotlinx.SerializerLookupKt.serializerForTypeInfo(SerializerLookup.kt:29 undefined)
at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:77 undefined)
at io.ktor.serialization.ContentConverterKt$deserialize$inlined$map$1$2.emit(Emitters.kt:224 undefined)
at kotlinx.coroutines.flow.FlowKt__BuildersKt$asFlow$inlined$unsafeFlow$3.collect(SafeCollector.common.kt:116 undefined)
at io.ktor.serialization.ContentConverterKt$deserialize$inlined$map$1.collect(SafeCollector.common.kt:113 undefined)
at kotlinx.coroutines.flow.FlowKt__ReduceKt.firstOrNull(Reduce.kt:243 undefined)
at kotlinx.coroutines.flow.FlowKt.firstOrNull(Unknown Source:1)
at io.ktor.serialization.ContentConverterKt.deserialize(ContentConverter.kt:123 undefined)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiation.convertResponse$ktor_client_content_negotiation(ContentNegotiation.kt:230 undefined)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invokeSuspend(ContentNegotiation.kt:262 undefined)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invoke(Unknown Source:13)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invoke(Unknown Source:6)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78 undefined)
at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:177 undefined)
at io.ktor.client.HttpClient$4.invoke(Unknown Source:11)
at io.ktor.client.HttpClient$4.invoke(Unknown Source:6)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:88 undefined)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:142 undefined)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(Unknown Source:13)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(Unknown Source:6)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98 undefined)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77 undefined)
at io.ktor.client.call.HttpClientCall.bodyNullable(HttpClientCall.kt:89 undefined)
at com.satpati.stutu.externalapi.QuoteApiKt$fetchQuote$2.invokeSuspend(QuoteApi.kt:50 undefined)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33 undefined)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108 undefined)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115 undefined)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103 undefined)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584 undefined)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793 undefined)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697 undefined)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684 undefined)

I have added this in my project level gradle plugins -

alias(libs.plugins.kotlin.serialization)

i have added this in my app level gradle dependencies -

implementation(libs.ktor.client.core)
implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.kotlinx.serialization.json)

this is my toml file -

[versions]
ktor = "2.3.4"
kotlinx-serialization = "1.7.3"

[libraries]
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }

[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }

this is my data class -

@Serializable
data class QuoteResponse(
    val id: Int,
    val quote: String,
    val author: String
)

this is my quoteApi -

val client = HttpClient(CIO) {
    install(ContentNegotiation) {
        json()
    }
}

suspend fun fetchQuote(): String {
    return withContext(Dispatchers.IO) {
        try {
            val url = "https://dummyjson.com/quotes/random"
            val response = client.get(url)

            // Handle non-successful responses (like 429)
            if (!response.status.isSuccess()) {
                Log.e("QuoteFetch", "HTTP Error: ${response.status}")
                return@withContext "API limit reached. Try again later."
            }
            val quoteResponse: QuoteResponse = response.body()
            quoteResponse.quote
        } catch (e: Exception) {
            Log.e("QuoteFetch", "Error fetching quote", e)
            "Unable to fetch quote."
         }
    }
}

Can you please help me in finding what am I missing here.


Solution

  • You didn't apply the serialization plugin correctly.

    You need to add this to the build gradle file of the module where you want to access serialization:

    alias(libs.plugins.kotlin.serialization)
    

    And in your project build gradle file you should only declare the plugin but not apply it, like this:

    alias(libs.plugins.kotlin.serialization) apply false
    

    After a Gradle sync everything should work now.


    Unrelated, but: