{"id":13536801,"url":"https://github.com/evant/kotlin-inject","last_synced_at":"2025-05-14T09:08:17.305Z","repository":{"id":35515752,"uuid":"194859139","full_name":"evant/kotlin-inject","owner":"evant","description":"Dependency injection lib for kotlin","archived":false,"fork":false,"pushed_at":"2025-02-25T21:40:18.000Z","size":1394,"stargazers_count":1392,"open_issues_count":46,"forks_count":64,"subscribers_count":20,"default_branch":"main","last_synced_at":"2025-04-11T23:55:05.954Z","etag":null,"topics":["dependency-injection","kotlin"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evant.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"evant"}},"created_at":"2019-07-02T12:30:10.000Z","updated_at":"2025-04-09T08:45:00.000Z","dependencies_parsed_at":"2023-02-17T13:20:17.255Z","dependency_job_id":"832b950a-3f56-4230-a015-0c12929a06bd","html_url":"https://github.com/evant/kotlin-inject","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fkotlin-inject","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fkotlin-inject/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fkotlin-inject/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fkotlin-inject/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evant","download_url":"https://codeload.github.com/evant/kotlin-inject/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248497812,"owners_count":21113984,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection","kotlin"],"created_at":"2024-08-01T09:00:49.783Z","updated_at":"2025-05-14T09:08:17.295Z","avatar_url":"https://github.com/evant.png","language":"Kotlin","funding_links":["https://github.com/sponsors/evant"],"categories":["Libraries","IoC"],"sub_categories":["DI","💉 Dependency Injection"],"readme":"# kotlin-inject\n\n[![CircleCI](https://circleci.com/gh/evant/kotlin-inject.svg?style=svg)](https://circleci.com/gh/evant/kotlin-inject)\n[![Maven Central](https://img.shields.io/maven-central/v/me.tatarka.inject/kotlin-inject-runtime.svg)](https://search.maven.org/search?q=g:me.tatarka.inject)\n[![Sonatype Snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/me.tatarka.inject/kotlin-inject-runtime.svg)](https://oss.sonatype.org/content/repositories/snapshots/me/tatarka/inject/)\n\nA compile-time dependency injection library for kotlin.\n\n```kotlin\n@Component\nabstract class AppComponent {\n    abstract val repo: Repository\n\n    @Provides\n    protected fun jsonParser(): JsonParser = JsonParser()\n\n    protected val RealHttp.bind: Http\n        @Provides get() = this\n}\n\ninterface Http\n\n@Inject\nclass RealHttp : Http\n\n@Inject\nclass Api(private val http: Http, private val jsonParser: JsonParser)\n\n@Inject\nclass Repository(private val api: Api)\n```\n\n```kotlin\nval appComponent = AppComponent::class.create()\nval repo = appComponent.repo\n```\n\n## Download\n\nUsing [ksp](https://github.com/google/ksp)\n\n`settings.gradle`\n\n```groovy\npluginManagement {\n    repositories {\n        gradlePluginPortal()\n        mavenCentral()\n    }\n}\n```\n\n`build.gradle`\n\n```groovy\nplugins {\n    id(\"org.jetbrains.kotlin.jvm\") version \"1.9.0\"\n    id(\"com.google.devtools.ksp\") version \"1.9.0-1.0.13\"\n}\n\nrepositories {\n    mavenCentral()\n    google()\n}\n\ndependencies {\n    ksp(\"me.tatarka.inject:kotlin-inject-compiler-ksp:0.8.0\")\n    implementation(\"me.tatarka.inject:kotlin-inject-runtime:0.8.0\")\n}\n```\n\n## Usage\n\nLet's go through the above example line-by line and see what it's doing.\n\n```kotlin\n@Component\nabstract class AppComponent {\n```\n\nThe building block of kotlin-inject is a component which you declare with an `@Component` annotation on an abstract\nclass. An implementation of this component will be generated for you.\n\n```kotlin\n    abstract val repo: Repository\n```\n\nIn your component you can declare abstract read-only properties or functions to return an instance of a given type. This\nis where the magic happens. kotlin-inject will figure out how to construct that type for you in it's generated\nimplementation. How does it know how to do this? There's a few ways:\n\n```kotlin\n@Provides\nprotected fun jsonParser(): JsonParser = JsonParser()\n```\n\nFor external dependencies, you can declare a function or read-only property in the component to create an instance for a\ncertain type. kotlin-inject will use the return type to provide this instance where it is requested.\n\nNote: It is good practice to always explicitly declare the return type, that way it's clear what type is being provided.\nIt may not always be what you expect!\n\n```kotlin\nprotected val RealHttp.bind: Http\n    @Provides get() = this\n```\n\nYou can declare arguments to a providing function/property to help you construct your instance. Here we are taking in an\ninstance of `RealHttp` and providing it for the interface `Http`. You can see a little sugar with this as the receiver\ntype for an extension function/property counts as an argument. Another way to write this would be:\n\n```kotlin\n@Provides\nfun http(http: RealHttp): Http = http\n```\n\n```kotlin\n@Inject\nclass RealHttp : Http\n\n@Inject\nclass Api(private val http: Http, private val jsonParser: JsonParser)\n\n@Inject\nclass Repository(private val api: Api)\n```\n\nFor your own dependencies you can simply annotate the class with `@Inject`. This will use the primary constructor to\ncreate an instance, no other configuration required!\n\n```kotlin\nval appComponent = AppComponent::class.create()\nval repo = appComponent.repo\n```\n\nFinally, you can create an instance of your component with the generated `.create()` extension function.\n\n## Features\n\n### Component Arguments\n\nIf you need to pass any instances into your component you can declare them as constructor args. You can then pass them\ninto the generated create function. You can optionally annotate it with `@Provides` to provide the value to the\ndependency graph.\n\n```kotlin\n@Component\nabstract class MyComponent(@get:Provides protected val foo: Foo)\n```\n\n```kotlin\nMyComponent::class.create(Foo())\n```\n\nIf the argument is another component, you can annotate it with `@Component` and it's dependencies will also be available\nto the child component. This allows you to compose them into a graph.\n\n```kotlin\n@Component\nabstract class ParentComponent {\n    @Provides\n    fun provideFoo(): Foo = ...\n}\n\n@Component\nabstract class ChildComponent(@Component val parent: ParentComponent) {\n    abstract val foo: Foo\n}\n```\n\n```kotlin\nval parent = ParentComponent::class.create()\nval child = ChildComponent::class.create(parent)\n```\n\n### Qualifiers\n\nIf you have multiple instances of the same type you want to differentiate, you can use a `@Qualifier`. They will be\ntreated as separate types for the purposes of injection. They can be placed either on the variable or the type.\n\n```kotlin\n@Qualifier\n@Target(\n  AnnotationTarget.PROPERTY_GETTER,\n  AnnotationTarget.FUNCTION,\n  AnnotationTarget.VALUE_PARAMETER,\n  AnnotationTarget.TYPE\n)\nannotation class Named(val value: String)\n\n@Component\nabstract class MyComponent {\n  @Provides\n  fun dep1(): @Named(\"one\") Dep = Dep(\"one\")\n\n  @Provides\n  fun dep2(): @Named(\"two\") Dep = Dep(\"two\")\n\n  @Provides\n  fun provides(@Named(\"one\") dep1: Dep, @Named(\"two\") dep2: Dep): Thing = Thing(dep1, dep2)\n}\n\n@Inject\nclass InjectedClass(@Named(\"one\") dep1: Dep, @Named(\"two\") dep2: Dep)\n```\n\n### Type Alias Support\n\nAlternatively different typealises will be treated as different types. (Note: this is going away in a future release, so\nconsider using a `@Qualifier` annotation instead. There will be a migration path.)\n\n```kotlin\ntypealias Dep1 = Dep\ntypealias Dep2 = Dep\n\n@Component\nabstract class MyComponent {\n    @Provides\n    fun dep1(): Dep1 = Dep(\"one\")\n\n    @Provides\n    fun dep2(): Dep2 = Dep(\"two\")\n\n    @Provides\n    fun provides(dep1: Dep1, dep2: Dep2): Thing = Thing(dep1, dep2)\n}\n\n@Inject\nclass InjectedClass(dep1: Dep1, dep2: Dep2)\n```\n\n### Function Injection\n\nYou can also use type aliases to inject into top-level functions. Annotate your function with `@Inject` and create a\ntype alias with the same name.\n\n```kotlin\ntypealias myFunction = () -\u003e Unit\n\n@Inject\nfun myFunction(dep: Dep) {\n}\n```\n\nYou can then use the type alias anywhere and you will be provided with a function that calls the top-level one with the\nrequested dependencies.\n\n```kotlin\n@Inject\nclass MyClass(val myFunction: myFunction)\n\n@Component\nabstract class MyComponent {\n    abstract val myFunction: myFunction\n}\n```\n\nYou can optionally pass explicit args as the last arguments of the function.\n\n```kotlin\ntypealias myFunction = (String) -\u003e String\n\n@Inject\nfun myFunction(dep: Dep, arg: String): String = ...\n```\n\n### Scopes\n\nBy default kotlin-inject will create a new instance of a dependency each place it's injected. If you want to re-use an\ninstance you can scope it to a component. The instance will live as long as that component does.\n\nFirst create your scope annotation.\n\n```kotlin\n@Scope\n@Target(CLASS, FUNCTION, PROPERTY_GETTER)\nannotation class MyScope\n```\n\nThen annotate your component with that scope annotation.\n\n```kotlin\n@MyScope\n@Component\nabstract class MyComponent()\n```\n\nFinally, annotate your provides and `@Inject` classes with that scope.\n\n```kotlin\n@MyScope\n@Component\nabstract class MyComponent {\n    @MyScope\n    @Provides\n    protected fun provideFoo(): Foo = ...\n}\n\n@MyScope\n@Inject\nclass Bar()\n```\n\n### Component Inheritance\n\nYou can define `@Provides` and scope annotations on an interface or abstract class that's not annotated\nwith `@Component`. This allows you to have multiple implementations, which is useful for things like testing. For\nexample, you can have an abstract class like\n\n```kotlin\n@NetworkScope\nabstract class NetworkComponent {\n    @NetworkScope\n    @Provides\n    abstract fun api(): Api\n}\n```\n\nThen you can have multiple implementations\n\n```kotlin\n@Component\nabstract class RealNetworkComponent : NetworkComponent() {\n    override fun api(): Api = RealApi()\n}\n\n@Component\nabstract class TestNetworkComponent : NetworkComponent() {\n    override fun api(): Api = FakeApi()\n}\n```\n\nThen you can provide the abstract class to your app component\n\n```kotlin\n@Component abstract class AppComponent(@Component val network: NetworkComponent)\n```\n\nThen in your app you can do\n\n```kotlin\nAppComponent::class.create(RealNetworkComponent::class.create())\n```\n\nand in tests you can do\n\n```kotlin\nAppComponent::class.create(TestNetworkComponent::class.create())\n```\n\n### Multi-bindings\n\nYou can collect multiple bindings into a `Map` or `Set` by using the `@IntoMap` and `@IntoSet` annotations respectively.\n\nFor a set, return the type you want to put into a set, then you can inject or provide a `Set\u003cMyType\u003e`.\n\n```kotlin\n@Component\nabstract class MyComponent {\n    abstract val allFoos: Set\u003cFoo\u003e\n\n    @IntoSet\n    @Provides\n    protected fun provideFoo1(): Foo = Foo(\"1\")\n\n    @IntoSet\n    @Provides\n    protected fun provideFoo2(): Foo = Foo(\"2\")\n}\n```\n\nFor a map, return a `Pair\u003cKey, Value\u003e`.\n\n```kotlin\n@Component\nabstract class MyComponent {\n    abstract val fooMap: Map\u003cString, Foo\u003e\n\n    @IntoMap\n    @Provides\n    protected fun provideFoo1(): Pair\u003cString, Foo\u003e = \"1\" to Foo(\"1\")\n\n    @IntoMap\n    @Provides\n    protected fun provideFoo2(): Pair\u003cString, Foo\u003e = \"2\" to Foo(\"2\")\n}\n```\n\n### Function Support \u0026 Assisted Injection\n\nSometimes you want to delay the creation of a dependency or provide additional params manually. You can do this by\ninjecting a function that returns the dependency instead of the dependency directly.\n\nThe simplest case is you take no args, this gives you a function that can create the dep.\n\n```kotlin\n@Inject\nclass Foo\n\n@Inject\nclass MyClass(fooCreator: () -\u003e Foo) {\n    init {\n        val foo = fooCreator()\n    }\n}\n```\n\nIf you define args, you can use these to assist the creation of the dependency. To do so, mark these args with the\n`@Assisted` annotation. The function should take the same number of assisted args in the same order.\n\n```kotlin\n@Inject\nclass Foo(bar: Bar, @Assisted arg1: String, @Assisted arg2: String)\n\n@Inject\nclass MyClass(fooCreator: (arg1: String, arg2: String) -\u003e Foo) {\n    init {\n        val foo = fooCreator(\"1\", \"2\")\n    }\n}\n```\n\n### Lazy\n\nSimilarly, you can inject a `Lazy\u003cMyType\u003e` to construct and re-use an instance lazily.\n\n```kotlin\n@Inject\nclass Foo\n\n@Inject\nclass MyClass(lazyFoo: Lazy\u003cFoo\u003e) {\n    val foo by lazyFoo\n}\n```\n\n### Default Arguments\n\nYou can use default arguments for parameters you inject. If the type is present in the graph, it'll be injected,\notherwise the default will be used.\n\n  ```kotlin\n@Inject class MyClass(val dep: Dep = Dep(\"default\"))\n\n@Component abstract class ComponentWithDep {\n    abstract val myClass: MyClass\n    @Provides fun dep(): Dep = Dep(\"injected\")\n}\n@Component abstract class ComponentWithoutDep {\n    abstract val myClass: MyClass\n}\n\nComponentWithDep::class.create().myClass.dep // Dep(\"injected\")\nComponentWithoutDep::class.create().myClass.dep // Dep(\"default\")\n```\n\n### Options\n\nYou can [pass options to the processor](https://kotlinlang.org/docs/ksp-quickstart.html#pass-options-to-processors) which enables certain functionality. You do this in the main `build.gradle.kts` file of your project. For example:\n\n```kotlin\nksp {\n    arg(\"me.tatarka.inject.dumpGraph\", \"true\")\n}\n```\n\nThe following options exist:\n\n- `me.tatarka.inject.enableJavaxAnnotations=true`\n\n  `@javax.inject.*` annotations can be used in in addition to the provided annotations. This can be useful if you are\n  migrating existing code or want to be abstracted from the injection lib you are using on the jvm.\n\n- `me.tatarka.inject.generateCompanionExtensions=true`\n\n  This will generate the `create()` methods on the companion object instead of the component's class. This allows you to\n  do\n  `MyComponent.create()` instead of `MyComponent::class.create()`. However, due to a kotlin limitation you will have to\n  explicitly specify a companion object for your component.\n\n  ```kotlin\n  @Component abstract class MyComponent {\n    companion object\n  }\n  ```\n\n- `me.tatarka.inject.dumpGraph=true`\n\n  This will print out the dependency graph when building. This can be useful to help debug issues.\n\n### Additional docs\n\nYou can find additional docs on specific use-cases in the [docs](docs) folder.\n\n- [Testing](docs/testing.md)\n- [Android](docs/android.md)\n- [Multiplatform](docs/multiplatform.md)\n\n## Samples\n\nYou can find various samples [here](https://github.com/evant/kotlin-inject-samples)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fkotlin-inject","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevant%2Fkotlin-inject","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fkotlin-inject/lists"}