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 4.0.0 on Android, factoryOf() can only cope with 22 constructor parameters #2004

Open Andrew-Beechey-DS opened 1 month ago

Andrew-Beechey-DS commented 1 month ago

In my current Android application I have used the following gradle deps

koin-bom = "4.0.0"

koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin-bom" }
koin-core = { module = "io.insert-koin:koin-core" }
koin-android = { module = "io.insert-koin:koin-android" }
koin-startup = { module = "io.insert-koin:koin-androidx-startup" }
di-koin-compose = { module = "io.insert-koin:koin-androidx-compose" }

I am migrating from koin = "3.5.0"

Android Studio version

Android Studio Koala | 2024.1.1
Build #AI-241.15989.150.2411.11948838, built on June 10, 2024
Runtime version: 17.0.10+0-17.0.10b1087.21-11609105 aarch64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
macOS 15.0
GC: G1 Young Generation, G1 Old Generation
Memory: 8192M
Cores: 16
Metal Rendering is ON
Registry:
  ide.instant.shutdown=false
  ide.experimental.ui=true

Describe the bug when attempting to define factoryOf(::MyBigConstructor) factoryOf cannot copy with this....

            MyBigConstructor(
                getSpecialOptions = get(),
                getHotspotTypes = get(),
                doNotShowCheckDateWarning = get(),
                registerStreamNotificationsIfFlagIsOn = get(),
                updateMenuModuleSettingsOrder = get(),
                generateMenuButtons = get(),
                hasMenuAnyHiddenModules = get(),
                updateSelectedSystemDateUseCase = get(),
                logoutUser = get(),
                getCompaniesWithResources = get(),
                getZoneTypes = get(),
                getUnreadSiteNotificationsCount = get(),
                refreshPocketSettings = get(),
                getStages = get(),
                hasAreaFiles = get(),
                getModuleSettings = get(),
                checkAreasForModule = get(),
                fetchInitialData = get(),
                userSessionManager = get(),
                getHotspotMandatoryFields = get(),
                getSubzoneSettings = get(),
                getLimitHotspotTypes = get(),
                syncSubzoneClusterSettings = get()
            )

To Reproduce Steps to reproduce the behavior:

  1. Create class with more than 22 constructor arguments
  2. within a Koin module declaration create factoryOf(::ThatClass)

Expected behavior koin provides a factory

Koin module and version:

Snippet or Sample project to help reproduce

even though I resolved the compile time issue by developing the following:--

import org.koin.core.definition.KoinDefinition
import org.koin.core.module.Module
import org.koin.core.module.dsl.DefinitionOptions
import org.koin.core.module.dsl.factoryOf
import org.koin.core.module.dsl.new
import org.koin.core.module.dsl.onOptions
import org.koin.core.scope.Scope

/**
 * @see new
 */
inline fun <reified R, reified T1, reified T2, reified T3, reified T4, reified T5, reified T6, reified T7, reified T8, reified T9, reified T10, reified T11, reified T12, reified T13, reified T14, reified T15, reified T16, reified T17, reified T18, reified T19, reified T20, reified T21, reified T22, reified T23> Scope.new(
    constructor: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23) -> R,
): R = constructor(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get())

/**
 * @see factoryOf
 */
inline fun <reified R, reified T1, reified T2, reified T3, reified T4, reified T5, reified T6, reified T7, reified T8, reified T9, reified T10, reified T11, reified T12, reified T13,
        reified T14, reified T15, reified T16, reified T17, reified T18, reified T19, reified T20, reified T21, reified T22, reified T23> Module.factoryOf(
    crossinline constructor: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23) -> R,
    noinline options: DefinitionOptions<R>? = null,
): KoinDefinition<R> = factory { new(constructor) }.onOptions(options)

when i build the android application I get this exception


rg.jetbrains.kotlin.backend.common.BackendException: Backend Internal error: Exception during IR lowering
File being compiled: /Users/frank/my_systems/MyApp/app/src/main/java/com/boundedcontexts/menu/ioc/MenuUiKoinModule.kt
The root cause java.lang.RuntimeException was thrown at: org.jetbrains.kotlin.backend.jvm.codegen.FunctionCodegen.generate(FunctionCodegen.kt:47)
    at org.jetbrains.kotlin.backend.common.CodegenUtil.reportBackendException(CodegenUtil.kt:253)
    at org.jetbrains.kotlin.backend.common.CodegenUtil.reportBackendException$default(CodegenUtil.kt:236)
    at org.jetbrains.kotlin.backend.common.phaser.PerformByIrFilePhase.invokeSequential(performByIrFile.kt:65)
    at org.jetbrains.kotlin.backend.common.phaser.PerformByIrFilePhase.invoke(performByIrFile.kt:52)
    at org.jetbrains.kotlin.backend.common.phaser.PerformByIrFilePhase.invoke(performByIrFile.kt:38)
    at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.phaseBody(CompilerPhase.kt:166)
    at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedCompilerPhase.invoke(CompilerPhase.kt:113)
    at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:27)
    at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:14)
    at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.phaseBody(CompilerPhase.kt:166)
    at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedCompilerPhase.invoke(CompilerPhase.kt:113)
    at org.jetbrains.kotlin.backend.common.phaser.CompilerPhaseKt.invokeToplevel(CompilerPhase.kt:62)
    at org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory.invokeCodegen(JvmIrCodegenFactory.kt:371)
    at org.jetbrains.kotlin.codegen.CodegenFactory.generateModule(CodegenFactory.kt:47)
    at org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory.generateModuleInFrontendIRMode(JvmIrCodegenFactory.kt:433)
    at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.generateCodeFromIr(jvmCompilerPipeline.kt:246)
    at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:142)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
    at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
    at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
    at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.tryCompileIncrementally$lambda$9$compile(IncrementalCompilerRunner.kt:249)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.tryCompileIncrementally(IncrementalCompilerRunner.kt:267)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:120)
    at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
    at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
    at jdk.internal.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base/java.lang.reflect.Method.invoke(Unknown Source)
    at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Unknown Source)
    at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Unknown Source)
    at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.RuntimeException: Exception while generating code for:
FUN LOCAL_FUNCTION_FOR_LAMBDA name:ioc$lambda$22 visibility:private modality:FINAL <> ($this$module:org.koin.core.module.Module) returnType:kotlin.Unit?
  VALUE_PARAMETER name:$this$module index:0 type:org.koin.core.module.Module
  BLOCK_BODY
    COMPOSITE type=kotlin.Unit origin=null
      TYPE_OP type=org.koin.core.definition.KoinDefinition<com.boundedcontexts.menu.ui.viewmodel.MenuUseCaseProfile> origin=IMPLICIT_CAST typeOperand=org.koin.core.definition.KoinDefinition<com.boundedcontexts.menu.ui.viewmodel.MenuUseCaseProfile>
        CALL 'public final fun factoryOf$default <R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> (constructor: kotlin.Function23<T1 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T2 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T3 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T4 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T5 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T6 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T7 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T8 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T9 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T10 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T11 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T12 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T13 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T14 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T15 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T16 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T17 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T18 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T19 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T20 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T21 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T22 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, T23 of com.utils.extensions.KoinExtensionsKt.factoryOf$default, R of com.utils.extensions.KoinExtensionsKt.factoryOf$default>, options: @[ExtensionFunctionType] kotlin.Function1<org.koin.core.definition.BeanDefinition<R of com.utils.extensions.KoinExtensionsKt.factoryOf$default>, kotlin.Unit>?, $mask0: kotlin.Int, $handler: kotlin.Any?): org.koin.core.definition.KoinDefinition<R of com.utils.extensions.KoinExtensionsKt.factoryOf$default> [inline] declared in com.utils.extensions.KoinExtensionsKt' type=org.koin.core.definition.KoinDefinition<R of com.utils.extensions.KoinExtensionsKt.factoryOf$default> origin=DEFAULT_DISPATCH_CALL
          <R>: com.boundedcontexts.menu.ui.viewmodel.MenuUseCaseProfile
          <T1>: domain.specialoptions.useCases.GetSpecialOptionsUseCase
          <T2>: domain.specialoptions.useCases.DoNotShowCheckDateWarningUseCase
          <T3>: com.boundedcontexts.menu.domain.usecases.RegisterStreamNotificationsIfFlagIsOnUseCase
arnaudgiuliani commented 1 day ago

it's a known limitation. As in Kotlin function has max 21 parameters. We took max 21 param for constructors.