skip to content

How do you publish a java-platform that enforces alignment so consumers resolve a family to one consistent version?

level: middleimportance: should knowfreq 35%

answer

  1. java-platform plugin
  2. constraints { api(...) }
  3. consumer: platform("...")
  4. enforcedPlatform = strict override
  5. allowDependencies() to import BOMs

basics

~10 s

Apply the java-platform plugin, list the family modules under constraints in dependencies, and publish it. Consumers add platform("you:platform:v"). Because all constraints share the platform version, the family aligns when consumers omit explicit versions.

solid answer

~50 s

A reusable, *published* alignment artifact is a `java-platform`. You create a module that applies the `java-platform` plugin and declares the family's coordinates as **constraints** (under `dependencies { constraints { api("g:m:v") } }`). When you publish it (via `maven-publish`), it becomes a real platform consumers import with `platform("you:platform:1.0")`. Constraints provide the version, so consumers depend on the modules *without* versions and all resolve to the platform's coordinates. To *enforce* (override transitive versions rather than just suggest), consumers use `enforcedPlatform(...)`, or the platform itself can be authored to align. By default `java-platform` forbids declaring real dependencies (only constraints); set `javaPlatform { allowDependencies() }` if you must import another BOM. This is the in-house equivalent of a vendor BOM — versioned, shareable across many builds, and the cleanest way to give an org one source of truth for a family's version.

code

kotlin · 12 lines
kotlin
plugins { `java-platform`; `maven-publish` }

dependencies {
    constraints {
        api("com.fasterxml.jackson.core:jackson-core:2.15.2")
        api("com.fasterxml.jackson.core:jackson-databind:2.15.2")
    }
}

publishing {
    publications { create<MavenPublication>("platform") { from(components["javaPlatform"]) } }
}

go deeper

for a junior

Know that a java-platform is a publishable BOM consumers import with platform(...).

for a middle

Author one with constraints, publish it, and explain platform vs enforcedPlatform.

for a senior

Decide platform vs enforcedPlatform per risk, and compose platforms (allowDependencies + imported BOMs).

for a principal

Run a versioned org platform as the single source of truth for family versions; govern its release cadence.

## What a java-platform is The `java-platform` plugin builds a component that carries *no code* — only **dependency constraints**. It's Gradle's first-class BOM. Publishing it yields Gradle Module Metadata (and a Maven BOM POM) other builds can consume. ```kotlin plugins { `java-platform` `maven-publish` } dependencies { constraints { api("com.fasterxml.jackson.core:jackson-core:2.15.2") api("com.fasterxml.jackson.core:jackson-databind:2.15.2") api("com.fasterxml.jackson.core:jackson-annotations:2.15.2") } } publishing { publications { create<MavenPublication>("platform") { from(components["javaPlatform"]) } } } ``` ## How consumers use it ```kotlin dependencies { implementation(platform("com.acme:jackson-platform:1.0")) implementation("com.fasterxml.jackson.core:jackson-databind") // no version } ``` The `platform(...)` notation imports the constraints. Because every family member's version comes from the *same* platform, the family stays consistent. If a transitive dependency requests a different member version, conflict resolution and the platform constraint together drive a single chosen version. ## platform vs. enforcedPlatform - `platform(...)` — constraints act as *preferences/recommendations*; a higher transitive request can still win. - `enforcedPlatform(...)` — constraints become *forced* (strict), overriding transitive requests. Powerful but blunt; can cause downgrades and surprising failures, so prefer plain `platform` unless you truly need to pin. ## allowDependencies By default a `java-platform` rejects regular `dependencies` (only `constraints` allowed) to keep it dependency-free. To import another platform/BOM inside yours, opt in: ```kotlin javaPlatform { allowDependencies() } dependencies { api(platform("org.springframework.boot:spring-boot-dependencies:3.3.0")) } ``` ## Why publish vs. a virtual platform A virtual platform (metadata-rule `belongsTo(..., true)`) is *local* to whatever build defines the rule. A published `java-platform` is **shareable** — one versioned artifact many repos import — making it the right tool for org-wide governance of a family's version.

  • When would you choose enforcedPlatform over platform?
    When you must hard-override transitive versions (e.g. force a security-patched version family-wide). It's strict and can downgrade deps, so use sparingly and watch for breakage.
  • Why does java-platform forbid normal dependencies by default?
    A platform should carry only constraints, not pull code. allowDependencies() relaxes this so you can import another BOM into yours.
  • How does a published java-platform differ from a virtual platform?
    The java-platform is a real, shareable, versioned artifact published to a repo; a virtual platform is synthesized locally by a metadata rule and not published.

saying these in an interview costs you the question

  • Reaching for enforcedPlatform by default — its forced versions cause silent downgrades and hard-to-debug resolution.
  • Putting real implementation dependencies in a java-platform without allowDependencies().

context