What is the difference between extensions.create() and extensions.add(), and when would you choose one over the other?
answer
- create() = ObjectFactory builds + decorates
- add() = register your own instance
- create supports abstract/@Nested/Property
- add(publicType,...) hides impl
- default to create()
basics
~10 screate() instantiates the extension for you via ObjectFactory (decorated, with managed Property/@Nested support) and registers it. add() registers an instance you already built yourself, with no decoration. Prefer create().
solid answer
~50 sBoth register an object in the `ExtensionContainer` so it gets a DSL block, but they differ in *who constructs it*. `extensions.create("name", Type::class.java, ctorArgs...)` asks Gradle's `ObjectFactory` to **instantiate and decorate** the type: abstract `Property`/`ListProperty` getters are materialized, `@Nested` sub-objects are created, and the instance is `ExtensionAware`. `extensions.add("name", existingInstance)` (or `add(publicType, name, instance)`) registers an object **you already constructed** with `new` — so it gets none of that managed decoration unless you built it yourself. You almost always want `create()` because it enables the modern managed/lazy model and nested DSL with zero boilerplate. Use `add()` only when you must register a pre-built or externally-supplied instance, or when you want to register it under a specific *public type* different from its concrete class (the `add(publicType, ...)` overload) so consumers see a clean interface. There's also `create(publicType, name, implType, args)` to combine decoration with a published public type.
code
kotlin · 6 lines// create(): Gradle instantiates & decorates (abstract Property OK)
project.extensions.create("greeting", GreetingExtension::class.java)
// add(): you supply the instance (must be concrete, self-wired)
val impl = DefaultGreeting(project.objects)
project.extensions.add(GreetingExtension::class.java, "greeting", impl) // published as interface typego deeper
Knowing create() is the normal way to register an extension is enough.
Explain that create() lets Gradle build/decorate the object while add() registers one you built yourself.
Pick create() for managed/lazy types and use add(publicType,...) to publish a clean public type; know why abstract types need create().
Standardize on create() across plugin suites and define when published public types are warranted for API stability.
## Same goal, different construction Both methods put an object into `project.extensions` so a matching DSL block appears. The difference is **instantiation and decoration**. ## extensions.create() ```kotlin project.extensions.create("greeting", GreetingExtension::class.java) ``` Gradle routes construction through `ObjectFactory`. That means: - abstract `Property<T>`, `ListProperty<T>`, `SetProperty`, `MapProperty` getters are **materialized** automatically; - `@Nested` abstract getters become managed sub-objects; - the instance is **decorated** and `ExtensionAware` (so it can host nested extensions); - constructor args you pass are forwarded. This is the modern, recommended path because it gives you the lazy/managed model for free. ## extensions.add() ```kotlin val mine = GreetingExtension(project.objects) // you build it project.extensions.add("greeting", mine) ``` `add` registers an **already-constructed** instance. Gradle does not decorate it: abstract managed getters are *not* auto-materialized (you'd get an abstract-class instantiation error if you tried), so you must use a concrete class and wire everything yourself. There is also a public-type overload: ```kotlin project.extensions.add(GreetingExtension::class.java, "greeting", impl) ``` which publishes the extension under a chosen **public type** (often an interface) while `impl` is the concrete object — useful for hiding implementation details from consumers' type-based lookups. ## When to use which | Need | Use | |---|---| | Managed `Property`/`@Nested`, least boilerplate | `create()` | | Register a pre-built / third-party instance | `add()` | | Publish under a clean public interface type | `add(publicType, name, impl)` or `create(publicType, name, impl, args)` | ## Practical guidance Default to `create()`. Reach for `add()` only when you genuinely cannot let Gradle construct the object, or you need precise control over the published public type. Mixing `add()` with abstract managed types is a common mistake — abstract types require `ObjectFactory` construction, which `create()` provides and bare `add()` does not.
- Why can create() handle an abstract extension class but bare add() cannot?create() constructs via ObjectFactory, which subclasses/decorates the abstract type and materializes managed getters. add() takes an already-built instance, so an abstract type can't be instantiated.
- When is the add(publicType, name, impl) overload useful?When you want consumers' getByType/the<>() lookups to resolve to a clean public interface while keeping the concrete implementation private.
saying these in an interview costs you the question
- Saying create() and add() are identical.
- Using add() with an abstract managed type (it fails — needs ObjectFactory via create()).
- Believing add() auto-materializes Property fields.