Summary
The Maven 4 Node API (org.apache.maven.api.Node) does not expose dependency resolution metadata that Aether stores in DependencyNode.getData() and via DependencyManagerUtils. This information is essential for tools that display verbose dependency trees (conflict indicators, version management overrides, scope changes).
Missing accessors on Node
The following four pieces of metadata are currently inaccessible through the public Maven 4 API:
| Information |
Aether source |
Used for |
| Winner node (conflict loser's winning sibling) |
ConflictResolver.NODE_DATA_WINNER |
"omitted for conflict" display |
| Pre-managed version (original version before DM override) |
DependencyManagerUtils.getPremanagedVersion() |
"4.4.3 ⚠ 3.25.1" conflict indicator |
| Pre-managed scope (original scope before DM override) |
DependencyManagerUtils.getPremanagedScope() |
Scope management indicator |
| Original scope (scope before conflict resolution) |
ConflictResolver.NODE_DATA_ORIGINAL_SCOPE |
Scope conflict display |
Current workaround
Tools like pilot must use reflection to call AbstractNode.getDependencyNode() (package-private) to reach the Aether DependencyNode and access this data:
// TODO: remove reflection once this issue is resolved
Method m = node.getClass().getDeclaredMethod("getDependencyNode");
m.setAccessible(true);
DependencyNode aetherNode = (DependencyNode) m.invoke(node);
String premanagedVersion = DependencyManagerUtils.getPremanagedVersion(aetherNode);
DependencyNode winner = (DependencyNode) aetherNode.getData().get(ConflictResolver.NODE_DATA_WINNER);
Note: DefaultNode.asString() already reads all this data internally (it's how mvn dependency:tree -Dverbose works), so the underlying plumbing is solid — it just isn't exposed through the API.
Proposed API additions on Node
Following the noun-style accessor convention for immutable value types established in #13035 / #13036:
/**
* Returns the node that won the dependency conflict resolution for this node,
* or empty if this node was not omitted due to a conflict.
* Only available when the resolver is run in verbose mode.
*/
Optional<Node> winner();
/**
* Returns the version of this dependency as originally declared (before
* dependency management overrode it), or empty if the version was not managed.
* Only available when the resolver is run in verbose mode.
*/
Optional<String> premanagedVersion();
/**
* Returns the scope of this dependency as originally declared (before
* dependency management overrode it), or empty if the scope was not managed.
* Only available when the resolver is run in verbose mode.
*/
Optional<String> premanagedScope();
/**
* Returns the scope of this dependency before conflict resolution,
* or empty if the scope was not changed during conflict resolution.
* Only available when the resolver is run in verbose mode.
*/
Optional<String> originalScope();
Note: Node is already annotated @Immutable, so these follow the same noun-style accessor pattern being applied to Artifact, Dependency, Project, etc. in #13036. No getX() compat bridge is needed since these are new methods with no prior getX() form.
Also needed: API constant for verbose mode
To populate the above metadata, the resolver session must be configured with verbose mode. Currently this requires importing DependencyManagerUtils.CONFIG_PROP_VERBOSE from maven-resolver-util (an Aether internal), which leaks an implementation dependency into client code:
// Requires import of org.eclipse.aether.util.graph.manager.DependencyManagerUtils — an Aether internal
mutableSession.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE);
DefaultDependencyResolver already handles this internally when DependencyResolverRequest.verbose() is set — but that path performs full resolution. Tools that call RepositorySystem.collectDependencies() directly (e.g. to collect without resolving artifacts) have no Maven API way to request verbose mode.
Proposed addition: expose the config property key as a constant on a Maven API type (e.g. DependencyResolverRequest or a new ResolverConfig class in maven-api-core), so tools don't need to depend on maven-resolver-util just to enable verbose mode.
Affected components
maven-api-core: org.apache.maven.api.Node (new accessors)
maven-impl: org.apache.maven.impl.AbstractNode / DefaultNode (implementations)
maven-api-core: new constant for the verbose config property key (optional, separate)
Summary
The Maven 4
NodeAPI (org.apache.maven.api.Node) does not expose dependency resolution metadata that Aether stores inDependencyNode.getData()and viaDependencyManagerUtils. This information is essential for tools that display verbose dependency trees (conflict indicators, version management overrides, scope changes).Missing accessors on
NodeThe following four pieces of metadata are currently inaccessible through the public Maven 4 API:
ConflictResolver.NODE_DATA_WINNERDependencyManagerUtils.getPremanagedVersion()DependencyManagerUtils.getPremanagedScope()ConflictResolver.NODE_DATA_ORIGINAL_SCOPECurrent workaround
Tools like pilot must use reflection to call
AbstractNode.getDependencyNode()(package-private) to reach the AetherDependencyNodeand access this data:Note:
DefaultNode.asString()already reads all this data internally (it's howmvn dependency:tree -Dverboseworks), so the underlying plumbing is solid — it just isn't exposed through the API.Proposed API additions on
NodeFollowing the noun-style accessor convention for immutable value types established in #13035 / #13036:
Note:
Nodeis already annotated@Immutable, so these follow the same noun-style accessor pattern being applied toArtifact,Dependency,Project, etc. in #13036. NogetX()compat bridge is needed since these are new methods with no priorgetX()form.Also needed: API constant for verbose mode
To populate the above metadata, the resolver session must be configured with verbose mode. Currently this requires importing
DependencyManagerUtils.CONFIG_PROP_VERBOSEfrommaven-resolver-util(an Aether internal), which leaks an implementation dependency into client code:DefaultDependencyResolveralready handles this internally whenDependencyResolverRequest.verbose()is set — but that path performs full resolution. Tools that callRepositorySystem.collectDependencies()directly (e.g. to collect without resolving artifacts) have no Maven API way to request verbose mode.Proposed addition: expose the config property key as a constant on a Maven API type (e.g.
DependencyResolverRequestor a newResolverConfigclass inmaven-api-core), so tools don't need to depend onmaven-resolver-utiljust to enable verbose mode.Affected components
maven-api-core:org.apache.maven.api.Node(new accessors)maven-impl:org.apache.maven.impl.AbstractNode/DefaultNode(implementations)maven-api-core: new constant for the verbose config property key (optional, separate)