Reputation: 85936
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
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