I faced with some Maven behavior that I was not expected before. For example we have multi-module project A:
A
|
--- api
--- impl
impl module uses api as a dependency:
<dependency>
<groupId>examle</groupId>
<artifactId>api</artifactId>
</dependency>
when I run mvn clean test
for whole app maven finishes successfully.
when I execute same command for impl module them maven fails with exception like:
[ERROR] Failed to execute goal on project impl: Could not resolve
dependencies for project A:impl:jar:1.0-SNAPSHOT: Could not find artifact
A:api:jar:1.0-SNAPSHOT in maven-public
So my question is how maven resolves dependencies that was not build into jar file and pushed into local/remote repositories. In all tutorials it is said that maven looks for dependencies in local repository and if it can not find it then it search in remote repo and it has little bit different behavior for SNAPSHOTS.
But in my case I run test stage and do not build jar file even in target repo
To makes things clear, you noticed this behavior with this command run from the multi-module project :
mvn clean test
but you would have the same behavior, that is : getting the dependencies resolved and usable between modules without previously installing them in the local repository with any phase you run such as :
mvn test
mvn compile
mvn package
In fact the Maven documentation about this point is not explicit.
You can read in the Guide to Working with Multiple Modules :
The Reactor
The mechanism in Maven that handles multi-module projects is referred to as the reactor. This part of the Maven core does the following:
Collects all the available modules to build
Sorts the projects into the correct build order
Builds the selected projects in order
You can guess that if the order of the modules matters for the Maven build, it probably means that the build of a module relies on the build of dependent modules that were previously built. That explains the sort done by the reactor if the order you specified in <modules>
is not correct in terms of dependencies (the correct order is that the used dependency has to be declared before the user dependency).
There are of course some uses cases where you want to install a maven artifact into a local repository such as (not exhaustive) :
By executing your maven build command with the -X
flag (the debug flag) you will see that Maven computes the dependencies between module for each module build.
For example with your example you should see for the impl
build :
DEBUG] === PROJECT BUILD PLAN ================================================ [DEBUG] Project: A:impl:0.0.1-SNAPSHOT [DEBUG] Dependencies (collect): [] [DEBUG] Dependencies (resolve): [compile, test]
And a little later the detection of the inter-module dependency :
[DEBUG] A:impl:jar:0.0.1-SNAPSHOT [DEBUG] A:api:jar:0.0.1-SNAPSHOT:compile
Here is a more detailed extract of :
[DEBUG] ======================================================================= [DEBUG] Dependency collection stats: {ConflictMarker.analyzeTime=23166, ConflictMarker.markTime=13490, ConflictMarker.nodeCount=2, ConflictIdSorter.graphTime=31377, ConflictIdSorter.topsortTime=6158, ConflictIdSorter.conflictIdCount=1, ConflictIdSorter.conflictIdCycleCount=0, ConflictResolver.totalTime=51611, ConflictResolver.conflictItemCount=1, DefaultDependencyCollector.collectTime=368903, DefaultDependencyCollector.transformTime=134014} [DEBUG] A:impl:jar:0.0.1-SNAPSHOT [DEBUG] A:api:jar:0.0.1-SNAPSHOT:compile
Consequently, the plugins executed during the build of the impl
will also have a classpath including the compiled classes of the api
module.
For example the debug traces of the compiler plugin execution show :
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ impl --- ... [DEBUG] (f) classpathElements = [C:\...\test-parent-pom\impl\target\classes, C:\...\test-parent-pom\api\target\classes]