ContributesGraphExtension
Generates a graph extension when the parent graph interface is merged.
The Problem
Imagine this module dependency tree:
:app
/ \
v v
:login :user-data:app defines the main dependency graph with @DependencyGraph. The :login module defines a graph extension for authenticated user flows, and :user-data provides some core functionality like UserRepository.
If :login defines its own graph directly with @DependencyGraph, it won't see contributions from :user-data unless :login depends on it directly.
The Solution
Instead, :login can use @ContributesGraphExtension(LoggedInScope::class) to say: "I want to contribute a new graph extension to the app graph." The extension will be generated in :app, which already depends on both :login and :user-data. Now UserRepository can be injected in LoggedInGraph.
@ContributesGraphExtension(LoggedInScope::class)
interface LoggedInGraph {
val userRepository: UserRepository
@ContributesGraphExtension.Factory(AppScope::class)
interface Factory {
fun createLoggedInGraph(): LoggedInGraph
}
}In the :app module:
@DependencyGraph(AppScope::class, isExtendable = true)
interface AppGraphThe generated code will modify AppGraph to implement LoggedInGraph.Factory and implement createLoggedInGraph() using a generated final $$ContributedLoggedInGraph class that includes all contributed bindings, including UserRepository from :user-data.
// modifications generated during compile-time
interface AppGraph : LoggedInGraph.Factory {
override fun createLoggedInGraph(): LoggedInGraph {
return $$ContributedLoggedInGraph(this)
}
// Generated in IR
class LoggedInGraph$$MetroGraph(appGraph: AppGraph) : LoggedInGraph {
// ...
}
}Finally, you can obtain a LoggedInGraph instance from AppGraph since it now implements LoggedInGraph.Factory:
// Using the asContribution() intrinsic
val loggedInGraph = appGraph.asContribution<LoggedInGraph.Factory>().createLoggedInGraph()
// Or if you have IDE support enabled
val loggedInGraph = appGraph.createLoggedInGraph()Graph arguments
You can pass arguments to the graph via the factory:
@ContributesGraphExtension.Factory(AppScope::class)
interface Factory {
fun create(@Provides userId: String): LoggedInGraph
}This maps to:
// Generated in IR
@DependencyGraph(LoggedInScope::class)
class $$ContributedLoggedInGraph(
@Extends parent: AppGraph,
@Provides userId: String
): LoggedInGraph {
// ...
}In AppGraph, the generated factory method looks like:
// Generated in IR
override fun create(userId: String): LoggedInGraph {
return LoggedInGraph$$MetroGraph(this, userId)
}Note: Abstract factory classes cannot be used as graph contributions.
Contributed graphs may also be chained, but note that isExtendable must be true to do so!
Types
Properties
Optional list of included binding containers. See the doc on BindingContainer for more details.
If enabled, marks this graph as available for extension and generates extra metadata about this graph's available bindings for child graphs to read.