{"id":13428800,"url":"https://github.com/square/anvil","last_synced_at":"2025-05-14T05:10:34.494Z","repository":{"id":37829748,"uuid":"271357426","full_name":"square/anvil","owner":"square","description":"A Kotlin compiler plugin to make dependency injection with Dagger 2 easier.","archived":false,"fork":false,"pushed_at":"2025-05-05T21:57:19.000Z","size":6359,"stargazers_count":1380,"open_issues_count":60,"forks_count":88,"subscribers_count":25,"default_branch":"main","last_synced_at":"2025-05-12T08:56:22.142Z","etag":null,"topics":["dagger2","dagger2-android","kotlin","kotlin-compiler-plugin"],"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/square.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-10T18:42:16.000Z","updated_at":"2025-05-10T05:50:31.000Z","dependencies_parsed_at":"2023-02-18T13:00:51.636Z","dependency_job_id":"851e2612-b5d0-4c55-b349-a9bb3340cadc","html_url":"https://github.com/square/anvil","commit_stats":null,"previous_names":["square/hephaestus"],"tags_count":84,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/square%2Fanvil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/square%2Fanvil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/square%2Fanvil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/square%2Fanvil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/square","download_url":"https://codeload.github.com/square/anvil/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254076849,"owners_count":22010611,"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":["dagger2","dagger2-android","kotlin","kotlin-compiler-plugin"],"created_at":"2024-07-31T01:01:05.459Z","updated_at":"2025-05-14T05:10:34.473Z","avatar_url":"https://github.com/square.png","language":"Kotlin","readme":"# Anvil\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.squareup.anvil/gradle-plugin.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.squareup.anvil%22)\n[![CI](https://github.com/square/anvil/workflows/CI/badge.svg)](https://github.com/square/anvil/actions?query=branch%3Amain)\n\n\u003e _\"When all you have is an anvil, every problem looks like a hammer.\"_ - [Abraham Maslow](https://en.wikipedia.org/wiki/Law_of_the_instrument)\n\nAnvil is a Kotlin compiler plugin to make dependency injection with [Dagger](https://dagger.dev/)\neasier by automatically merging Dagger modules and component interfaces. In a nutshell, instead of\nmanually adding modules to a Dagger component and making the Dagger component extend all component\ninterfaces, these modules and interfaces can be included in a component automatically:\n\n```kotlin\n@Module\n@ContributesTo(AppScope::class)\nclass DaggerModule { .. }\n\n@ContributesTo(AppScope::class)\ninterface ComponentInterface {\n  fun getSomething(): Something\n  fun injectActivity(activity: MyActivity)\n}\n\n// The real Dagger component.\n@MergeComponent(AppScope::class)\ninterface AppComponent\n```\n\nThe generated `AppComponent` interface that Dagger sees looks like this:\n\n```kotlin\n@Component(modules = [DaggerModule::class])\ninterface AppComponent : ComponentInterface\n```\n\nNotice that `AppComponent` automatically includes `DaggerModule` and extends `ComponentInterface`.\n\n## Setup\n\nThe plugin consists of a Gradle plugin and Kotlin compiler plugin. The Gradle plugin automatically\nadds the Kotlin compiler plugin and annotation dependencies. It needs to be applied in all modules\nthat either contribute classes to the dependency graph or merge them:\n\n```groovy\nplugins {\n  id 'com.squareup.anvil' version \"${latest_version}\"\n}\n```\n\nOr you can use the old way to apply a plugin:\n```groovy\nbuildscript {\n  repositories {\n    mavenCentral()\n  }\n  dependencies {\n    classpath \"com.squareup.anvil:gradle-plugin:${latest_version}\"\n  }\n}\n\napply plugin: 'com.squareup.anvil'\n```\n\n## Quick Start\n\nThere are three important annotations to work with Anvil.\n\n`@ContributesTo` can be added to Dagger modules and component interfaces that should be included\nin the Dagger component. Classes with this annotation are automatically merged by the compiler\nplugin as long as they are on the compile classpath.\n\n`@MergeComponent` is used instead of the Dagger annotation `@Component`. Anvil will generate\nthe Dagger annotation and automatically include all modules and component interfaces that were\ncontributed the same scope.\n\n`@MergeSubcomponent` is similar to `@MergeComponent` and should be used for subcomponents instead.\n\n## Scopes\n\nScope classes are only markers. The class `AppScope` from the sample could look like this:\n\n```kotlin\nabstract class AppScope private constructor()\n```\n\nThese scope classes help Anvil make a connection between the Dagger component and which Dagger\nmodules and other component interfaces to include.\n\nScope classes are independent of the Dagger scopes. It's still necessary to set a scope for\nthe Dagger component, e.g.\n\n```kotlin\n@Singleton\n@MergeComponent(AppScope::class)\ninterface AppComponent\n```\n\n## Contributed bindings\n\nThe `@ContributesBinding` annotation generates a Dagger binding method for an annotated class and \ncontributes this binding method to the given scope. Imagine this example:\n```kotlin\ninterface Authenticator\n\nclass RealAuthenticator @Inject constructor() : Authenticator\n\n@Module\n@ContributesTo(AppScope::class)\nabstract class AuthenticatorModule {\n  @Binds abstract fun bindRealAuthenticator(authenticator: RealAuthenticator): Authenticator\n}\n```\nThis is a lot of boilerplate if you always want to use `RealAuthenticator` when injecting\n`Authenticator`. You can replace this entire Dagger module with the `@ContributesBinding` \nannotation. The equivalent would be:\n```kotlin\ninterface Authenticator\n\n@ContributesBinding(AppScope::class)\nclass RealAuthenticator @Inject constructor() : Authenticator\n```\n\n`@ContributesBinding` also supports qualifiers. You can annotate the class with any qualifier \nand the generated binding method will preserve the qualifier, e.g.\n```kotlin\n@ContributesBinding(AppScope::class)\n@Named(\"Prod\")\nclass RealAuthenticator @Inject constructor() : Authenticator\n\n// Will generate:\n@Binds @Named(\"Prod\") \nabstract fun bindRealAuthenticator(authenticator: RealAuthenticator): Authenticator\n```\n\n## Contributed multibindings\n\nSimilar to contributed bindings, `@ContributesMultibinding` will generate a multibindings method \nfor (all/an) annotated class(es). Qualifiers are supported the same way as normal bindings.\n```kotlin\n@ContributesMultibinding(AppScope::class)\n@Named(\"Prod\")\nclass MainListener @Inject constructor() : Listener\n\n// Will generate this binding method.\n@Binds @IntoSet @Named(\"Prod\")\nabstract fun bindMainListener(listener: MainListener): Listener\n```\nIf the class is annotated with a map key annotation, then Anvil will generate a maps multibindings \nmethod instead of adding the element to a set:\n```kotlin\n@MapKey\nannotation class BindingKey(val value: String)\n\n@ContributesMultibinding(AppScope::class)\n@BindingKey(\"abc\")\nclass MainListener @Inject constructor() : Listener\n\n// Will generate this binding method.\n@Binds @IntoMap @BindingKey(\"abc\")\nabstract fun bindMainListener(listener: MainListener): Listener\n```\n\n## Exclusions\n\nDagger modules and component interfaces can be excluded in two different levels.\n\nOne class can always replace another one. This is especially helpful for modules that provide\ndifferent bindings for instrumentation tests, e.g.\n\n```kotlin\n@Module\n@ContributesTo(\n    scope = AppScope::class,\n    replaces = [DevelopmentApplicationModule::class]\n)\nobject DevelopmentApplicationTestModule {\n  @Provides\n  fun provideEndpointSelector(): EndpointSelector = TestingEndpointSelector\n}\n```\n\nThe compiler plugin will find both classes on the classpath. Adding both modules\n`DevelopmentApplicationModule` and `DevelopmentApplicationTestModule` to the Dagger graph would\nlead to duplicate bindings. Anvil sees that the test module wants to replace the other and\nignores it. This replacement rule has a global effect for all applications which are including the\nclasses on the classpath.\n\nApplications can exclude Dagger modules and component interfaces individually without affecting\nother applications.\n\n```kotlin\n@MergeComponent(\n  scope = AppScope::class,\n  exclude = [\n    DaggerModule::class\n  ]\n)\ninterface AppComponent\n```\n\nIn a perfect build graph it’s unlikely that this feature is needed. However, due to legacy modules,\nwrong imports and deeply nested dependency chains applications might need to make use of it. The\nexclusion rule does what it implies. In this specific example `DaggerModule` wishes to be\ncontributed to this scope, but it has been excluded for this component and thus is not added.\n\n## Dagger Factory Generation\n\nAnvil allows you to generate Factory classes that usually the Dagger annotation processor would\ngenerate for `@Provides` methods, `@Inject` constructors and `@Inject` fields. The benefit of this\nfeature is that you don't need to enable the Dagger annotation processor in this module. That often\nmeans you can skip KAPT and the stub generating task. In addition Anvil generates Kotlin instead\nof Java code, which allows Gradle to skip the Java compilation task. The result is faster\nbuilds.\n\n\u003cdetails open\u003e\n\u003csummary\u003eGradle DSL\u003c/summary\u003e\n\n```groovy\n// build.gradle\nanvil {\n  generateDaggerFactories = true // default is false\n}\n```\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003eGradle Properties\u003c/summary\u003e\n\n```properties\n# gradle.properties\ncom.squareup.anvil.generateDaggerFactories=true # default is false\n```\n\u003c/details\u003e\n\nIn our codebase we measured that modules using Dagger build 65% faster with this new Anvil feature\ncompared to using the Dagger annotation processor:\n\n|| Stub generation | Kapt | Javac | Kotlinc | Sum\n:--- | ---: | ---: | ---: | ---: | ---:\nDagger | 12.976 | 40.377 | 8.571 | 10.241 | 72.165\nAnvil | 0 | 0 | 6.965 | 17.748 | 24.713\n\nFor full builds of applications we measured savings of 16% on average.\n\n![Benchmark Dagger Factories](images/benchmark_dagger_factories.png?raw=true \"Benchmark Dagger Factories\")\n\nThis feature can only be enabled in Gradle modules that don't compile any Dagger component. Since\nAnvil only processes Kotlin code, you shouldn't enable it in modules with mixed Kotlin / Java\nsources either.\n\nWhen you enable this feature, don't forget to remove the Dagger annotation processor. You should\nkeep all other dependencies.\n\n## Extending Anvil\n\nEvery codebase has its own dependency injection patterns where certain code structures need to be\nrepeated over and over again. Here Anvil comes to the rescue and you can extend the compiler \nplugin with your own `CodeGenerator`. For usage please take a look at the \n[`compiler-api` artifact](compiler-api/README.md)\n\n## Advantages of Anvil\n\nAdding Dagger modules to components in a large modularized codebase with many application targets\nis overhead. You need to know where components are defined when creating a new Dagger module and\nwhich modules to add when setting up a new application. This task involves many syncs in the IDE\nafter adding new module dependencies in the build graph. The process is tedious and cumbersome.\nWith Anvil you only add a dependency in your build graph and then you can immediately test\nthe build.\n\nAligning the build graph and Dagger's dependency graph brings a lot of consistency. If code is on\nthe compile classpath, then it's also included in the Dagger dependency graph.\n\nModules implicitly have a scope, if provided objects are tied to a scope. Now the scope of a module\nis clear without looking at any binding.\n\nWith Anvil you don't need any composite Dagger module anymore, which only purpose is to\ncombine multiple modules to avoid repeating the setup for multiple applications. Composite modules\neasily become hairballs. If one application wants to exclude a module, then it has to repeat the\nsetup. These forked graphs are painful and confusing. With Dagger you want to make the decision\nwhich modules fulfill dependencies as late as possible, ideally in the application module.\nAnvil makes this approach a lot easier by generating the code for included modules. Composite\nmodules are redundant. You make the decision which bindings to use by importing the desired module\nin the application module.\n\n## Performance\n\nAnvil is a convenience tool. Similar to Dagger it doesn't improve build speed compared to\nwriting all code manually before running a build. The savings are in developer time.\n\nThe median overhead of Anvil is around 4%, which often means only a few hundred milliseconds\non top. The overhead is marginal, because Kotlin code is still compiled incrementally and Kotlin\ncompile tasks are skipped entirely, if nothing has changed. This doesn't change with Anvil.\n\n![Benchmark](images/benchmark.png?raw=true \"Benchmark\")\n\nOn top of that, Anvil provides actual build time improvements by replacing the Dagger annotation\nprocessor in many modules if you enable [Dagger Factory generation](#dagger-factory-generation).\n\n## Kotlin compiler plugin\n\nWe investigated whether other alternatives like a bytecode transformer and an annotation processor\nwould be a better option, but ultimately decided against them. For what we tried to achieve a\nbytecode transformer runs too late in the build process; after the Dagger components have been\ngenerated. An annotation processor especially when using KAPT would be too slow. Even though the\nKotlin compiler plugin API isn't stable and contains bugs we decided to write a compiler plugin.\n\n## Limitations\n\n#### No Java support\n\nAnvil is a Kotlin compiler plugin, thus Java isn’t supported. You can use Anvil in\nmodules with mixed Java and Kotlin code for Kotlin classes, though.\n\n#### Correct error types disabled\n\nKAPT has the option to\n[correct non-existent types](https://kotlinlang.org/docs/kapt.html#non-existent-type-correction).\nThis option however changes order of how compiler plugins and KAPT itself are invoked. The result\nis that Anvil cannot merge supertypes before the Dagger annotation processor runs and abstract\nfunctions won't be implemented properly in the final Dagger component.\n\nAnvil will automatically set `correctErrorTypes` to false to avoid this issue.\n\n#### Incremental Kotlin compilation breaks Anvil's feature to merge contributions\n\n\u003e [!TIP]\n\u003e Anvil now supports incremental compilation and Gradle's build caching,\n\u003e as of [v2.5.0](https://github.com/square/anvil/releases/tag/v2.5.0-beta01).\n\u003e\n\u003e This feature is enabled by default.\n\u003e It can be disabled via a Gradle property or the Gradle DSL:\n\u003e \u003cdetails open\u003e\n\u003e \u003csummary\u003eGradle Properties\u003c/summary\u003e\n\u003e \n\u003e ```properties\n\u003e # gradle.properties\n\u003e com.squareup.anvil.trackSourceFiles=false # default is true\n\u003e ```\n\u003e \n\u003e \u003c/details\u003e\n\u003e \u003cdetails\u003e\n\u003e \u003csummary\u003eGradle DSL\u003c/summary\u003e\n\u003e \n\u003e ```groovy\n\u003e // build.gradle\n\u003e anvil {\n\u003e   trackSourceFiles = false // default is true\n\u003e }\n\u003e ```\n\u003e \u003c/details\u003e\n\nAnvil merges Dagger component interfaces and Dagger modules during the stub generating task\nwhen `@MergeComponent` is used. This requires scanning the compile classpath for any contributions.\nAssume the scenario that a contributed type in a module dependency has changed, but the module\nusing `@MergeComponent` itself didn't change. With Kotlin incremental compilation enabled the\ncompiler will notice that the module using `@MergeComponent` doesn't need to be recompiled and\ntherefore doesn't invoke compiler plugins. Anvil will miss the new contributed type from the module\ndependency.\n\nTo avoid this issue, Anvil must disable incremental compilation for the stub generating task, which\nruns right before Dagger processes annotations. Normal Kotlin compilation isn't impacted by this\nworkaround. The issue is captured in\n[KT-54850 Provide mechanism for compiler plugins to add custom information into binaries](https://youtrack.jetbrains.com/issue/KT-54850/Provide-mechanism-for-compiler-plugins-to-add-custom-information-into-binaries).\n\nDisabling incremental compilation for the stub generating task could have a negative impact on\ncompile times, if you heavily rely on KAPT. While Anvil can\n[significantly help to improve build times](#dagger-factory-generation), the wrong configuration\nand using KAPT in most modules could make things worse. The\nsuggestion is to extract and isolate annotation processors in separate modules and avoid using Anvil\nin the same modules, e.g. a common practice is to move the Dagger component using `@MergeComponent`\ninto the final application module with little to no other code in the app module.\n\n## Hilt\n\n[Hilt](https://dagger.dev/hilt/) is Google's opinionated guide how to dependency injection on\nAndroid. It provides a similar feature with `@InstallIn` for entry points and modules as Anvil.\nIf you use Hilt, then you don't need to use Anvil.\n\nHilt includes many other features and comes with some restrictions. For us it was infeasible to\nmigrate a codebase to Hilt with thousands of modules and many Dagger components while we only\nneeded the feature to merge modules and component interfaces automatically. We also restrict the\nusage of the Dagger annotation processor to only [specific modules](https://speakerdeck.com/vrallev/android-at-scale-at-square?slide=36)\nfor performance reasons. With Hilt we wouldn't be able to enforce this requirement anymore for\ncomponent interfaces. The development of Anvil started long before Hilt was announced and the\ninternal version is being used in production for a while.\n\n## Roadmap\nSee [here](https://github.com/square/anvil/blob/main/docs/ROADMAP.md)\n\n## License\n\n    Copyright 2020 Square, Inc.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n","funding_links":[],"categories":["Libraries","IoC"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsquare%2Fanvil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsquare%2Fanvil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsquare%2Fanvil/lists"}