A Jackson family ends up with mixed versions despite an alignment rule. How do you diagnose why alignment didn't take effect?
answer
- dependencyInsight --dependency --configuration
- look for virtual platform node + selection reason
- group filter missed a module
- version must be id.version
- competing forced/strict constraint
basics
~20 sRun ./gradlew :app:dependencies (or dependencyInsight) for the configuration and look for the virtual platform node and each module's selected version + 'selected by rule/conflict' reasons. Usually the rule's group filter missed a module, or the version coordinate didn't match.
solid answer
~50 sTreat it as a resolution-trace problem. First, run `./gradlew dependencyInsight --dependency jackson-core --configuration runtimeClasspath` for each suspect module — the report shows the *selected version* and *why* (conflict resolution, constraint, or alignment). Look for whether a `virtual platform` node appears and whether the module is listed as belonging to it. Common causes: (1) the `ComponentMetadataRule` group filter doesn't match every module's group (e.g. `jackson-module-kotlin` lives under `com.fasterxml.jackson.module`, not `...core`); (2) the `belongsTo` coordinate uses a hardcoded version instead of `${id.version}`, so different module versions map to different virtual platforms and never align; (3) a strict/forced constraint or `enforcedPlatform` elsewhere pins one member; (4) the rule isn't actually registered for that configuration's resolution. Cross-check by printing the full `dependencies` tree and confirming a single platform node drives all members. Fix the filter or version mapping, then re-run the insight to confirm one consistent version.
code
bash · 6 lines./gradlew :app:dependencyInsight \
--dependency com.fasterxml.jackson.core:jackson-databind \
--configuration runtimeClasspath
# Read 'Selection reasons': expect 'belongs to platform ... jackson-platform'
# If absent, the alignment rule didn't apply to this module.go deeper
Know that ./gradlew dependencies shows the resolved tree to spot mismatched versions.
Use dependencyInsight to read selection reasons and spot a missed group filter.
Systematically distinguish missed membership vs competing forced constraints and fix root cause.
Build guardrails (CI checks, build-scan inspection) so misalignment is caught before merge across the org.
## Tools for the diagnosis Gradle exposes two reporting tasks that answer *what* resolved and *why*: - `./gradlew :app:dependencies --configuration runtimeClasspath` — the full tree; shows each module's selected version and `(*)`/conflict markers. - `./gradlew :app:dependencyInsight --dependency jackson-databind --configuration runtimeClasspath` — focuses one module and prints **selection reasons**: `by conflict resolution`, `by constraint`, `belongs to platform ...`, `forced`, etc. When alignment works you'll see a `virtual platform com.fasterxml.jackson:jackson-virtual-platform:X` node, and each family member reported as part of it, all at version `X`. ## The usual root causes ### 1. Group filter too narrow Jackson spans multiple groups: `com.fasterxml.jackson.core`, `com.fasterxml.jackson.module`, `com.fasterxml.jackson.datatype`. A rule that only matches `...core` leaves the module/datatype artifacts unaligned. Fix by matching the common prefix: ```kotlin if (id.group.startsWith("com.fasterxml.jackson")) belongsTo("com.fasterxml.jackson:jackson-platform:${id.version}", true) ``` ### 2. Hardcoded platform version If you write `belongsTo("g:vp:2.15.0", true)` literally, then `core:2.13` maps to virtual platform `vp:2.15.0` while `databind:2.15` maps to... also `2.15.0` — so they *do* collapse, but if you accidentally template by something else, modules land on *different* platform versions and never converge. Always derive the platform version from `id.version`. ### 3. A competing strict/forced constraint An `enforcedPlatform`, a `strictly` rich-version, or a `resolutionStrategy.force` elsewhere can pin one member, defeating alignment. The insight report flags these as `forced` or `by constraint`. ### 4. Rule not applied to that resolution Metadata rules registered in a subproject don't automatically apply to another project's resolution. Confirm the rule is in scope (e.g. via a convention plugin) for the configuration you're inspecting. ## Workflow 1. Reproduce with `dependencyInsight` on one mismatched module. 2. Read the selection reason — is the platform node present? Is the module a member? 3. If no platform membership: fix the group filter or version mapping. 4. If `forced`/`by constraint`: find and reconcile the competing pin. 5. Re-run insight; confirm all members share one version and the platform node. ## Tip Add `--info` or use the build scan to see metadata-rule application if you suspect the rule never ran.
- Which task tells you *why* a specific version was selected?dependencyInsight with --dependency and --configuration; it prints selection reasons like conflict resolution, by constraint, forced, or platform membership.
- Why can hardcoding the platform version in belongsTo break alignment?Different module versions must map to a *consistent* virtual-platform coordinate derived from id.version; a wrong/static mapping can split members across platforms so they never align.
- How can a competing constraint defeat your alignment rule?An enforcedPlatform, strictly version, or resolutionStrategy.force can pin one member; the insight report flags it as forced/by constraint and it overrides alignment.
saying these in an interview costs you the question
- Guessing at versions instead of reading dependencyInsight selection reasons.
- Assuming the rule applies everywhere when it was only registered in one subproject.
- Ignoring a stray resolutionStrategy.force that overrides alignment.