DependencyGraph

@Target(allowedTargets = [AnnotationTarget.CLASS])
annotation class DependencyGraph(val scope: KClass<*> = Nothing::class, val additionalScopes: Array<KClass<*>> = [], val excludes: Array<KClass<*>> = [], val isExtendable: Boolean = false, val bindingContainers: Array<KClass<*>> = [])(source)

Declares the annotated type to be a dependency graph. Metro's compiler plugin will build, validate, and implement this graph at compile-time.

Graph types must be either an interface or an abstract class.

Scoping

See Scope before reading this section!

Graphs may declare a scope (and optionally additionalScopes if there are more). Each of these declared scopes act as an implicit SingleIn representation of that scope. For example:

@DependencyGraph(AppScope::class)
interface AppGraph

Is functionally equivalent to writing the below.

@SingleIn(AppScope::class)
@DependencyGraph(AppScope::class)
interface AppGraph

Creating a graph

For simple graphs with no creator types, an implicit one will be generated. You can instantiate them with createGraph.

val graph = createGraph<AppGraph>()

For creators (more below), you can create a factory with createGraphFactory.

val graph = createGraphFactory<AppGraph.Factory().create("hello!")

Providers

Graph types can declare providers via Provides and Binds to provide dependencies into the graph.

Graph creators can provide instance dependencies and other graphs as dependencies.

@DependencyGraph
interface AppGraph {
val httpClient: HttpClient

@Provides fun provideHttpClient: HttpClient = HttpClient()
}

Creators

Graphs can have creators. Right now, this just means Factory creators. See its doc for more details.

Aggregation

Graphs can automatically aggregate contributed bindings and interfaces. Any contributions to the same scope will be automatically aggregated to this graph. This includes contributions generated from ContributesTo (supertypes), ContributesBinding, ContributesIntoSet, and ContributesIntoMap.

@DependencyGraph(AppScope::class)
interface AppGraph

@ContributesTo(AppScope::class)
interface HttpClientProvider {
val httpClient: HttpClient
}

@ContributesBinding(AppScope::class)
@Inject
class RealHttpClient(...) : HttpClient

// Results in generated code like...
@DependencyGraph(AppScope::class)
interface AppGraph : HttpClientProvider {
/* fake */override val RealHttpClient.bind: HttpClient
}

Graph Extensions

Dependency graphs can be marked as extendable to allow child graphs to extend them. These are similar in functionality to Dagger’s Subcomponents but are detached in nature like in kotlin-inject.

A graph must opt itself into extension in via marking isExtendable to true, which will make the Metro compiler generate extra metadata for downstream child graphs.

Then, a child graph can add an @Extends-annotated parameter to its creator to extend that graph.

@DependencyGraph(isExtendable = true)
interface AppGraph {
@Provides fun provideHttpClient(): HttpClient { ... }
}

@DependencyGraph
interface UserGraph {
@DependencyGraph.Factory
fun interface Factory {
fun create(@Extends appGraph: AppGraph): UserGraph
}
}

Child graphs then contain a superset of bindings they can inject, including both their bindings and their parents'. Graph extensions can be chained as well.

Child graphs also implicitly inherit their parents’ scopes.

Hoisting unused scoped class injections in parent graphs

In some cases, there are scoped bindings that are unused in the parent graph but are used in child graphs. Due to the detached nature of graph extensions, these bindings by default end up scoped to the child. To enforce that these bindings are scoped and held by the parent, Metro generates hints for these classes and discovers them during graph processing by default. You can disable this via the enableScopedInjectClassHints property in the Gradle DSL.

Note that this must be enabled in the compilation of the scoped class itself.

Types

Link copied to clipboard
@Target(allowedTargets = [AnnotationTarget.CLASS])
annotation class Factory

Graph factories can be declared as a single nested declaration within the target graph to create instances with bound instances (via Provides), graph dependencies (via Includes), or parent graphs to extend (via Extends).

Properties

Link copied to clipboard
Link copied to clipboard

Optional list of included binding containers. See the doc on BindingContainer for more details.

Link copied to clipboard

Optional list of excluded contributing classes (requires a scope to be defined).

Link copied to clipboard
val isExtendable: Boolean = false

If enabled, marks this graph as available for extension and generates extra metadata about this graph's available bindings for child graphs to read.

Link copied to clipboard
val scope: KClass<*>