openrewrite / openrewrite/rewrite

Support classifiers on BOMs imported into `<dependencyManagement>` (Maven 4)

Open
#8,345 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

maven parser
Dominant language
Java
Stars
3.7k
Forks
570
Avg merge
13h 12m
Merged PRs (30d)
261

Description

Problem

Maven 4 permits a <classifier> on a BOM imported into <dependencyManagement>, and the Maven team actively recommends that project BOMs be published as classified artifacts (via the bom-builder3 plugin's <bomClassifier>) so that a BOM is a separate artifact from the project's own POM:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>example</artifactId>
            <version>1.0.0</version>
            <classifier>bom</classifier>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

rewrite-maven silently ignores the classifier. The import resolves example-1.0.0.pom instead of example-1.0.0-bom.pom, so the wrong managed versions are contributed — or, when the project publishes no main POM worth importing, none are, and every dependency that relied on the BOM fails to resolve with an error that never mentions the BOM.

Current behavior

<classifier> on an imported BOM is dropped at parse time and never reaches the downloader.

Root cause

The classifier has nowhere to live and no way to be requested:

  • ManagedDependency.Imported holds only a GroupArtifactVersion — there is no classifier field, unlike ManagedDependency.Defined.
  • RawPom.mapDependencyManagement (~line 560) and UpdateMavenModel (~line 111) both construct new ManagedDependency.Imported(gav), discarding d.getClassifier().
  • ResolvedPom.mergeDependencyManagement (~line 936) calls downloader.download(groupArtifactVersion, null, ...).
  • MavenPomDownloader builds the POM URI as <artifactId>-<version>.pom (~line 594, and <artifactId>-<version>.pom again for maven-local at ~line 1298). There is no classifier slot in either path.

Maven's own validation confirms this is version-gated behavior rather than something that was always allowed — DefaultModelValidator.validate20RawDependencies reports "must be empty, imported POM cannot have a classifier." only below model 4.1.0:

} else if (!is41OrBeyond
        && dependency.getClassifier() != null
        && !dependency.getClassifier().isEmpty()) {
    addViolation(problems, errOn30, Version.V20, prefix + prefix2 + "classifier", ...
        "must be empty, imported POM cannot have a classifier.", dependency);
}

Desired behavior

A classifier on an imported BOM is preserved through parsing and used when downloading the BOM POM, so <classifier>bom</classifier> resolves example-1.0.0-bom.pom. Unclassified imports must keep working unchanged.

This touches the LST model (ManagedDependency.Imported), so it needs care around serialization compatibility.

Secondary: diagnose non-importing <dependencyManagement> entries

When a <dependencyManagement> entry looks like a BOM import but is not one, the failure surfaces as a MavenDownloadingException pointing at an unrelated downstream artifact:

No version provided for direct dependency org.junit.jupiter:junit-jupiter-api

Maven instead reports the cause directly, at the offending element (DefaultModelValidator, ~line 1176):

[WARNING] 'dependencyManagement.dependencies.dependency.type' for groupId='com.example',
  artifactId='example', type='bom' must be 'pom' to import the managed dependencies. @ line 5, column 98

Mirroring that — a warning when a managed dependency carries <scope>import</scope> with a non-pom type, or a bom type that will not be imported — would make this class of failure diagnosable from a build log.

Not a bug: <type>bom</type> is not an import

This issue originally asked for <type>bom</type> in <dependencyManagement> to be treated as an import. That is not Maven 4 behavior, and rewrite-maven's current handling is correct.

DefaultModelBuilder.importDependencyManagement, identical on master, maven-4.0.x, and tag maven-4.0.0-rc-5:

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

The || "bom".equals(...) clause is dead code — when the type is bom the first clause has already forced the continue. The condition is exactly Maven 3's. It arrived as a drive-by in c6380108b1 ([MNG-7877], a consumer-POM commit) with no test and no IT, and there is not a single <type>bom</type> anywhere in apache/maven's sources, ITs, or test resources; every BOM IT uses <type>pom</type><scope>import</scope>. Pairing <type>bom</type> with <scope>import</scope> produces the "must be 'pom' to import the managed dependencies" warning quoted above.

Verified by running Maven 4.0.0-rc-5: a pom declaring a BOM with <type>bom</type> fails with 'dependencies.dependency.version' for ... is missing, whether the model version is 4.0.0 or 4.1.0. Implementing the original request would make rewrite resolve POMs that Maven itself cannot build.

bom in Maven 4 is two other things, neither of which is a consumer-side import mechanism:

  • <packaging>bom</packaging> on the producing project — a build-POM-only packaging whose lifecycle binds install/deploy only, and whose published consumer POM is rewritten to <packaging>pom</packaging> (apache/maven#11427) so Maven 3 can still import it. It produces no artifact other than POMs.
  • A registered artifact type whose extension is .pom (DefaultTypeProvider: new DefaultType(Type.BOM, Language.NONE, "pom", null, false)). In a plain <dependencies> block it resolves the .pom and contributes nothing to the classpath and no managed versions.

Related

  • #6869 — Maven 4 versionless parent references
  • Maven 4 BOM packaging (describes the packaging, not a <type>bom</type> import)
  • MNG-7879 — add a new BOM packaging

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ManagedDependency.Imported, then trace classifier handling through RawPom.mapDependencyManagement, UpdateMavenModel, ResolvedPom.mergeDependencyManagement, and both MavenPomDownloader URI paths identified in the issue. Check serialization compatibility while preserving unclassified imports. Done means classified BOM imports request the classified POM, unclassified imports remain unchanged, and the non-importing dependency-management case is diagnosable.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.