Koin Annotations
The goal of Koin Annotations project is to help declare Koin definition in a very fast and intuitive way, and generate all underlying Koin DSL for you. The goal is to help developer experience to scale and go fast ๐, thanks to Kotlin Compilers.
Getting Started
Not familiar with Koin? First take a look at Koin Getting Started
Tag your cpomnents with definition & module annotations, and use the regular Koin API.
Use the org.koin.ksp.generated.*
import as follow to be able to use generated code:
That's it, you can use your new definitions in Koin with the regular Koin API
Definitions
Koin Annotations allow to declare the same kind of definitions as the regular Koin DSL, but with annotations. Just tag your class with the needed annotatation, and it will generate everything for you!
For example the equivalent to single { MyComponent(get()) }
DSL declaration, is just done by tagging with @Single
like this:
Koin Annotations keep the same semantic as the Koin DSL. You can declare your components with the following definitions:
@Single
- singleton instance (declared withsingle { }
in DSL)@Factory
- factory instance. For instances recreated each time you need an instance. (declared withfactory { }
in DSL)@KoinViewModel
- Android ViewModel instance (declared withviewModel { }
in DSL)
For Scopes, check the Declaring Scopes section.
Automatic or Specific Binding
When declaring a component, all detected "bindings" (associated supertypes) will be already prepared for you. For example, the following definition:
Koin will declare that your MyComponent
component is also tied to MyInterface
. The DSL equivalent is single { MyComponent(get()) } bind MyInterface::class
.
Instead of letting Koin detect thigns for you, you can also specify what type you really want to bind with the binds
annotation parameter:
Nullable Dependencies
If your component is using nullable depndency, don't worry it will be handled automaticaly for you. Keep using yopur definition annotation, and Koin will guess what to do:
The generated DSL equivalent will be single { MyComponent(getOrNull()) }
Note that this also works for injected Parameters and properties
Qualifier with @Named
You can add a "name" to definition (also called qualifier), to make distinction between several definitions for the same type, with the @Named
annotation:
When resolving a dependency, just use the qualifier with named
function:
Injected Parameters with @InjectedParam
You can tag a constructor member as "injected parameter", which means that the dependency will be passed in the graph when calling for resolution.
For example:
Then you can call your MyComponent
and pass a instance of MyDependency
:
The generated DSL equivalent will be single { params -> MyComponent(params.get()) }
Properties with @Property
To resolve a Koin property in your definition, just tag a cosntructor member with @Property
. Ths is will resolve the Koin property thanks to the value passed to the annotation:
The generated DSL equivalent will be single { MyComponent(getProperty("my_key")) }
Declaring Scopes with @Scope
You can declare definition inside a scope, by using the @Scope
annotation. The target scope can be specified as a class, or a name:
The generated DSL equivalent will be:
You can cumulate
@Factory
or@KoinViewModel
, to specify a scoped Factory or a ViewModel. Also you can use the@Scoped
annotation to let define specific bindings on a@Scope
tagged components.
Modules
While using definitions, you may need to organize them in modules or not. You can even not use any module at all and use the "default" generated module.
No Module - Using the Generated Default Module
If you don't want to specify any module, Koin provide a default one to host all your definitions. The defaultModule
is ready to be use directly:
Don't forget to use the
org.koin.ksp.generated.*
import
Class Module with @Module
To declare a module, just tag a class with @Module
annotation:
To load your module in Koin, just use the .module
extension generated for any @Module
class. Just create new instance of your module MyModule().module
:
Don't forget to use the
org.koin.ksp.generated.*
import
Components Scan with @ComponentScan
To scan and gather annotated components into a module, just use the @ComponentScan
annotation on a module:
This will scan current package and subpackages for annotated components.
You can specify to scan a given package
@ComponentScan("com.my.package")
Definitions in Class Modules
To define a definition directly in your can, you an annotate a function with definition annotations:
@InjectedParam, @Property are also usable on function members
Including Modules
To include other class modules to your module, just use the includes
attribute of the @Module
annotation:
This way you can just run your root module: