How do you obtain Property and Provider instances in a plugin, and why can't you instantiate them directly?
answer
- Provider/Property are interfaces, no new
- project.objects.property(Type::class)
- @Inject ObjectFactory in managed types
- project.provider { } for read-only
- abstract managed properties = Gradle instantiates
basics
~10 sThey're interfaces with no public constructor. You create a Property via ObjectFactory (project.objects.property(Type::class)) and create read-only Providers via project.provider { ... } or by transforming an existing Provider.
solid answer
~40 s`Provider<T>` and `Property<T>` are **interfaces**, so you never `new` them — Gradle owns their implementations. For a writable `Property`, ask the `ObjectFactory`, available as `project.objects`: `objects.property(String::class)`. ObjectFactory is also injectable into task and extension constructors via `@Inject`, which is the preferred way inside managed types so Gradle wires instances for you. For a read-only `Provider` computed from a closure, use `project.provider { ... }`; for one derived from an existing provider, use transformations that return a new `Provider`. Creating through the factory (rather than a constructor) lets Gradle attach the laziness machinery, presence tracking, and configuration-cache support that a hand-rolled object couldn't provide. In a custom task or extension you typically declare these as abstract `@get:Input`/`@Internal` properties and let Gradle's managed-property mechanism instantiate them automatically.
code
kotlin · 5 linesabstract class StampExtension @Inject constructor(objects: ObjectFactory) {
val version: Property<String> = objects.property(String::class)
// or, fully managed:
// abstract val version: Property<String>
}go deeper
Know that you create a Property via project.objects.property(Type::class), not a constructor.
Distinguish ObjectFactory for writable Property vs project.provider for read-only Provider; mention @Inject.
Recommend abstract managed properties as the idiomatic style and explain why Gradle owns the implementations (laziness + config cache).
Standardize managed-property authoring conventions across the team's plugins to keep types config-cache compatible and consistent.
## Why no constructor `Property<T>` and `Provider<T>` are Gradle **interfaces**. Their concrete implementations carry internal state for lazy evaluation, presence, conventions, and configuration-cache serialization. Gradle deliberately hides those classes so it can evolve them and guarantee the laziness contract — hence you always go through a factory. ## ObjectFactory — the source of Properties `ObjectFactory` is a Gradle service exposed as `project.objects`. Relevant methods: - `property(Class<T>)` — a `Property<T>`. - `listProperty/mapProperty/setProperty` — collection variants (separate leaf). - `fileProperty()`, `directoryProperty()` — file-typed variants (separate leaf). ```kotlin val objects = project.objects val name: Property<String> = objects.property(String::class) val count: Property<Int> = objects.property(Int::class) ``` ## Injecting ObjectFactory Inside a custom task or extension, prefer constructor injection so the object is managed: ```kotlin abstract class GreetingExtension @Inject constructor(objects: ObjectFactory) { val message: Property<String> = objects.property(String::class) } ``` ## Read-only Providers When you just need a lazily-computed read-only value: - `project.provider { expensiveCompute() }` — wraps a closure. - Transforming an existing provider returns a new `Provider` (still read-only). ## Managed (abstract) properties — the modern style Instead of creating instances yourself, declare abstract getters and let Gradle implement them: ```kotlin abstract class MyExtension { abstract val message: Property<String> // Gradle provides the instance } ``` Gradle's managed-type mechanism instantiates the backing `Property` automatically when it creates the extension/task. This is the cleanest approach and avoids touching ObjectFactory at all. ## Summary Writable `Property` -> `objects.property(...)` or an abstract managed getter. Read-only `Provider` -> `project.provider { }` or a transformation. Never a constructor — Gradle owns the implementations.
- What's the advantage of declaring an abstract Property instead of creating one via ObjectFactory?Gradle's managed-type mechanism instantiates the backing property for you, so there's less boilerplate, no @Inject of ObjectFactory, and it's the idiomatic style for tasks and extensions.
- How do you make a read-only Provider from a computation?Use project.provider { ... } to wrap a closure that returns the value lazily, or derive it from an existing provider via a transformation — both return a Provider you cannot set().
saying these in an interview costs you the question
- Trying to call a Property/Provider constructor.
- Storing the resolved value in a plain field instead of using ObjectFactory.
- Confusing project.provider { } (read-only) with objects.property (writable).