Interop¶
Annotations¶
Metro supports user-defined annotations for common annotations. This means that a user doesn’t necessarily have to use Metro’s annotations if they’re introducing it to an existing codebase. Support varies depending on the annotation’s use case.
Compile-only annotations are mostly supported. This includes the following:
@Assisted
@AssistedFactory
@AssistedInject
@Binds
@BindsInstance
@ContributesTo
@ContributesBinding
@ElementsIntoSet
@DependencyGraph
@DependencyGraph.Factory
@Inject
@IntoMap
@IntoSet
@MapKey
@Multibinds
@Provides
@Qualifier
@Scope
These are configurable via Metro’s Gradle extension.
metro {
interop {
assisted.add("dagger/assisted/Assisted")
}
}
For Dagger and KI specifically, there are convenience helper functions.
metro {
interop {
includeDagger()
includeKotlinInject()
includeAnvil()
}
}
@DependencyGraph
is replaceable but your mileage may vary if you use Anvil or modules, since Metro’s annotation unifies Anvil’s @MergeComponent
functionality and doesn’t support modules.
Similarly, @ContributesBinding
is replaceable but there are not direct analogues for Anvil’s @ContributesMultibinding
or kotlin-inject-anvil’s @ContributesBinding(multibinding = …)
as these annotations are implemented as @ContributesInto*
annotations in Metro. Also - boundType
in metro uses a more flexible mechanism to support generics.
Components¶
Metro graphs can interop with components generated by Dagger and Kotlin-Inject. These work exclusively through their public accessors and can be depended on like any other graph dependency.
@DependencyGraph
interface MetroGraph {
val message: String
@DependencyGraph.Factory
fun interface Factory {
fun create(
daggerComponent: DaggerComponent
): MetroGraph
}
}
@dagger.Component
interface DaggerComponent {
val message: String
@dagger.Component.Factory
fun interface Factory {
fun create(@Provides message: String): DaggerComponent
}
}
Conversely, kotlin-inject and Dagger components can also depend on Metro graphs.
@DependencyGraph
interface MessageGraph {
val message: String
// ...
}
// Dagger
@Component(dependencies = [MetroGraph::class])
interface DaggerComponent {
val message: String
@Component.Factory
fun interface Factory {
fun create(messageGraph: MessageGraph): DaggerComponent
}
}
// kotlin-inject
@Component
abstract class KotlinInjectComponent(
@Component val messageGraph: MessageGraph
) {
abstract val message: String
}
Runtime¶
Enabling dagger interop also enables more advanced runtime interop with Dagger/Javax/Jakarta’s Provider
/Lazy
types.
metro {
interop {
includeDagger()
}
}
This specifically enables two features.
- Interop with Dagger/Javax/Jakarta’s
Provider
andLazy
runtime intrinsics. - Interop with generated Dagger factories for constructor-injected and assisted-injected classes. This means that an upstream class that was processed with the dagger compiler and has a generated Java factory class for a constructor injected class can be reused by Metro natively.
Note this also automatically adds an extra interop-dagger
dependency to support this scenario.