What is a NamedDomainObjectProvider, how do you obtain one, and how does it keep container access lazy?
answer
- lazy handle to one named element
- from register(...) or named(name)
- configure{}/map don't realize
- get() triggers realization
- named = lazy, getByName = eager
basics
~10 sIt's a lazy handle to a named element returned by register or named(name). Holding or configuring it (configure { }) doesn't realize the element; only get() does — so wiring stays deferred.
solid answer
~40 sA `NamedDomainObjectProvider<T>` is the container's configuration-avoidant reference to a single named element. You get one from `register(name)` or by looking up an existing registration with `named(name)` (or `named(name, Type)` for the typed overload). The key property: obtaining the provider, calling `configure { }` on it, or `map`/`flatMap` over it does **not** realize the underlying element — realization happens only when something calls `get()` or otherwise resolves the value (e.g. wiring it into a task input that runs). This lets you reference and partially configure elements that may never be needed without paying their cost. It extends Gradle's `Provider` type, so it composes with `Property` wiring: you can `map` a provider's attribute and feed it into another task's input lazily. Prefer `named` over `getByName` whenever you only need a lazy handle.
code
kotlin · 12 linesval tasksC = project.tasks
// Lazy lookup of an existing registration
val compileJava: TaskProvider<*> = tasksC.named("compileJava")
// Configure without realizing
compileJava.configure { /* runs only if compileJava is realized */ }
// Wire lazily into another task's input
tasks.register("report") {
inputs.files(compileJava.map { it.outputs.files })
}go deeper
Know it's a lazy reference to a named element returned by register/named.
Explain that configure/map keep it lazy and only get() realizes, and that named beats getByName for laziness.
Show composing the provider via map/flatMap into Property-based task inputs to preserve end-to-end laziness.
Establish provider-based wiring as the standard and treat eager getByName/findByName in plugins as configuration-time debt.
## What it is `NamedDomainObjectProvider<T>` is a subtype of Gradle's `Provider<T>` specialized for container elements. It's a **lazy reference** to exactly one named element, plus a `configure(Action)` method to queue further configuration of that element without realizing it. ## How you get one - `container.register("name") { ... }` returns a provider for the newly registered (not yet realized) element. - `container.named("name")` returns a provider for an element that already exists in the registration set (throws if the name is unknown). - `container.named("name", Type::class.java)` is the typed overload, giving a `NamedDomainObjectProvider<Type>` and validating the type lazily. ## Why it stays lazy The whole point is configuration avoidance. These operations do **not** realize the element: - Holding the provider in a variable. - `provider.configure { ... }` — queues an action that runs when (and if) the element is realized. - `provider.map { it.someProperty }` / `flatMap { ... }` — derives another lazy provider. Realization is triggered by `provider.get()`, `provider.orNull` resolution, or wiring the provider into something that actually executes (a task input/dependency that runs). ## Contrast with eager lookup `container.getByName("name")` and `findByName("name")` both **realize** the element to return the concrete object. So `named(...)` is the lazy lookup, `getByName(...)` is the eager one. In modern plugin code, reach for `named`. ## Composing with Property wiring Because it's a `Provider`, you can wire an element's lazy attribute straight into a task: ```kotlin val envs = objects.domainObjectContainer(Environment::class.java) val dev: NamedDomainObjectProvider<Environment> = envs.register("dev") { url.convention("https://dev.example.com") } // Lazy: deploy is only wired; dev realizes when deploy runs. tasks.register("deployDev", DeployTask::class.java) { target.set(dev.map { it.url.get() }) } // Later configuration without realizing: dev.configure { timeoutSeconds.set(30) } ``` Nothing about `dev` runs unless `deployDev` is part of the executed task graph — that's the laziness payoff.
- Does calling configure { } on a NamedDomainObjectProvider realize the element?No. configure queues an action that runs only when the element is later realized; it preserves laziness. Only get()/value resolution forces realization.
- What's the difference between named(name) and getByName(name)?named returns a lazy NamedDomainObjectProvider without realizing the element; getByName realizes the element immediately and returns the concrete object.
saying these in an interview costs you the question
- Saying named(...) realizes the element — it returns a lazy provider.
- Claiming you must call get() to configure an element — provider.configure{} works lazily.