InsertKoinIO / koin

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

How do you use Koin with TornadoFX #193

Closed bj0 closed 5 years ago

bj0 commented 6 years ago

According to the tornadofx documentation: [https://edvin.gitbooks.io/tornadofx-guide/content/part2/Dependency%20Injection.html], you can override their basic DI with a 3rd party framework by setting:

val guice = Guice.createInjector(MyModule())

FX.dicontainer = object : DIContainer {
    override fun <T : Any> getInstance(type: KClass<T>)
        = guice.getInstance(type.java)
}

I would like to use Koin, but I cannot find anything equivalent to getInstance in the Koin documentation.

arnaudgiuliani commented 6 years ago

Hello, to retrieve instances from Koin you have to use KoinComponent interface.

Try something like:

val guice = Guice.createInjector(MyModule())

FX.dicontainer = object : DIContainer, KoinComponent {
    override fun <T : Any> getInstance(type: KClass<T>)
        = get()
}
bj0 commented 6 years ago

When I try that, it gives "type inference failed". If I specify the return type as T:

   override fun <T : Any> getInstance(type: KClass<T>): T = get()

Then i get the error "cannot use T as reified type parameter. Use a class instead."

arnaudgiuliani commented 6 years ago

because you need to specify it in your signature: override inline fun <reified T : Any> getInstance(type: KClass<T>): T = get()

add the Kotlin keywords reified and inline.

bj0 commented 6 years ago

both reified and inline give errors when used with override.

arnaudgiuliani commented 6 years ago

Because we can't modify the overriden function signature. Let me open a bit this

bj0 commented 6 years ago

fyi, I was able to get it to work with:

    FX.dicontainer = object : DIContainer, KoinComponent {
        override fun <T : Any> getInstance(type: KClass<T>): T = (StandAloneContext.koinContext as KoinContext).get(
                ClassRequest(clazz = type.java, parameters = emptyParameterDefinition())
        )
    }

but it's ugly. It would be much nicer if there was an override of get that just took the type, so I could just:

    FX.dicontainer = object : DIContainer, KoinComponent {
        override fun <T : Any> getInstance(type: KClass<T>): T = koinContext.get(type)
        )
    }
arnaudgiuliani commented 6 years ago

Cool 👍 Since beta-8, it should be easier to write with (StandAloneContext.koinContext as KoinContext).getForClass(...)

mobiletoly commented 6 years ago

arnaudgiuliani, can you provide an example please?

mobiletoly commented 6 years ago

oops, nevermind. seems like this one worked for me

StandAloneContext.startKoin(listOf(appModule))

FX.dicontainer = object : DIContainer, KoinComponent {
    override fun <T : Any> getInstance(type: KClass<T>): T =
        (StandAloneContext.koinContext as KoinContext).getForClass(clazzName = type.qualifiedName!!)
}

val appModule = module {
    single<StudioProjectModel>()
}
arnaudgiuliani commented 6 years ago

Good 👍

bj0 commented 6 years ago

It looks like getForClass disappeared in 1.0.0, is there a replacement?

arnaudgiuliani commented 6 years ago

Just use the get function. It can get a KClass as parameter.

ianbrandt commented 5 years ago

It took some trial and error to realize that I had to call one of the get overloads on Koin, as opposed to any on KoinComponent. Here's how I got it to work with 2.0.1 in case it saves anyone some time:

FX.dicontainer = object : DIContainer, KoinComponent {
    override fun <T : Any> getInstance(type: KClass<T>): T {
        return getKoin().get(clazz = type, qualifier = null, parameters = null)
    }
}