InsertKoinIO / koin-annotations

Koin Annotations - About Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform insert-koin.io
https://insert-koin.io
Apache License 2.0
162 stars 44 forks source link

DefinitonParameterException - No value found for type when using annotations #22

Closed jsiefers closed 2 years ago

jsiefers commented 2 years ago

Describe the bug After migrating from 'regular' implementation to annotations, I get the following exception (snippet):

org.koin.core.error.DefinitionParameterException: No value found for type 'com.example.myapp.domain.repository.MyRepository'
        at org.koin.ksp.generated.KoinDomainModuleGenKt$KoinDomainModuleModule$1$10.invoke(KoinDomainModuleGen.kt:17)
        at org.koin.ksp.generated.KoinDomainModuleGenKt$KoinDomainModuleModule$1$10.invoke(KoinDomainModuleGen.kt:14)
        at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:54)

Following the call stack in the debugger, leads me to the instantiation of my ViewModel. This project follows the principles of clean architecture and consists of multiple gradle modules (app, domain and data).

ViewModel (app module)

@KoinViewModel
class MyViewModel : ViewModel(), KoinComponent {

    private val myListUseCase: MyUseCase by inject()
    val myList: LiveData<List<Something>> by lazy {
        myListUseCase()
    }
}

Use case (domain module)

@Factory
class MyUseCase(
    @InjectedParam private val myRepository: MyRepository
) {
    operator fun invoke(): LiveData<List<Something>> =
        myRepository.loadList()
}

MyRepository (domain module)

interface MyRepository {
    fun loadList(): LiveData<List<Something>>
}

Implementation of MyRepository (data module)

@Single
internal class MyRepositoryImpl(
    @InjectedParam private val myDao: MyDao
) : BaseRepository(), DummyRepository {
    override fun loadList(): LiveData<List<Something>> {
        return myDao.loadList()
    }
}

Koin modules: (reside in their respective gradle modules, in the di subpackage)

@Module
@ComponentScan("com.example.myapp")
class KoinAppModule
@Module
@ComponentScan("com.example.myapp.domain")
class KoinDomainpModule
@Module
@ComponentScan("com.example.myapp.data")
class KoinDataModule
val customDataModule = module {
    single { Database.create() }
    single { get<Database>().myDao() }
}

Starting Koin:

startKoin {
    androidLogger()
    androidContext(this@MyApplicationClass)
    modules(
        KoinAppModule().module,
        KoinDomainModule().module,
        KoinDataModule().module,
        customDataModule
    )
}

Additional information:

Expected behavior All injected dependencies are resolved properly and no exception occurs

Koin project used and used version: koin-core and koin-android version: 3.2.0-beta-1 (api in domain module, on which the other modules have a dependency) koin-annotations version: 1.0.0-beta-2 (api in domain module, on which the other modules have a dependency) ksp plugin version: 1.6.20-1.0.5 (in all modules)

arnaudgiuliani commented 2 years ago

are you sure your injecting the repository param in your useCase?

private val myListUseCase: MyUseCase by inject()

->
@Factory
class MyUseCase(
    @InjectedParam private val myRepository: MyRepository
)

Why do you need @InjectedParam?

jsiefers commented 2 years ago

@arnaudgiuliani I think I misunderstood the @InjectedParam annotation. I thought that was needed to let Koin know that that parameter should be injected. After removing it, I don't get the exception any more. Thanks for your reply.