Thread
#serialization
    v

    Vivek Modi

    5 months ago
    Hey Guys, I am using sealed class to handle api response. I am trying some code but getting some error. Can somone suggest me? Please see in the thread.
    2022-04-22 10:50:28.614 8365-8365/com.example.app.dev E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.example.app.dev, PID: 8365
        kotlinx.serialization.json.internal.JsonDecodingException: Polymorphic serializer was not found for missing class discriminator ('null')
        JSON input: .....pping":false,"phonePrefix":"263","isCurrentCountry":false}]}
            at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:24)
            at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:32)
            at kotlinx.serialization.json.internal.PolymorphicKt.throwSerializerNotFound(Polymorphic.kt:76)
            at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:66)
            at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:36)
            at kotlinx.serialization.json.Json.decodeFromString(Json.kt:100)
            at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:55)
            at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invokeSuspend(ContentNegotiation.kt:135)
            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:123)
            at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
            at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:170)
            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:123)
            at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
            at io.ktor.client.plugins.logging.Logging$setupResponseLogging$2.invokeSuspend(Logging.kt:167)
            at io.ktor.client.plugins.logging.Logging$setupResponseLogging$2.invoke(Unknown Source:11)
            at io.ktor.client.plugins.logging.Logging$setupResponseLogging$2.invoke(Unknown Source:6)
            at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
            at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
            at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:91)
            at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:140)
            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:123)
            at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
            at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:101)
            at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
            at io.ktor.client.call.HttpClientCall.body(HttpClientCall.kt:87)
            at com.example.kotlinmultiplatformsharedmodule.KtorCountryApi.getCart(KtorCountryApi.kt:53)
            at com.example.kotlinmultiplatformsharedmodule.KtorCountryApi$getCart$1.invokeSuspend(Unknown Source:14)
            at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
            at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
            at android.os.Handler.handleCallback(Handler.java:938)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loopOnce(Looper.java:201)
            at android.os.Looper.loop(Looper.java:288)
            at android.app.ActivityThread.main(ActivityThread.java:7839)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
    actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) {
        config(this)
        install(Logging) {
            logger = Logger.SIMPLE
            level = LogLevel.BODY
        }
        install(ContentNegotiation) {
            json(Json {
                prettyPrint = true
                ignoreUnknownKeys = true
                explicitNulls = false
            })
        }
        engine {
            config {
                retryOnConnectionFailure(true)
                connectTimeout(30, TimeUnit.SECONDS)
                readTimeout(40, TimeUnit.SECONDS)
            }
        }
        defaultRequest {
            header("Client-Version", Platform().versionCode)
        }
        install(Auth) {
            bearer {
                loadTokens {
                    BearerTokens(tokenProvider.accessToken, "")
                }
                refreshTokens {
                    val response =
                        <http://client.post|client.post>("<https://shop-api.letsgetchecked-stg2.com/api/v1/session/refresh>") {
                            markAsRefreshTokenRequest()
                            contentType(ContentType.Application.Json)
                            setBody(KtorSessionCommand(tokenProvider.refreshToken))
                        }
                    if (response.status == HttpStatusCode.Unauthorized) {
                        null
                    } else {
                        val ktorLoginResponse = response.body<KtorLoginResponse>()
                        ktorLoginResponse.accessToken?.let { ktorAccessToken ->
                            ktorAccessToken.accessToken?.let { accessToken ->
                                ktorAccessToken.refreshToken?.let { refreshToken ->
                                    BearerTokens(accessToken, refreshToken)
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    import io.ktor.client.*
    import io.ktor.client.call.*
    import io.ktor.client.request.*
    import kotlinx.coroutines.flow.Flow
    import kotlinx.serialization.Serializable
    
    class KtorCountryApi(private val httpClient: HttpClient) {
        suspend fun getCart(): Flow<ApiResponse<KtorCountriesResponse>> {
            println("api call")
            return httpClient.get {
                url("<https://shop-api.example-stg2.com/api/v1/address/country>")
            }.body()
        }
    }
    
    @Serializable
    data class KtorCountriesResponse(
        val items: List<KtorCountry>? = null
    )
    
    @Serializable
    data class KtorCountry(
        val id: String? = null,
        val isCurrentCountry: Boolean? = null,
        var isoAlpha2Code: String? = null,
        var name: String? = null,
        var phonePrefix: String? = null,
        val usesPerAreaShipping: Boolean? = null
    )
    import kotlinx.serialization.Serializable
    
    sealed class ApiResponse<out T : Any> {
    
        data class Success<out T : Any>(
            val data: T?
        ) : ApiResponse<T>()
    
        data class Error(
            val exception: Throwable? = null,
            val responseCode: Int = -1
        ) : ApiResponse<Nothing>()
    
        fun handleResult(onSuccess: ((responseData: T?) -> Unit)?,onError: ((error: Error) -> Unit)?) {
            when (this) {
                is Success -> {
                    onSuccess?.invoke(this.data)
                }
                is Error -> {
                    onError?.invoke(this)
                }
            }
        }
    }
    
    @Serializable
    data class ErrorResponse(
        val errorCode: Int,
        val errorMessage: String
    )