You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by "gnodet (via GitHub)" <gi...@apache.org> on 2026/08/27 08:46:20 UTC

Re: [PR] [MNG-8099] Add explicit 'api' scope for dependencies and make 'compile' non-transitive for Maven 4 [maven]

gnodet commented on PR #12745:
URL: https://github.com/apache/maven/pull/12745#issuecomment-5436611779

   Thanks for the effort on this, @Hiteshsai007. The `api`/`implementation` split is a feature the community has been asking for, and it's worth getting the design right.
   
   Here are a few concerns and an alternative design proposal:
   
   ### Model version
   
   Changing the semantics of `compile` scope cannot land in model 4.1.0 — it would need to be model `>= 4.2.0`. The 4.1.0 model is already defined and changing existing scope behavior within it would be a breaking change to an established contract.
   
   ### Design concern: flipping `compile` semantics
   
   Making `compile` non-transitive and adding `api` as the transitive replacement inverts 20+ years of meaning. This creates a serious migration hazard: bumping `modelVersion` to 4.2.0 without migrating scopes would silently break runtime classpaths — everything compiles fine, then fails at runtime with `ClassNotFoundException`. The current consumer POM builder strips non-transitive scopes, so downstream consumers would lose those dependencies entirely.
   
   ### Alternative proposal: additive, not rename
   
   Instead of changing what `compile` means, introduce two **new** scopes alongside the existing ones:
   
   | Scope | Build paths | Transitive | Gradle equivalent |
   |---|---|---|---|
   | `compile` (unchanged) | compile + runtime + test | Yes | `api` |
   | `compile-only` (unchanged) | compile only | No | `compileOnly` |
   | **`api`** (new) | compile + runtime + test | Yes | `api` |
   | **`implementation`** (new) | compile + runtime + test | No | `implementation` |
   
   `api` is semantically identical to `compile` — it exists to express intent ("this is part of my public API"). `implementation` is the new scope that provides the non-transitive behavior the PR is after. `compile` keeps its current meaning across all model versions — including as the default scope when `<scope>` is omitted.
   
   This is purely additive — no existing behavior changes, no silent breakage on model version bump, and no change to the default scope. Projects adopt `api`/`implementation` at their own pace.
   
   ### Phased rollout
   
   A concern with the additive approach is adoption — if the default doesn't change, there's no forcing function to get projects to use the new scopes. A phased rollout addresses this:
   
   **Model 4.2.0** — introduces `api` and `implementation` as new scopes. A model-level flag (e.g. `<defaultScope>`) controls the default scope when `<scope>` is omitted. The flag defaults to `api` (preserving today's transitive behavior). Early adopters can set it to `implementation` to get non-transitive defaults immediately.
   
   **Model 4.3.0** — the flag defaults to `implementation`. The default scope becomes non-transitive for everyone.
   
   The effective model builder already resolves undefined scope to `compile` — it would just need to check the flag and resolve to `api` or `implementation` accordingly.
   
   This gives projects three levels of adoption speed:
   1. **Conservative**: bump to 4.2.0, don't touch the flag — nothing changes
   2. **Gradual**: bump to 4.2.0, start using `api`/`implementation` explicitly on some deps
   3. **Aggressive**: bump to 4.2.0, flip the flag — get 4.3.0 behavior immediately
   
   ### Consumer POM compatibility
   
   The consumer POM needs to remain consumable by Maven 3.x. The scope mapping when downgrading to model 4.0.0 would be:
   
   - `api` → `compile` — exact semantic match ✅
   - `implementation` → `runtime` — consumers can't compile against it (correct), it's present at runtime (correct), slightly wider transitivity than ideal but safe ✅
   
   This means `api`/`implementation` should **not** force the consumer POM model version up — they have clean 4.0.0 equivalents. The `DefaultConsumerPomBuilder` would need a scope mapping table instead of the current `isTransitive()` filter, but no changes to Maven 3.x are needed.
   
   ### Migration via `mvnup`
   
   - **4.1.0 → 4.2.0**: no-op — new scopes are available, default behavior unchanged
   - **4.2.0 → 4.3.0**: for every dependency without an explicit `<scope>`, inject `<scope>api</scope>` to preserve transitive behavior. Developers can then tighten to `implementation` where appropriate. Projects that already set the flag or adopted `api`/`implementation` explicitly need no changes.
   
   This mirrors the migration path Gradle users went through when `compile` was deprecated in favor of `api`/`implementation`.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org