Foso / Ktorfit

HTTP client generator / KSP plugin for Kotlin Multiplatform (Android, iOS, Js, Jvm, Native, WasmJs)) using KSP and Ktor clients inspired by Retrofit https://foso.github.io/Ktorfit
https://foso.github.io/Ktorfit
Apache License 2.0
1.61k stars 43 forks source link

FlowConverterFacotry: java.util.NoSuchElementException: List is empty. #511

Open ahmadmssm opened 10 months ago

ahmadmssm commented 10 months ago

Ktorfit version

1.11.1

What happened and how can we reproduce this issue?

I didn't find the FlowConverterFactory in the last version as I previously reported, so I copied it from the Repo but when trying to parse any response it falls at this line val response = getResponse() with this error java.util.NoSuchElementException: List is empty.

What did you expect to happen?

The parsing to success as in the previous versions.

Is there anything else we need to know about?

No response

ahmadmssm commented 10 months ago

I rolled back to a previous build and both bugs were not reproducible.

ahmadmssm commented 10 months ago

The issue is here

  if (requestType.typeInfo.type == HttpResponse::class)
                            emit(getResponse())

if I add more than one response converter, it will jump automatically when I call getResponse() to the other response converter, if there is only one converter, then it will work as expected.

niyajali commented 3 weeks ago

Hi, I'm getting the same error on the release build whereas on debug build it's works fine.

ktorVersion = "3.0.0" ktorfit = "2.1.0" ktorfitKsp = "2.1.0-1.0.26"

Caused by: java.util.NoSuchElementException: List is empty.                                                                                 
    at kotlin.collections.CollectionsKt___CollectionsKt.first(_Collections.kt:221)                                                          
    at org.mifospay.core.network.utils.FlowConverterFactory$responseConverter$1.convert(FlowConverterFactory.kt:32)                         
    at org.mifospay.core.network.utils.FlowConverterFactory$responseConverter$1.convert(FlowConverterFactory.kt:30)                         
    at de.jensklingenberg.ktorfit.internal.KtorfitConverterHelper.request(KtorfitConverterHelper.kt:33)                                     
    at org.mifospay.core.network.services._ClientServiceImpl.getAccounts(_ClientServiceImpl.kt:148)                                         
    at org.mifospay.core.data.repositoryImp.SelfServiceRepositoryImpl.getActiveAccountsWithTransactions(SelfServiceRepositoryImpl.kt:139)   
    at org.mifospay.feature.home.HomeViewModel.<init>(HomeViewModel.kt:47)                                                                  
    at org.mifospay.feature.home.di.HomeModuleKt$HomeModule$lambda$0$$inlined$viewModelOf$default$1.invoke(ViewModelOf.kt:17)               
    at org.mifospay.feature.home.di.HomeModuleKt$HomeModule$lambda$0$$inlined$viewModelOf$default$1.invoke(ViewModelOf.kt:59) (Ask Gemini)  
    at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)                                                                 
ahmadmssm commented 3 weeks ago

@niyajali Try using the following combination together ktorVersion = "3.0.0" ktorfit = "2.1.0" ktorfitKsp = "2.0.21-1.0.25"

Foso commented 3 weeks ago

@niyajali Could be an issue with R8. What does your ConverterFactory look like?

niyajali commented 3 weeks ago

I'm using Ktorfit FlowConverterFactory

Foso commented 3 weeks ago

@niyajali So you are using exactly the same code as in here in your code? https://github.com/Foso/Ktorfit/blob/master/ktorfit-converters/flow/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/FlowConverterFactory.kt

I'm asking because based on the package name "org.mifospay.core.network.utils.FlowConverterFactory" you are using your own class and i have other way of knowing what the code in there looks like

niyajali commented 3 weeks ago

@Foso Yes I've copied exact same code, and also tried with ktorfit-flow-converter library and getting the same error on release build

niyajali commented 3 weeks ago
package org.mifospay.core.network.utils

import de.jensklingenberg.ktorfit.Ktorfit
import de.jensklingenberg.ktorfit.converter.Converter
import de.jensklingenberg.ktorfit.converter.KtorfitResult
import de.jensklingenberg.ktorfit.converter.TypeData
import io.ktor.client.call.body
import io.ktor.client.statement.HttpResponse
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

/**
 * Factory that enables the use of Flow<T> as return type
 */
public class FlowConverterFactory : Converter.Factory {
    override fun responseConverter(
        typeData: TypeData,
        ktorfit: Ktorfit,
    ): Converter.ResponseConverter<HttpResponse, *>? {
        if (typeData.typeInfo.type == Flow::class) {
            return object : Converter.ResponseConverter<HttpResponse, Flow<Any?>> {
                override fun convert(getResponse: suspend () -> HttpResponse): Flow<Any?> {
// Getting error on below line, somehow typeArgs is empty after applying progurd, so when we calling first() resulting NoSuchElementException
                    val requestType = typeData.typeArgs.first() 
                    return flow {
                        val response = getResponse()
                        if (requestType.typeInfo.type == HttpResponse::class) {
                            emit(response)
                        } else {
                            val convertedBody =
                                ktorfit.nextSuspendResponseConverter(
                                    this@FlowConverterFactory,
                                    typeData.typeArgs.first(),
                                )?.convert(KtorfitResult.Success(response))
                                    ?: response.body(typeData.typeArgs.first().typeInfo)
                            emit(convertedBody)
                        }
                    }
                }
            }
        }
        return null
    }
}