You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by el...@apache.org on 2026/08/05 19:31:41 UTC

(maven-resolver) branch master updated: docs: rewrite common-misconceptions.md to ASD-STE100 rules (#2035)

This is an automated email from the ASF dual-hosted git repository.

elharo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


The following commit(s) were added to refs/heads/master by this push:
     new 0a5bd0481 docs: rewrite common-misconceptions.md to ASD-STE100 rules (#2035)
0a5bd0481 is described below

commit 0a5bd048144e37aeb48bb85fab657de948346caa
Author: Elliotte Rusty Harold <el...@users.noreply.github.com>
AuthorDate: Wed Aug 5 19:31:36 2026 +0000

    docs: rewrite common-misconceptions.md to ASD-STE100 rules (#2035)
    
    * docs: rewrite common-misconceptions.md to STE rules
    
    * Update common-misconceptions.md
    
    * Update common-misconceptions.md
    
    * Update common-misconceptions.md
    
    * Update common-misconceptions.md
    
    * Update common-misconceptions.md
    
    * Update common-misconceptions.md
    
    * Update common-misconceptions.md
    
    * Update common-misconceptions.md
    
    * model --> src/main
    
    * trailing whitespace
---
 src/site/markdown/common-misconceptions.md | 132 +++++++++--------------------
 1 file changed, 39 insertions(+), 93 deletions(-)

diff --git a/src/site/markdown/common-misconceptions.md b/src/site/markdown/common-misconceptions.md
index 8a1a58129..b6f52aac9 100644
--- a/src/site/markdown/common-misconceptions.md
+++ b/src/site/markdown/common-misconceptions.md
@@ -18,75 +18,38 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-Due to smooth transitions from Maven2 into Maven3 (and soon
-Maven4), and the fact that Maven2 plugins kept working with Maven3, maybe
-even without change, some misconceptions crept in 
-as well. Despite the marvel of "compatibility", Maven3 resolution
-differs considerably from Maven2, and the sole reason is actual improvement
-in area of resolution. It became much more precise (and, due
-to that, lost some "bad" habits present in Maven2). Here, we will try to
-enumerate some of the most common misconceptions.
+Maven 2 plugins kept working with Maven 3 although Maven 3 resolution differs from Maven 2 resolution. Resolution is now much more precise. Some old behaviors from Maven 2 no longer exist. This page lists some of the most common misconceptions.
 
-## Misconception No1: How Resolver Works
+## Misconception Number 1: How Resolver Works
 
 (Simplified)
 
-The most typical use case for Resolver is to "resolve transitively" 
-dependencies. Resolver, to achieve this, internally (but these are
-exposed via API as distinguished API calls as well) performs 3 steps:
-"collect", "transform" and "resolve".
-
-The "collect" step is first, where it builds the "dirty tree" (or dirty graph)
-of artifacts. It is important to remark, that in "collect" step, while 
-the graph is being built, Maven uses only POMs. Hence, if collecting an 
-Artifact that was never downloaded to your local repository, it will 
-download **the POMs only**. Using POMs resolver is able to build current 
-"node" of graph, but also figure outgoing vertices and adjacent nodes of 
-current node and so on. Which dependency is chosen to continue with from
-the current node POM is decided by various criteria (configured).
-
-The "transform" step transforms the "dirty graph": this is where conflict resolution
-happens. It is here when resolver applies various rules to resolve conflicting 
-versions, conflicting scopes, and so on. Here, if "verbose tree" is asked for,
-conflict resolution does not remove graph nodes, merely marks the conflicts
-and the conflict "winner". Thus, "verbose tree" cannot be resolved.
-
-Finally, the "resolve" step runs, when the (transformed) graph node artifacts
-are being resolved, basically ensuring (and downloading if needed) their 
-correspondent files (i.e. JAR files) are present in local repository.
-
-It is important to state, that in "collect" step happens the selection of nodes
-by various criteria, among other by the configured scope filters. And here we
-come to the notion of "runtime graph" vs "test graph". 
-
-In resolver, maybe un-intuitively, the "scope filter" is usually used (but does 
-not have to, this is just how it IS used in Maven Core, probably for historical
-reasons) as "what should be omitted". The default session filter in Maven 
-is set up as this:
+The most common use of Resolver is to resolve dependencies transitively. Resolver performs three steps: "collect", "transform", and "resolve". Resolver also exposes these steps as separate API calls.
+
+The "collect" step is first. During this step, Resolver builds the "dirty tree" (or dirty graph) of artifacts. While it builds the graph, Maven only uses POMs. If an artifact is not in your local repository, Maven downloads the POM only. With the POM, Resolver builds the current node of the graph and finds its outgoing vertices and adjacent nodes. The configured criteria decide which dependency continues from the current node POM.
+
+The "transform" step transforms the "dirty graph". This is where conflict resolution happens. Resolver applies rules to resolve conflicting versions and conflicting scopes. If you ask for the "verbose tree", conflict resolution does not remove graph nodes. It only marks the conflicts and the conflict "winner". Therefore, the "verbose tree" cannot be resolved.
+
+Finally, in the "resolve" step, Resolver resolves the artifacts of the transformed graph nodes. It ensures that the corresponding files (for example, JAR files) are present in the local repository. It downloads them if needed.
+
+During the "collect" step, various criteria select the nodes. The configured scope filters are among these criteria. This leads to the notion of the "runtime graph" and the "test graph".
+
+The "scope filter" selects what to omit. This use of the filter is not intuitive. Maven Core uses the filter this way. The default session filter in Maven is set up as follows:
 
 ```
   new ScopeDependencySelector("test", "provided")
 ```
 
-This means, that "current dependency node" dependencies in "test" and "provided" scope
-will be simply omitted from the graph. In other words, this filter builds
-the "downstream runtime classpath" of supplied artifact (i.e. "what is needed by the 
-artifact at runtime when I depend on it").
-
-Note: these are NOT "Maven related" notions yet, there is nowhere Maven in picture here,
-and these are not the classpath used by Compiler or Surefire plugins, merely just
-a showcase how Resolver works.
+This filter omits the dependencies of the "current dependency node" that are in the "test" and "provided" scope. In other words, this filter builds the "downstream runtime classpath" of the supplied artifact. It shows what the artifact needs at runtime when you depend on it.
 
+Note: These notions do not relate to Maven yet. Maven does not appear in this example. This is not the classpath that the Compiler or Surefire plugins use. It is only a showcase of how Resolver works.
 
-## Misconception No2: "Test graph" Is Superset Of "Runtime graph"
+## Misconception Number 2: "Test graph" is a Superset of the "Runtime graph"
 
-**Wrong**. As can be seen from above, for runtime graph we leave out "test" scoped
-dependencies. It was true in Maven2, where test graph really was a superset of runtime, 
-but this does not stand anymore in Maven3. And this has interesting consequences. Let me show an example:
+**Wrong**. For the runtime graph, Resolver omits the "test" scoped dependencies. This has interesting consequences. The example below shows this.
 
-(Note: very same scenario, as explained below for Guice+Guava would work for Jackson Databind+Core, etc.)
-
-Assume your project is using Google Guice, so you have declared it as a dependency:
+The example below uses Guice and Guava.
+Your project uses Google Guice. You have declared Guice as a dependency:
 
 ```
       <dependency>
@@ -96,12 +59,9 @@ Assume your project is using Google Guice, so you have declared it as a dependen
       </dependency>
 ```
 
-All fine and dandy. At the same time, you want to avoid any use of Guava. We all know Guava is a direct dependency 
-of Guice. This is fine, since as we know, the best practice is to declare all dependencies your code compiles 
-against. By not having Guava here, analysis tools will report if code touches Guava as an "undeclared dependency".
+The src/main code does not directly use Guava. However, Guava is a direct dependency of Guice.
+Your unit tests do need Guava so you add Guava as a test-scoped dependency. The POM now looks like this:
 
-But let's go one step further: to set up your unit tests, you **do need** Guava. So what now? Nothing, just 
-add it as a test dependency, so your POM looks like this:
 
 ```
       <dependency>
@@ -136,19 +96,16 @@ The `dependency:tree` plugin for this project outputs this verbose tree:
 [INFO]    \- com.google.j2objc:j2objc-annotations:jar:1.3:test
 ```
 
-This IS the "test graph" **of the project** and contains a conflict as noted by "omitted for duplicate"
-and "scope not updated to compile" remarks next to Guava nodes.
+This is the "test graph" of the project. It contains a conflict indicated by the remarks "omitted for duplicate" and "scope not updated to compile" next to the Guava nodes.
 
-So this setup results that:
+This setup has these results:
 
-* when you compile, Guava is NOT on compile classpath, so you cannot even touch it (by mistake)
-* when test-compile and test-execute run, Guava will be present on classpath, as expected
+* When you compile, Guava is not on the compile classpath. You cannot touch it by mistake.
+* When test-compile and test-execute run, Guava is present on the classpath, as expected.
 
-So far so good, but what happens when this library is consumed downstream by someone? When it becomes used as a library?
-Nothing, all works as expected!
+What happens when someone consumes this library downstream? Nothing. Everything works as expected.
 
-When a downstream dependency declares a dependency on this project, the downstream project will get this graph (from
-the node that is your library):
+When a downstream project declares a dependency on your project, it gets this graph from the node of your library:
 
 ```
 [INFO] --- dependency:3.6.1:tree (default-cli) @ DOWNSTREAM-PROJECT ---
@@ -167,29 +124,18 @@ the node that is your library):
 [INFO]          \- com.google.j2objc:j2objc-annotations:jar:1.3:compile
 ```
 
-So what happens here? First, revisit "How Resolver Works". There you will see that for "runtime graph" of the
-dependency the "test" and "provided" scopes of the dependency artifact **are not even considered**. They are simply
-omitted. Not skipped, but completely omitted, like they do not even exist. Hence, in the graph there is 
-**no conflict happening** (as "test" Guava is completely omitted during "collect" step). Hence, everything 
-goes as expected.
+What happens here? The section "How Resolver Works" above explains this. For the "runtime graph" of the dependency, Resolver does not consider the "test" and "provided" scopes of the dependency artifact. Resolver omits them completely. It does not skip them. They do not exist in the graph.
+
+Therefore, no conflict happens. Resolver omits the "test" Guava during the "collect" step. Everything goes as expected.
 
 ### Important Consequences
 
-One, maybe not so obvious consequence can be explained with use of `maven-assembly-plugin`. Assume you want to
-assemble your module "runtime" dependencies.
-
-If you do it from "within" the project, for example in the package phase, your packaging will be incomplete. 
-Guava will be missing! But if you do it from "outside" of the project (i.e. subsequent module of the build, or 
-downstream dependency), the assembly will contain Guava as well.
-
-This is a [Maven Assembly plugin bug](https://issues.apache.org/jira/browse/MASSEMBLY-1008), somewhat explained 
-in [MRESOLVER-391](https://issues.apache.org/jira/browse/MRESOLVER-391). In short, the Maven Assembly plugin considers 
-"project test graph", and then "cherry-picks runtime scoped nodes" from it, which, as we can see in this case, 
-is wrong. You need to build different graphs for "runtime" and "test" classpath.
-For Assembly plugin, the problem is that as Mojo, it requests "test graph", then it reads configuration
-(assembly descriptor, and this is the point where it learns about required scopes), and then it "filters"
-the resolved "test graph" for runtime scopes. And it is wrong, as Guava is in test scope. Instead, the plugin
-should read the configuration first, and ask Resolver for "runtime graph" and filter that. In turn, this problem
-does not stand with `maven-war-plugin`, as the "war" Mojo asks resolution of "compile+runtime" scope. Of course, 
-the WAR use case is much simpler than the Assembly use case is, as the former always packages the same scope, while Assembly receives 
-a complex configuration and exposes much more complex "modus operandi".
+One consequence is not so obvious. It involves the `maven-assembly-plugin`. You want to assemble the "runtime" dependencies of the module.
+
+If you assemble from within the project, for example in the package phase, the packaging will be incomplete. Guava will be missing. If you assemble from outside the project, the assembly will contain Guava. This includes assembly from a subsequent module of the build or from a downstream dependency.
+
+This is a [Maven Assembly plugin bug](https://issues.apache.org/jira/browse/MASSEMBLY-1008). [MRESOLVER-391](https://issues.apache.org/jira/browse/MRESOLVER-391) explains it in part. The Maven Assembly plugin considers the "test graph" of the project. Then it "cherry-picks" the runtime scoped nodes from the graph. This is wrong in this case.
+
+You must build different graphs for the "runtime" and "test" classpath. The Assembly plugin is a Mojo. It requests the "test graph". Then it reads the configuration (the assembly descriptor). It learns the required scopes at this point. Then it "filters" the resolved "test graph" for the runtime scopes.
+
+This is wrong, because Guava is in the test scope. The plugin must read the configuration first. Then it must ask Resolver for the "runtime graph". Then it must filter the graph. This problem does not exist with `maven-war-plugin`. The "war" Mojo asks for the "compile+runtime" scope. The WAR case is much simpler than the Assembly use case. The WAR plugin always packages the same scope.