InsertKoinIO / koin

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform
https://insert-koin.io
Apache License 2.0
9.08k stars 719 forks source link

Koin - Variables initialisation/not have value #1684

Closed pedroramos1449 closed 7 months ago

pedroramos1449 commented 1 year ago

I am converting my whole project into Koin. Using Koin KMP (I am converting right now my shared module).

And I have multiple modules, that are being executed in one main module (which the main contains the references to the others), for organisation proposes only.

Here's my Main Module:

package pt.custojusto.procore.shared.dependencyinjection

import io.ktor.client.HttpClient
import kotlinx.coroutines.CoroutineScope
import kotlinx.serialization.InternalSerializationApi
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.context.startKoin
import org.koin.dsl.koinApplication
import org.koin.dsl.module
import pt.custojusto.accountprivate.AccountPrivateKoinInitializer
import pt.custojusto.authenticationprivate.AuthenticationKoinInitializer
import pt.custojusto.buyoptions.BuyOptionsKoinInitializer
import pt.custojusto.configuration.ConfigurationKoinInitializer
import pt.custojusto.configuration.firebase.FeatureTogglesFirebaseRemoteConfig
import pt.custojusto.configuration.services.featuretoggles.configuratorapp.FeatureTogglesConfiguratorAppService
import pt.custojusto.global.core.expectations.CJFileManager
import pt.custojusto.global.core.expectations.ChallengeHandler
import pt.custojusto.global.core.expectations.KtorFactory
import pt.custojusto.global.core.models.AppEnvironment
import pt.custojusto.messaging.MessagingSharedKoinInitializer
import pt.custojusto.parametersprivate.ParametersPrivateKoinInitializer
import pt.custojusto.procore.shared.repositories.provider.RepositoryProvider
import pt.custojusto.procore.shared.repositories.provider.RepositoryProviderImpl
import pt.custojusto.procore.shared.services.provider.ServiceProvider
import pt.custojusto.procore.shared.services.provider.ServiceProviderImpl
import pt.custojusto.procore.shared.usecases.provider.UseCaseProvider
import pt.custojusto.procore.shared.usecases.provider.UseCaseProviderImpl

@InternalSerializationApi
class KoinModules : KoinComponent {

    lateinit var ktor: HttpClient
    val services: ServiceProvider by inject()
    val repositories: RepositoryProvider by inject()
    val useCases: UseCaseProvider by inject()

    val buyOptionsKoinInitializer: BuyOptionsKoinInitializer by inject()
    val authenticationKoinInitializer: AuthenticationKoinInitializer by inject()
    val configurationKoinInitializer: ConfigurationKoinInitializer by inject()
    val parametersPrivateKoinInitializer: ParametersPrivateKoinInitializer by inject()
    val accountPrivateKoinInitializer: AccountPrivateKoinInitializer by inject()
    val messagingSharedKoinInitializer: MessagingSharedKoinInitializer by inject()

    private val servicesModules = module {
        single { ServiceProviderImpl(get(), get(), get()) }
        single { RepositoryProviderImpl(get(), get(), get()) }
        single { UseCaseProviderImpl(get(), get(), get()) }
    }

    fun initKoin(
        coroutineScope: CoroutineScope,
        isDebug: Boolean,
        fileManager: CJFileManager,
        sessionFileUrl: String,
        sessionChallengeHandler: ChallengeHandler?,
        configuratorAppFeatureTogglesService: FeatureTogglesConfiguratorAppService,
        firebaseRemoteConfig: FeatureTogglesFirebaseRemoteConfig,
        versionName: String,
        versionCode: Int,
        isPro: Boolean
    ) {

        this.ktor = KtorFactory.create(sessionChallengeHandler, versionName, versionCode, isPro)
        val koinServices = koinApplication {
            modules(servicesModules)
        }

        startKoin {
            modules(module {
                koinServices
                //TODO: Check if initialization works like this on koin
                factory {
                    ConfigurationKoinInitializer(
                        coroutineScope, configuratorAppFeatureTogglesService, firebaseRemoteConfig
                    ).configurationModule
                }

                factory {
                    AuthenticationKoinInitializer(
                        fileManager,
                        sessionFileUrl
                    ).authenticationModule
                }

                BuyOptionsKoinInitializer().buyOptionsModule
                ParametersPrivateKoinInitializer(
                    ktor,
                    configurationKoinInitializer.configurationService,
                    authenticationKoinInitializer.sessionRepository
                ).parametersModule
                AccountPrivateKoinInitializer(
                    ktor,
                    configurationKoinInitializer.configurationService,
                    authenticationKoinInitializer.sessionRepository
                ).accountModule

                /*val serviceProvider = ServiceProviderImpl(
                    configurationKoinInitializer.configurationService,
                    authenticationKoinInitializer.sessionRepository,
                    ktor
                )
                val repositoryProvider = RepositoryProviderImpl(
                    serviceProvider,
                    authenticationKoinInitializer.sessionRepository,
                    accountPrivateKoinInitializer.accountRepository
                )*/

                MessagingSharedKoinInitializer(
                    ktor,
                    services.configurationService,
                    authenticationKoinInitializer.sessionRepository
                ).messagingModule
            })
        }
        configureEnvironment(isDebug)
        with(services, repositories, useCases)
    }

    fun with(
        serviceProvider: ServiceProvider,
        repositoryProvider: RepositoryProvider,
        useCaseProvider: UseCaseProvider
    ) {

    }

    private fun configureEnvironment(isDebug: Boolean) {
        val configuration = repositories.provideConfigurationRepository()
        if (configuration.firstLaunch) {
            if (isDebug) {
                configuration.saveAppEnvironment(AppEnvironment.Qa)
            } else {
                configuration.saveAppEnvironment(AppEnvironment.Prod)
            }
            configuration.saveFirstLaunch(false)
        }
    }
}

Here's the child module, per example ConfigurationKoinInitializer.

package pt.custojusto.configuration

import kotlinx.coroutines.CoroutineScope
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.context.startKoin
import org.koin.dsl.module
import pt.custojusto.configuration.firebase.FeatureTogglesFirebaseRemoteConfig
import pt.custojusto.configuration.repositories.configuration.ConfigurationRepository
import pt.custojusto.configuration.repositories.configuration.ConfigurationRepositoryImpl
import pt.custojusto.configuration.repositories.featuretoggles.FeatureTogglesRepository
import pt.custojusto.configuration.repositories.featuretoggles.FeatureTogglesRepositoryImpl
import pt.custojusto.configuration.services.configuration.ConfigurationService
import pt.custojusto.configuration.services.configuration.ConfigurationServiceImpl
import pt.custojusto.configuration.services.featuretoggles.FeatureTogglesService
import pt.custojusto.configuration.services.featuretoggles.configuratorapp.FeatureTogglesConfiguratorAppService
import pt.custojusto.configuration.services.featuretoggles.local.FeatureTogglesLocalService

class ConfigurationKoinInitializer(
    coroutineScope: CoroutineScope,
    configuratorAppFeatureTogglesService: FeatureTogglesConfiguratorAppService,
    firebaseRemoteConfig: FeatureTogglesFirebaseRemoteConfig
) : KoinComponent {

    val configurationService: ConfigurationService by inject()
    val featureTogglesService: FeatureTogglesService by inject()
    val configurationRepository: ConfigurationRepository by inject()
    val featureTogglesRepository: FeatureTogglesRepository by inject()

     val configurationModule = module {
        single { coroutineScope }
        single { configuratorAppFeatureTogglesService }
        single { firebaseRemoteConfig }
        single { ConfigurationServiceImpl(get()) }
        single { FeatureTogglesLocalService() }
        single { ConfigurationRepositoryImpl(get()) }
        single {
            FeatureTogglesRepositoryImpl(
                get(),
                get(),
                get(),
                get()
            )
        }
    }
}

When building the app, it gives me an error about the initialisers, that I have on my KoinModules. I've tried to initialise with the get() (example: configurationKoinInitializer = get() ) and by the normal way we initialise things

(example: configurationKoinInitializer = ConfigurationKoinInitializer(
                        coroutineScope, configuratorAppFeatureTogglesService, firebaseRemoteConfig
                    ).configurationModule)

But it doesn't work...

The error I get on my Logcat:

ATAL EXCEPTION: main
                                                                                                    Process: com.schibsted.iberica.custojusto.debug, PID: 6741
                                                                                                    java.lang.RuntimeException: Unable to create application

pt.custojusto.MainApplication: org.koin.core.error.NoBeanDefFoundException: No definition found for type 'pt.custojusto.configuration.ConfigurationKoinInitializer'. Check your Modules configuration and add missing type and/or qualifier! at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7619) at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2400) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8757) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067) Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for type 'pt.custojusto.configuration.ConfigurationKoinInitializer'. Check your Modules configuration and add missing type and/or qualifier! at org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:301) at org.koin.core.scope.Scope.resolveValue(Scope.kt:271) at org.koin.core.scope.Scope.resolveInstance(Scope.kt:233) at org.koin.core.scope.Scope.get(Scope.kt:212) at pt.custojusto.procore.shared.dependencyinjection.KoinModules$special$$inlined$inject$default$6.invoke(KoinComponent.kt:67) at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) at pt.custojusto.procore.shared.dependencyinjection.KoinModules.getConfigurationKoinInitializer(KoinModules.kt:41) at pt.custojusto.procore.shared.dependencyinjection.KoinModules$initKoin$1$1.invoke(KoinModules.kt:91) at pt.custojusto.procore.shared.dependencyinjection.KoinModules$initKoin$1$1.invoke(KoinModules.kt:72) at org.koin.dsl.ModuleDSLKt.module(ModuleDSL.kt:45) at org.koin.dsl.ModuleDSLKt.module$default(ModuleDSL.kt:43) at pt.custojusto.procore.shared.dependencyinjection.KoinModules$initKoin$1.invoke(KoinModules.kt:72) at pt.custojusto.procore.shared.dependencyinjection.KoinModules$initKoin$1.invoke(KoinModules.kt:71) at org.koin.core.context.GlobalContext.startKoin(GlobalContext.kt:64) at org.koin.core.context.DefaultContextExtKt.startKoin(DefaultContextExt.kt:40) at pt.custojusto.procore.shared.dependencyinjection.KoinModules.initKoin(KoinModules.kt:71) at pt.custojusto.MainApplication.onCreate(MainApplication.kt:155) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1266) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7614)

I am new at dependency injection.

If someone has any idea, I would love.

Thanks.

arnaudgiuliani commented 1 year ago

Koin doesn't find ConfigurationKoinInitializer, means you don't have any definition for this type defined. Not sure your factory { ConfigurationKoinInitializer( coroutineScope, configuratorAppFeatureTogglesService, firebaseRemoteConfig ).configurationModule } expression is return ConfigurationKoinInitializer

what is configurationModule?

stale[bot] commented 7 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.