Jayson Minard
Jayson Minard

Reputation: 85936

With Kodein dependency injection, I don't want to pass around kodein instances everywhere

Using Kodein, I find I have to pass kodein instances around or inject them into modules and classes. But sometimes I have classes that are so disconnected I want them just to be able to discover "one true Kodein". Since this is a server side app, and I only have one Kodein scope it should be easy. I can create a global object, such as:

val kodeinGlobal: Kodein = Kodein { ... }

But that doesn't work when some of the modules are re-used across different projects and we cannot easily share this one instance. Maybe a separate module just to hold the global would work, but then it would need to be a var and I'd prefer it not be changeable.

Can Kodein find a main, top-level or global scope on its own?

Note: this question is intentionally written and answered by the author (Self-Answered Questions), so that the idiomatic answers to commonly asked Kotlin/Kodein topics are present in SO.

Upvotes: 2

Views: 2581

Answers (1)

Jayson Minard
Jayson Minard

Reputation: 85936

In Kodein 3.x there is a new module available called kodein-conf. This allows you to create a modifiable instance of Kodein (as long as you modify it before the first injection is done), and it also contains a Kodein global instance for shared use if that is desired instead. This is contrary to a normal Kodein instance which must have all bindings defined at construction time and can never be modified.

Using the predefined global is as easy as referencing Kodein.global. And it works the same as any configurable Kodein instance:

Kodein.global.addImport(someModule) // add other modules to it

val something: SomethingCool = Kodein.global.instance() // inject from it

If you want to make your own global:

val kodeinGlobal = ConfigurableKodein()

For more about ConfigurableKodein read the Kodein 3.x docs for ConfigurableKodein, and about the predefined global instance The God Complex: One True Kodein

As a helper, you can use the new KodeinGlobalAware interface to have natural access within your class to Kodein instances without having to directly reference the global Kodein instance. For example by adding this interface, you can just call the instance creation methods, such as:

class DefaultSomeService(): SomeService, KodeinGlobalAware {
    val mapper: ObjectMapper = instance()
    // ...
}

Or if you have a case (such as testing) where you want to use the global instance unless overridden with a specific instance, you can do something similar to:

class DefaultSomeService(override val kodein: Kodein = Kodein.global): SomeService, KodeinAware {
    val mapper: ObjectMapper = instance()
    // ...
}

Which uses KodeinAware interface and and overrides its abstract member variable kodein to do the same transparent type of injection within the class, while defaulting to the global instance.

If you want to only inject Kodein whether that is the global instance or a specific one, see: Injecting Kodein instances within binding declarations as an alternative.

Upvotes: 5

Related Questions