How do you publish an optional feature variant with the java-library plugin using registerFeature, and what does usingSourceSet do?
answer
- java { registerFeature(name){ usingSourceSet(...) } }
- creates nameApi / nameImplementation
- capability = base + '-feature'
- main source set vs dedicated source set
- consumer: requireCapability
basics
~10 sIn the java block call registerFeature("name") { usingSourceSet(...) }. It creates nameApi/nameImplementation configurations and an optional variant with capability group:base-feature:version that consumers opt into via requireCapabilities.
solid answer
~40 sA **feature variant** lets one module ship optional functionality behind a distinct capability. With the `java-library` (or `java`) plugin you call `registerFeature` inside the `java {}` block: ```kotlin java { registerFeature("mongoSupport") { usingSourceSet(sourceSets["main"]) } } ``` This registers `mongoSupportApi` and `mongoSupportImplementation` dependency buckets and creates new outgoing variants (`mongoSupportApiElements`, `mongoSupportRuntimeElements`) carrying the capability `group:project-mongoSupport:version`. The feature's dependencies stay **optional** — a plain consumer doesn't get them. To pull them in, the consumer requests the capability via `requireCapabilities`/`requireCapability`. `usingSourceSet(main)` says the feature's classes live in the main source set; passing a **dedicated** source set instead keeps the feature's code physically separate and avoids it being published twice. Feature variants require Gradle Module Metadata to be honoured by consumers.
code
kotlin · 19 lines// Producer: optional Mongo support as a feature variant
val mongoSupport = sourceSets.create("mongoSupport")
java {
registerFeature("mongoSupport") {
usingSourceSet(mongoSupport)
}
}
dependencies {
"mongoSupportImplementation"("org.mongodb:mongodb-driver-sync:4.11.0")
}
// Consumer opts in by requesting the capability
dependencies {
implementation("com.example:json-lib:1.0") {
capabilities { requireCapability("com.example:json-lib-mongoSupport") }
}
}go deeper
Know that registerFeature creates an optional variant and that consumers must opt in.
Show the registerFeature/usingSourceSet syntax, the generated configurations, and how a consumer requests the capability.
Contrast main vs dedicated source set, explain the generated capability naming, and how it publishes via Module Metadata.
Position feature variants as a way to ship one artifact with optional integrations instead of N coupling modules, and weigh the Maven-consumer interop cost.
## The problem feature variants solve A library sometimes has *optional* functionality: e.g. a JSON library with optional Mongo support that only some consumers need, pulling in an optional `mongodb-driver` dependency. You don't want every consumer to drag in that driver. Maven's answer is `<optional>true` (consumer must re-declare it). Gradle's answer is a **feature variant**: an opt-in variant identified by its own **capability**. ## Declaring a feature With the `java`/`java-library` plugin: ```kotlin java { registerFeature("mongoSupport") { usingSourceSet(sourceSets["main"]) } } dependencies { "mongoSupportImplementation"("org.mongodb:mongodb-driver-sync:4.11.0") } ``` `registerFeature("mongoSupport")` does several things: - creates dependency buckets `mongoSupportApi` and `mongoSupportImplementation`; - creates **consumable variants** `mongoSupportApiElements` and `mongoSupportRuntimeElements`; - gives those variants a capability `${group}:${name}-mongoSupport:${version}` (the base capability with `-featureName` appended). ## What usingSourceSet controls `usingSourceSet(sourceSet)` declares **which source set produces the feature's classes**. - `usingSourceSet(sourceSets["main"])` — the feature shares the main classes. Use when the optional code is already compiled into the main jar and only the *dependencies* are optional. Note: a source set can back only one feature this way, and using `main` means no separate artifact. - A **dedicated** source set (e.g. `sourceSets.create("mongoSupport")`) — the feature has its **own** classes, compiled separately and published as a **separate jar** with a classifier. This is the cleaner pattern when the optional code is genuinely separate. ```kotlin val mongoSupport = sourceSets.create("mongoSupport") java { registerFeature("mongoSupport") { usingSourceSet(mongoSupport) } } ``` ## How a consumer opts in The consumer requests the capability: ```kotlin dependencies { implementation("com.example:json-lib:1.0") { capabilities { requireCapability("com.example:json-lib-mongoSupport") } } } ``` Without that request the feature's `mongodb-driver` dependency is **not** added. ## Publishing When you publish with `maven-publish` and the `java` component, feature variants are included automatically in **Gradle Module Metadata**. Maven-only consumers (reading the POM) will see the dedicated-source-set artifact only as a classified jar without the optional-dependency wiring — feature variants are fully expressed only through `.module` metadata. ## Key APIs - `java { registerFeature(name) { usingSourceSet(ss) } }` - generated buckets: `${name}Api`, `${name}Implementation` - capability: `group:base-name:version` with `-feature` suffix - consumer: `requireCapability(...)`
- What capability name is generated for a feature called 'mongoSupport' in module com.example:json-lib?`com.example:json-lib-mongoSupport:<version>` — the base GAV with the feature name appended to the artifact name.
- When would you use a dedicated source set instead of usingSourceSet(main)?When the optional code is genuinely separate and you want it compiled and published as its own classified jar, so consumers who don't opt in never load those classes — not just skip the dependency.
- Does a normal consumer get the feature's dependencies automatically?No. Feature dependencies are pulled in only when the consumer explicitly requests the feature's capability via requireCapability.
saying these in an interview costs you the question
- Saying registerFeature lives in the dependencies block — it's inside the java {} block.
- Claiming the feature's optional dependencies are added to every consumer by default.