InsertKoinIO / koin

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

Sub-modules failing #1941

Open kmbisset89 opened 2 months ago

kmbisset89 commented 2 months ago

Getting an error when using submodules that throws an exception.

To Reproduce Steps to reproduce the behavior: Use the includes keyword: val commonModule = module { includes(infrastructureModule, viewModels, useCases, repositories) }

private val infrastructureModule = module { single { CoroutineErrorCatcher(get()) }

single { DispatcherProvider(get<CoroutineErrorCatcher>().coroutineExceptionHandler) }

}

private val viewModels = module {

}

private val useCases = module {

}

private val repositories = module {

}

                                                                                                Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List org.koin.core.module.Module.getIncludedModules()' on a null object reference

Expected behavior Not throw exception

Koin module and version:

GodzerBoot commented 1 month ago

Same issue

Not using includes() and writing all modules in the same file solved the problem, but... It's quite dirty

kmbisset89 commented 1 week ago

@arnaudgiuliani

@OptIn(KoinInternalApi::class)
fun flatten(modules: List<Module>): Set<Module> {
    // This is actually a DFS traversal of the module graph,
    // but we're using a stack instead of recursion to avoid stack overflows and performance overhead.

    val flatten = linkedSetOf<Module>()
    // I added a filter not null to get ride of this even though it should not be possible to have a null in that list. 
    val stack = ArrayDeque(modules.asReversed().filterNotNull())

    while (stack.isNotEmpty()) {

       /* The problem is here some how it is getting a null module */

        val current = stack.removeLast()

        // If the module is already in the set, that means we've already visited it, so we can skip it.
        if (!flatten.add(current)) {
            continue
        }

        // Add all the included modules to the stack if they haven't been visited yet.
        for (module in current.includedModules) {
            if (module !in flatten) {
                stack += module
            }
        }
    }

    return flatten
}