Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get/Inject all beans of T as Set<T> or List<T> #146

Closed
amirabiri opened this issue Jun 12, 2018 · 18 comments
Closed

Get/Inject all beans of T as Set<T> or List<T> #146

amirabiri opened this issue Jun 12, 2018 · 18 comments
Labels

Comments

@amirabiri
Copy link

For certain use cases I'd like to register multiple beans of SomeInterface and then get them from koin as a Set<SomeInterface> or List<SomeInterface>.

For example:

interface Command {
    ...
}

class GitClone(...) : Command {
    ...
}

class GitPull(...) : Command {
    ...
}

val ctxt = applicationContext {
    bean("clone") { GitClone(...) }
    bean("pull") { GitPull(...) }
}

fun main(args: Array<String>) {
    val koin = startKoin(listOf(ctxt))
    val cliFramework = CliFramework()
    cliFramework.registerCommands(
        koin.koinContext.getAll<Command>())
}
@arnaudgiuliani arnaudgiuliani added this to Analyzing in Koin Dev Board Jun 13, 2018
@arnaudgiuliani arnaudgiuliani added core type:feature-proposal status:checking currently in analysis - discussion or need more detailed specs labels Jun 13, 2018
@arnaudgiuliani
Copy link
Member

Ok, we'll see what we can propose for that 👍

Keep in touch.

@amirabiri
Copy link
Author

I've implemented a proposal and added a pull request. #148

@arnaudgiuliani
Copy link
Member

Ok, we'll check that 👍

@serandel
Copy link

I would really love this. Could you use it in Android like this?
val commands: List<Command> by inject()

@arnaudgiuliani
Copy link
Member

I see. Not sure to include it immediately for 1.0.0, perhaps one minor version behind.

@arnaudgiuliani arnaudgiuliani moved this from Analyzing to New / Waiting in Koin Dev Board Jul 6, 2018
@arnaudgiuliani arnaudgiuliani moved this from New / Waiting to Analyzing in Koin Dev Board Aug 8, 2018
@arnaudgiuliani arnaudgiuliani added status:waiting and removed status:checking currently in analysis - discussion or need more detailed specs labels Aug 16, 2018
@kuFEAR
Copy link

kuFEAR commented Oct 14, 2018

I think It should be implemented with explicit binders instances which we expect to collect into set/list/map. I may declare some instance which shouldn't be part of set of all instances,

My current multi-binding approach:

factory("set-of-validator-binds") { mutableSetOf(ValidatorA(), ValidatorB(), ValidatorC()) }
factory<Set<Validator<Entity>>("set-of-validator", override = true) { get<MutableSet<Validator<Entity>>>("set-of-validator-binds") }
factory { MessageProcessor(get("set-of-validator"))}

additional binding:

factory("set-of-validator") { get<MutableSet<Validator<Entity>>>("set-of-validator-binds").apply { add(ValidatorE()) } }

It would be preferred to implement separated definition methods for multi-binding:

bindIntoSet<Validator<Entity>>("set-validator-a") { ValidatorA() } 
bindIntoMap<Class, Validator<Entity>>("map-validator-a") { EntityA::class to EntityValidatorA() }
bindIntoMap<Int, Validator<Entity>>("map-validator-b") { 0 to EntityValidatorB() }
bindIntoMap<String, Validator<Entity>>("map-validator-c") { "C" to EntityValidatorC() }
factory { MessageProcessor(get("set-validator-a"), get("map-validator-a"), get("map-validator-b"), get("map-validator-c")) }

or it may be placed inside current definition methods:

factory { bindIntoMap{...} }
single { bindIntoSet{...} }
scope() { bindIntoSet{...} } 

@fmobus
Copy link

fmobus commented Dec 6, 2018

I see. Not sure to include it immediately for 1.0.0, perhaps one minor version behind.

Is there any roadmap for this? I'd love to use that feature :)

@viniciusccarvalho
Copy link
Contributor

Just wanted to give another +1 for this feature. Here's my use case:
I have several repositories (elastic search indices), and as we expand the project more and more are added.

One of the exposed methods to the business is the capability to run index operations (compactations, delete, recreate), and currently, every time a new index is added, we need to add a new entry to the list of index. Have we had something like
val indices: List<AbstractReposiory> by inject() it would be one less place to refactor

@arnaudgiuliani
Copy link
Member

wait and see what I can propose in 2.0

@REPLicated
Copy link

@arnaudgiuliani : Any news on this?

@arnaudgiuliani
Copy link
Member

not for 2.0 at least. Have to check that for next version. You can provide snippets to help around that for now.

@REPLicated
Copy link

@arnaudgiuliani , @amirabiri :

The following does the job for me. As-is it only works for single definitions in the global scope and needs kotlin-reflect due to isSubclassOf:

inline fun <reified T : Any> KoinComponent.getAllOfType(): Collection<T> =
        getKoin().let { koin ->
            koin.beanRegistry
                    .getAllDefinitions()
                    .filter { it.isKind(Single) }
                    .filter { it.primaryType.isSubclassOf(T::class)}
                    .map { koin.get<T>(clazz = it.primaryType, qualifier = null, parameters = null) }
        }

Koin Dev Board automation moved this from Proposals to Done Jun 12, 2019
@vojtapol
Copy link

vojtapol commented Nov 9, 2019

Why was this closed? This feature is essential in a mature DI framework. Spring has had this feature for years.

@blundell
Copy link

blundell commented Jan 23, 2020

update on @REPLicated's comment
on version 2.0.1:

inline fun <reified T : Any> KoinComponent.getAllOfType(): Collection<T> =
        getKoin().let { koin ->
            koin.rootScope.beanRegistry
                .getAllDefinitions()
                .filter { it.kind == Kind.Single }
                .filter { it.primaryType.isSubclassOf(T::class)}
                .map { koin.get<T>(clazz = it.primaryType, qualifier = null, parameters = null) }
        }

Just spotted Scope.getAll() might be the answer

Get a all instance for given inferred class (in primary or secondary type)

@REPLicated
Copy link

@blundell : Exactly. Now you can do something like:

single { FooBarJob(get()) } bind Job::class
getKoin().getAll<Job>()

@RomanMinenok
Copy link

RomanMinenok commented Feb 13, 2020

@REPLicated thanks, this works for me, but it still requires some boilerplate (bind Job::class), so it'd be great to have proper implementation in the future

@artemasoyan
Copy link

artemasoyan commented Jun 25, 2021

@RomanMinenok I'm using a less boilerplate verions, something like:

inline fun <reified T: Job> Module.job(
    crossinline job: Scope.() -> T,
): BeanDefinition<T> =
    factory<T> { job() } bind Job::class

@ESchouten
Copy link
Contributor

ESchouten commented Sep 25, 2021

Update on @REPLicated's comment
on version 3.1.2:

inline fun <reified T : Any> getAll(): Collection<T> =
    getKoin().let { koin ->
        koin.instanceRegistry.instances.values.map { it.beanDefinition }
            .filter { it.kind == Kind.Singleton }
            .filter { it.primaryType.isSubclassOf(T::class) }
            .map { koin.get(clazz = it.primaryType, qualifier = null, parameters = null) }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests