Koin variables initialisation on multi Module project

84 views Asked by At

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.

0

There are 0 answers