4

Let's assume that our build is about building modules from A to Z. All the version elements in pom files for these projects are set to -SNAPSHOT.

When we build the pom file, maven starts with project A, then goes to B, and then finally reaches the project Z. If Z depends on A, does maven check the remote repo for a latest A-SNAPSHOT.jar and potentially replace A-SNAPSHOT.jar that just got created as part of the same build at A/target/ and/or local Maven repo?

I think -o can avoid above scenario but I just wanted to understand.

Is it possible to set -o to a specific groupId to avoid obscure errors that might happen in above scenario.

Is it possible to configure the build in such a way to download any artifacts unavailable in the local repo but don't replace existing ones.

phanin
  • 5,327
  • 5
  • 32
  • 50
  • Are we talking about a multi module build? With those modules A-Z ? – khmarbaise Sep 22 '15 at 11:24
  • @khmarbaise yes; updated the question. – phanin Sep 22 '15 at 16:33
  • I don't understand your question. During one build reactor, Maven will only build a project once, never twice. If Z depends on A, Maven will build A then Z. – Tunaki Sep 27 '15 at 16:26
  • That's right but the question is slightly different: If Z depends on A and the build reaches Z after building A, does maven check the remote repo for a latest A-SNAPSHOT.jar and potentially replace A-SNAPSHOT.jar that just got created as part of the same build at A/target/ and/or local Maven repo? @Tunaki – phanin Sep 28 '15 at 16:39

4 Answers4

2

No, projects in the reactor will always be preferred over other dependencies.

This hold true even regardless of the following circumstances:

  • Running Maven with the -U flag set, meaning that update checks are forced.
  • Setting the <updatePolicy> to always in either settings.xml or in the POM.
  • Configuring the install plugin to <installAtEnd>true</installAtEnd>

Maven will figure out which artifacts are part of your reactor and exclude them from update checks.

This is quite easy to prove. If you try running Maven with either of the configurations above, you will see that Maven won't download artifact A (for instance), since each download is logged in the console.

For example, let's assume that you have this root POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>root</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
  <name>root</name>
  <modules>
    <module>A</module>
    <module>B</module>
    ...
    <module>Z</module>
  </modules>
</project>

And each module looks like this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.example</groupId>
    <artifactId>root</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <name>...</name>
  <artifactId>...</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
</project>

but the last one looks like this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.example</groupId>
    <artifactId>root</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>Z</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>Z</name>
  <dependencies>
    <dependency>
      <groupId>org.example</groupId>
      <artifactId>A</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>
</project>

Then no, module A will never be replaced by another version of the artifact from the repository.

Daniel
  • 4,033
  • 4
  • 24
  • 33
  • Thanks @Daniel. Could you please add any references if you have. – phanin Sep 30 '15 at 17:26
  • Well, I distinctly remember reading about it a long time ago. But I'm afraid I can't give you an explicit reference as such, because I don't remember exactly _where_ I read it. I created the example above based on my 9 years of experience of working with Maven to illustrate the point. – Daniel Oct 01 '15 at 07:49
1

Confirming Daniel answer, the implementation code has changed a lot between Maven 2 and 3 but basically the principle looks like this:

  • when a project (module) is built, its artifacts are attached to the "build reactor" and marked as "resolved",
  • when a project needs an artifact, it looks for a resolved artifact in the reactor,
  • if an attached resolved artifact is not found, then it will request for a resolution looking at the local and remote repositories.

Because resolution is only done when no resolved artifact is found and the module build is attaching its artifacts to the reactor, marked as resolved, then the answer is: no, Maven won't download a new SNAPSHOT jar to replace a jar that just got created in the same build.

You can give a look at the following code: MavenProject, DefaultArtifactResolver, DefaultArtifactResolver.

Community
  • 1
  • 1
Julien Carsique
  • 3,915
  • 3
  • 22
  • 28
0

There is a part of an answer to another question that solve your question:

When you build an application, Maven will search for dependencies in the local repository. If a stable version is not found there, it will search the remote repositories (defined in settings.xml or pom.xml) to retrieve this dependency. Then, it will copy it into the local repository, to make it available for the next builds.

For example, a foo-1.0.jar library is considered as a stable version, and if Maven finds it in the local repository, it will use this one for the current build.

Now, if you need a foo-1.0-SNAPSHOT.jar library, Maven will know that this version is not stable and is subject to changes. That's why Maven will try to find a newer version in the remote repositories, even if a version of this library is found on the local repository. However, this check is made only once per day. That means that if you have a foo-1.0-20110506.110000-1.jar (i.e. this library has been generated on 2011/05/06 at 11:00:00) in your local repository, and if you run the Maven build again the same day, Maven will not check the repositories for a newer version.

Note that this daily check is the default behavior. This behavior can be customized with the updatePolicy element defined inside the snapshot element.

From the documentation:

updatePolicy

The frequency for downloading updates - can be "always", "daily" (default), "interval:XXX" (in minutes) or "never" (only if it doesn't exist locally).

Thanks to Julien Carsique for this precision.

Community
  • 1
  • 1
Ortomala Lokni
  • 56,620
  • 24
  • 188
  • 240
0

From what I understand, SNAPSHOTS builds in local repository are used preferencially if available. To prove the point,

  1. Move your local maven repository to a different place, leaving the .m2/repository directory empty. (Do NOT delete it, as you may not find some of the artifacts later. Remote repositories do go down :))
  2. Change an API in A that is used by Z
  3. Run the build. It should fail while building Z if my line of thinking is correct. You have not changed the remote artifact, and the repository has nothing (since you moved it in the step above).
  4. Restore your original repository folder if you need to
  5. Rollback the API change in A.
miken32
  • 42,008
  • 16
  • 111
  • 154
Prashant
  • 1,002
  • 13
  • 29
  • Thanks for the answer. Your understanding is correct but the question is slightly different: We start a multi-module build, maven builds A, and finally reaches Z and discovers that it depends on A. At this point, if the remote repo / local repo has a newer A-SNAPSHOT.jar than the folder-of-A/target/A-SNAPSHOT.jar, which one does maven consider? – phanin Sep 28 '15 at 16:44
  • I believe it's Local before any other. Especially in a multi project build. It has to logically speaking, otherwise the dependencies would be meaningless. Hope that helps! – Prashant Sep 28 '15 at 17:33
  • Yes, please check Daniel's answer. I agree with you that it logically doesn't make sense to replace local jars in the same build. – phanin Sep 30 '15 at 17:28