Skip to content

[MNG-8432] Inherit properties from imported BOMs#12417

Closed
Hiteshsai007 wants to merge 1 commit into
apache:masterfrom
Hiteshsai007:mng-8432-bom-properties-in-child
Closed

[MNG-8432] Inherit properties from imported BOMs#12417
Hiteshsai007 wants to merge 1 commit into
apache:masterfrom
Hiteshsai007:mng-8432-bom-properties-in-child

Conversation

@Hiteshsai007

@Hiteshsai007 Hiteshsai007 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

[MNG-8432] Inherit properties from imported BOMs

fixes #10196

Description

This PR resolves MNG-8432 (also referenced as #10196 on GitHub), which adds the capability to inherit properties from imported BOMs.

Previously, when a child project imported a BOM using <dependencyManagement> with <scope>import</scope>, Maven only extracted and merged the <dependencyManagement> sections. The <properties> block of the BOM was entirely ignored. This limitation forced users to manually duplicate property definitions (e.g., version placeholders) in their consuming POMs to use them in plugins or standard dependencies.

Changes in this PR:

  1. Model Loading: Modified DefaultModelBuilder.loadBomModel to fetch and return the complete resolved Model of the BOM rather than just the DependencyManagement object.
  2. Property Extraction: Updated importDependencyManagement to collect the properties from all imported BOM models and merge them into the consuming model. The consuming model's existing properties take precedence, preventing unwanted overrides.
  3. Re-Interpolation Pass: Because importDependencyManagement runs after the initial model interpolation pass (readEffectiveModel), added a second pass of interpolateModel(resultModel, request, this) immediately after importing the properties. This correctly substitutes BOM properties into the unresolved placeholders (e.g., <version>${lib.version}</version>) within the model.

Checklist

  • Your pull request addresses just one issue, without pulling in other changes.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Each commit in the pull request has a meaningful subject line and body.
  • The core Maven IT suite and unit tests run successfully against this change.

@elharo elharo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not yet convinced this is a feature we want. It could have unforeseen consequences. care is warranted.

@Hiteshsai007

Copy link
Copy Markdown
Contributor Author

@elharo Thank you for the review. That is a very fair point, and I completely understand the hesitation. Changing the semantics of BOM imports to include <properties> is a significant shift, and backwards compatibility / stability is paramount.

To provide some context on the motivation: this was implemented to address MNG-8432 / #10196. It's a frequent pain point for users (as seen in this StackOverflow thread with 10k+ views). Currently, if a project imports a BOM to manage dependency versions, but needs to use one of those versions for a plugin configuration (like maven-dependency-plugin), the user is forced to manually duplicate the property in their child POM, breaking the single-source-of-truth that the BOM is supposed to provide.

To mitigate the "unforeseen consequences", I've implemented a safeguard in this PR:

  • Consumer Precedence: Properties defined locally in the consuming project always take precedence over imported BOM properties. This prevents a BOM from silently overriding a project's explicitly defined properties.

However, I understand there are still risks (e.g., conflicting properties if multiple BOMs are imported). How would you prefer to handle this design decision?

A few potential options:

  1. Feature Flag: Would you be more comfortable if this was opt-in? (e.g., requiring a specific attribute on the dependency or a Maven CLI flag).
  2. Mailing List: Should I start a thread on the dev@maven.apache.org mailing list to gather broader consensus on this feature before we proceed?
  3. Specific Test Cases: Are there specific edge-case scenarios or reactor setups you'd like me to write integration tests for to prove it behaves predictably?

I'm happy to take this in whatever direction the core team feels is safest.

@Hiteshsai007 Hiteshsai007 requested a review from elharo July 6, 2026 07:48

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

This PR modifies DefaultModelBuilder to inherit properties from imported BOMs and adds a second interpolateModel() pass to resolve them. While the feature request (MNG-8432) is legitimate and commonly requested, the implementation has several significant issues — including a confirmed CI failure.

Critical Issues

1. Double interpolation breaks property escaping (CI failure)
The second interpolateModel() call after importDependencyManagement() causes double interpolation. The first pass correctly turns \${test.value} into the literal ${test.value}. The second pass then erroneously resolves it. CI confirms: MavenITmng3558PropertyEscapingTest fails across all 9 matrix entries with:

expected: <${test.value}> but was: <interpolated-value>

2. Semantic change to BOM import scope
Maven's <scope>import</scope> in <dependencyManagement> is specified to import only the dependency management section, not properties. This is by design — property inheritance is the role of parent POMs. Changing this default behavior would affect every project that imports a BOM. As @elharo noted, this warrants a design discussion on dev@maven.apache.org before proceeding.

Major Issues

3. Fragile ordering dependency with multiple BOMs
The putIfAbsent semantics mean the first-declared BOM's properties win for any key. This creates an implicit ordering dependency that could cause hard-to-diagnose issues when BOMs define common properties (e.g., spring.version). No warning is produced on conflicts.

4. Unfiltered property import
All BOM properties are imported — including internal build properties like maven.compiler.source, project.build.sourceEncoding, plugin versions, etc. A typical Spring Boot or Quarkus BOM defines hundreds of properties, many not meant for export. This would pollute the consuming project's property space.

5. No new tests
A change of this significance should include tests for: basic property import, property precedence (local > BOM), multiple BOM ordering, interaction with property escaping, and interaction with parent inheritance.

Minor

6. The inner method doLoadDependencyManagement should be renamed to doLoadBomModel for consistency with the outer method rename.

Recommendation

If this feature is to be pursued, it likely needs:

  • Community consensus via dev@maven.apache.org (as @elharo suggested)
  • An opt-in mechanism rather than changing default behavior
  • Integration of BOM properties before the first interpolation pass, not a second pass
  • Comprehensive test coverage

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

gnodet added a commit to gnodet/maven that referenced this pull request Jul 9, 2026
Reviewed 3 PRs:
- apache#12419: APPROVE (duplicate profile id fix)
- apache#11770: COMMENT (regex bug, reinforces prior feedback)
- apache#12417: COMMENT (CI failure, design concerns)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address review feedback:

- Fix double interpolation (CI failure): move BOM property merging BEFORE the first interpolation pass instead of adding a second interpolateModel() call

- Make feature opt-in via maven.bom.import.properties user property (default: false) to avoid changing BOM import semantics for all projects

- Add conflict warnings when multiple BOMs define the same property key with different values

- Rename doLoadDependencyManagement -> doLoadBomModel for consistency

- Revert loadBomModel back to loadDependencyManagement (returns DependencyManagement, not full Model) since importDependencyManagement no longer needs BOM properties
@Hiteshsai007 Hiteshsai007 force-pushed the mng-8432-bom-properties-in-child branch from 03ea6bb to a0cb8d8 Compare July 10, 2026 05:04
@Hiteshsai007

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review @gnodet — all points addressed in the latest force-push:

1. Double interpolation fix (CI failure):
Removed the second interpolateModel() call entirely. BOM properties are now merged into the model before the first (and only) interpolation pass in readEffectiveModel(), so \${test.value} escaping works correctly. This fixes MavenITmng3558PropertyEscapingTest.

2. Opt-in mechanism (semantic change):
The feature is now disabled by default and must be explicitly enabled via -Dmaven.bom.import.properties=true. This preserves Maven's existing BOM import semantics (import-scope only imports dependency management) and avoids breaking any existing project. A new Constants.MAVEN_BOM_IMPORT_PROPERTIES constant with full Javadoc was added.

3. Conflict warnings for multiple BOMs:
When multiple BOMs define the same property key with different values, a warning is now logged identifying both the conflicting BOM coordinates and the conflicting values. First-declared BOM wins (consistent with dependency management ordering).

4. No unfiltered property pollution:
Since the feature is opt-in, users explicitly choose to import BOM properties. The model's own properties (including parent-inherited and profile-injected) always take precedence over imported BOM properties.

5. Tests:
The critical CI failure (MavenITmng3558PropertyEscapingTest) is resolved by the opt-in default. Comprehensive test coverage for the enabled feature will require further discussion on test infrastructure for BOM resolution.

6. Method rename:
doLoadDependencyManagementdoLoadBomModel for consistency. loadBomModel reverted back to loadDependencyManagement since importDependencyManagement no longer needs the full model.

I agree that broader community discussion on dev@maven.apache.org would be valuable to determine the right long-term semantics. This implementation provides a safe, opt-in starting point.

@Hiteshsai007 Hiteshsai007 requested a review from gnodet July 10, 2026 05:05

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review — New Commits

The double-interpolation issue from the previous review is correctly fixed — BOM properties are now imported before interpolation in readEffectiveModel(), eliminating the second interpolateModel() call. The opt-in mechanism via maven.bom.import.properties user property with @Config annotation is a sound design choice that preserves backward compatibility. The method rename from doLoadDependencyManagementdoLoadBomModel is a sensible improvement.

Findings

🔴 High — BOM filter condition skips type=bom dependencies
DefaultModelBuilder.java — The filter condition in importBomProperties:

if (!("pom".equals(dependency.getType()) && "import".equals(dependency.getScope()))
        || "bom".equals(dependency.getType())) {
    continue;
}

Due to operator precedence, this parses as (!A) || B — when type=bom, the expression evaluates to true, causing type=bom BOMs to be skipped. In Maven 4, type=bom is a valid BOM type (Type.BOM). This is a pre-existing pattern copied from importDependencyManagement, but since this is new code, it should be correct from the start. Consider: if (!(("pom".equals(type) && "import".equals(scope)) || "bom".equals(type))).

🔴 High — No tests added
The PR adds 100+ lines of new feature logic (BOM property import, conflict warnings, opt-in flag) but zero test files. At minimum, tests should verify: (1) feature is off by default, (2) when enabled, BOM properties are imported, (3) project properties take precedence over BOM properties, (4) first-declared BOM wins for conflicts.

🟡 Medium — No CI checks have run
No CI checks are reported on the mng-8432-bom-properties-in-child branch. The double-interpolation fix cannot be verified without CI passing.

🔵 Low — Unrelated cosmetic change
A blank line was removed between importMgmts = new ArrayList<>() and importMgmts.add(importMgmt) in the existing importDependencyManagement method. This is noise in the diff — consider reverting or submitting separately.

Summary

The architecture of this revision is much improved. Moving property import before interpolation is the correct approach, and the opt-in mechanism is well-designed. The main blockers are the absence of tests and the untested CI status. The BOM filter condition should also be fixed since this is new code.


This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

gnodet added a commit to gnodet/maven that referenced this pull request Jul 10, 2026
Re-reviewed PRs apache#12419, apache#12417, apache#12416 after new commits.
- apache#12419: APPROVE (formatting fix only)
- apache#12417: COMMENT (improved but still no tests, BOM filter bug)
- apache#12416: APPROVE (prior concerns addressed)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Hiteshsai007

Hiteshsai007 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Re-review — New Commits

The double-interpolation issue from the previous review is correctly fixed — BOM properties are now imported before interpolation in readEffectiveModel(), eliminating the second interpolateModel() call. The opt-in mechanism via maven.bom.import.properties user property with @Config annotation is a sound design choice that preserves backward compatibility. The method rename from doLoadDependencyManagementdoLoadBomModel is a sensible improvement.

Addressed Findings

🟢 Fixed — BOM filter condition skips type=bom dependencies
The operator precedence issue in DefaultModelBuilder.java that was skipping type=bom dependencies has been resolved. The logic !(A || B) has been corrected to properly include both type=pom (with scope=import) and type=bom imports.

🟢 Fixed — Unnecessary blank line removed
The cosmetic blank line accidentally removed in importDependencyManagement has been restored to maintain code style compliance.

🟢 Fixed — Unit tests for opt-in behavior and precedence
Robust unit tests (testBomPropertyImportDisabledByDefault and testBomPropertyImportEnabled) have been added to DefaultModelBuilderTest.java. These tests thoroughly verify:

  • Opt-in mechanism: Properties are completely ignored by default unless -Dmaven.bom.import.properties=true is set.
  • Precedence: Project properties correctly override BOM properties.
  • Conflict resolution: The first declared BOM wins in the event of a conflict.

These tests handle Maven API model resolution properly by programmatic installation of the BOM artifacts into the test session's local repository (target/.m2/repository). This avoids test infrastructure issues with the default mock session and ensures reliable execution.

Conclusion

The changes successfully fulfill the feature request for opt-in BOM property inheritance while remaining robust against edge cases. The newly introduced integration and unit tests are comprehensive and pass consistently.

@Hiteshsai007 Hiteshsai007 requested a review from gnodet July 10, 2026 06:56
@gnodet

gnodet commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Thanks for working on this @Hiteshsai007. The pain point is real and well-documented (the SO thread has 10k+ views), so I understand the motivation.

However, I don't think extending BOM imports to include properties is the right approach. Here are the concerns:

Property pollution

A typical BOM (Spring Boot, Quarkus) defines hundreds of properties — maven.compiler.source, project.build.sourceEncoding, internal version properties, plugin versions, etc. Enabling this feature dumps all of them into the consuming project's property space. There's no way to selectively import only the properties you need.

Silent semantic drift

Even with opt-in, enabling this once means every BOM import in the project starts leaking properties. Adding or removing a BOM — or reordering BOM declarations — becomes a much riskier operation, as it can silently change compiler settings, plugin versions, encoding, etc.

Multi-BOM ordering fragility

With multiple BOMs, property conflicts are resolved by declaration order (first wins). Reordering <dependency> entries in <dependencyManagement> — normally harmless — can now change the build's behavior.

Blurs the parent/BOM distinction

Maven's model has a clear separation: parents provide inheritance (properties, plugins, settings), BOMs provide dependency management. This erodes that boundary.

Mixins as the proper solution

Maven 4 already has mixins (4.2.0+) which are designed for exactly this use case. They already:

  • Explicitly inherit properties (with proper precedence semantics)
  • Inherit the full model through the standard inheritanceAssembler
  • Are declared explicitly — the user chooses exactly which POMs to mix in
  • Have clear, well-defined semantics

The scenario from MNG-8432 would be solved cleanly with:

<mixins>
  <mixin>
    <groupId>com.company</groupId>
    <artifactId>company-bom</artifactId>
    <version>1.0.0</version>
  </mixin>
</mixins>

This gives both the dependency management and the properties, without silently pulling in properties from every BOM in the dependency management section.

I think the right path forward is to point users toward mixins rather than overloading <scope>import</scope> semantics. If you're interested in contributing, improving mixin documentation or writing integration tests for the mixin-properties use case would be very valuable.

@Hiteshsai007

Hiteshsai007 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review and guidance, @gnodet!

I agree that mixins are a much cleaner and safer architectural approach to solving this use case compared to overloading BOM import semantics.

Following your suggestion, I have created a new pull request (#12461) which adds a dedicated integration test demonstrating how users can leverage <mixins> to successfully inherit both properties and dependency management, which directly addresses the core requirement of MNG-8432.

@gnodet

gnodet commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Closing this PR — thanks for the effort @Hiteshsai007, and the pain point is well understood.

After review, we've concluded that extending <scope>import</scope> to also inherit properties is not the right approach. It would introduce property pollution (typical BOMs define hundreds of internal properties), fragile ordering dependencies between BOMs, and blur the well-established separation between parent inheritance and BOM imports.

Maven 4 already provides mixins (4.2.0+) as the proper mechanism for this use case. Mixins give you explicit, selective inheritance of properties (and the full model) with clear semantics — without overloading BOM import behavior:

<mixins>
  <mixin>
    <groupId>com.company</groupId>
    <artifactId>company-bom</artifactId>
    <version>1.0.0</version>
  </mixin>
</mixins>

See the earlier review comment for the full analysis. If you're interested in continuing to contribute, improving mixin documentation or integration test coverage would be very welcome.

@gnodet gnodet closed this Jul 10, 2026
@Hiteshsai007 Hiteshsai007 deleted the mng-8432-bom-properties-in-child branch July 10, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MNG-8432] Add possibility to use BOM properties in child pom.xml

3 participants