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:
@AssistedFactory@AssistedInject@Assisted@BindsInstance@Binds@ContributesBinding@ContributesTo@DependencyGraph.Factory@DependencyGraph@ElementsIntoSet@Inject@IntoMap@IntoSet@MapKey@Module@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.
binding in Metro uses a more flexible mechanism to support generics, but interop with Anvil’s boundType: KClass<*> property is supported.
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(
@Includes 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 = [MessageGraph::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
ProviderandLazyruntime 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.