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 AppGraph
The 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.