Class ConflictResolver

java.lang.Object
org.eclipse.aether.util.graph.transformer.ConflictResolver
All Implemented Interfaces:
org.eclipse.aether.collection.DependencyGraphTransformer
Direct Known Subclasses:
ClassicConflictResolver, PathConflictResolver

public class ConflictResolver extends Object implements org.eclipse.aether.collection.DependencyGraphTransformer
Abstract base class for dependency graph transformers that resolve version and scope conflicts among dependencies. For a given set of conflicting nodes, one node will be chosen as the winner. How losing nodes are handled depends on the configured verbosity level: they may be removed entirely, have their children removed, or be left in place with conflict information. The exact rules by which a winning node and its effective scope are determined are controlled by user-supplied implementations of ConflictResolver.VersionSelector, ConflictResolver.ScopeSelector, ConflictResolver.OptionalitySelector and ConflictResolver.ScopeDeriver.

Available Implementations:

Implementation Selection Guide:

Usage Example:


 // Recommended: High-performance path-based resolver
 DependencyGraphTransformer transformer = new ChainedDependencyGraphTransformer(
     new PathConflictResolver(
         new NearestVersionSelector(),
         new JavaScopeSelector(),
         new SimpleOptionalitySelector(),
         new JavaScopeDeriver()),
     // other transformers...
 );

 // Legacy: Classic resolver for backward compatibility
 DependencyGraphTransformer legacyTransformer = new ChainedDependencyGraphTransformer(
     new ClassicConflictResolver(
         new NearestVersionSelector(),
         new JavaScopeSelector(),
         new SimpleOptionalitySelector(),
         new JavaScopeDeriver()),
     // other transformers...
 );
 

Verbosity Levels and Conflict Handling:

  • NONE (default): Creates a clean dependency tree without duplicate artifacts. Losing nodes are completely removed from the graph, so are cycles as well.
  • STANDARD: Retains losing nodes for analysis but removes their children to prevent duplicate dependencies. Special handling for version ranges: redundant nodes may still be removed if multiple versions of the same artifact exist. Losing nodes link back to the winner via NODE_DATA_WINNER and preserve original scope/optionality information. This mode removes cycles only, while conflict nodes/duplicates are left in place. Graphs in this verbosity level cannot be resolved, their purpose is for analysis only.
  • FULL: Preserves the complete original graph structure including all conflicts and cycles. All nodes remain with their children, but conflict information is recorded for analysis. Graphs in this verbosity level cannot be resolved, their purpose is for analysis only.
The verbosity level is controlled by the CONFIG_PROP_VERBOSE configuration property.

Conflict Metadata: In STANDARD and FULL modes, the keys NODE_DATA_ORIGINAL_SCOPE and NODE_DATA_ORIGINAL_OPTIONALITY are used to store the original scope and optionality of each node. Obviously, dependency trees with verbosity STANDARD or FULL are not suitable for artifact resolution unless a filter is employed to exclude the duplicate dependencies.

Conflict ID Processing Pipeline:

  1. ConflictMarker: Assigns conflict IDs based on GACE (groupId:artifactId:classifier:extension) coordinates, grouping artifacts that differ only in version (partitions the graph, assigning same conflict IDs to nodes belonging to same conflict group).
  2. ConflictIdSorter: Creates topological ordering of conflict IDs and detects cycles
  3. ConflictResolver implementation: Uses the sorted conflict IDs to resolve conflicts in dependency order
This transformer will query the keys TransformationContextKeys.CONFLICT_IDS, TransformationContextKeys.SORTED_CONFLICT_IDS, TransformationContextKeys.CYCLIC_CONFLICT_IDS for existing information about conflict ids. In absence of this information, it will automatically invoke the ConflictIdSorter to calculate it.
See Also: