maven pom.xml dependencies order vs classpath/build path order - maven

I am trying to understand the connection between the dependencies in a project's pom.xml file and the order of the java classpath/build path (my question is also regarding the inheritance of poms).
So far I wasn't able to find a detailed step-by-step explanation.
I have noticed for sure that it's not "the same", meaning, sometimes dependencies I have in my pom.xml will not appear in the build path in eclipse or will not be in the same order(after committing mvn eclipse:eclipse -$someflag) .
Let's assume for example I have the following Parent pom:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>SOME_GROUP_ID</groupId>
<artifactId>PARENT</artifactId>
<version>SOME_VERSION</version>
<name>${project.groupId}:${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>SOME_OTHER_ARTIFACT1</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<modules>
<module>CHILD</module>
</modules>
</project>
and that some other project's pom.xml inherits it:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>SOME_GROUP_ID</groupId>
<artifactId>PARENT</artifactId>
<version>SOME_VERSION</version>
</parent>
<artifactId>CHILD</artifactId>
<name>${project.groupId}:${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>SOME_OTHER_ARTIFACT2</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
My questions are: If I now run mvn eclipse:eclipse -$someflag on CHILD project:
Should the build path for CHILD project contain: PARENT, SOME_OTHER_ARTIFACT1, SOME_OTHER_ARTIFACT2 for sure? not for sure? when and why one of them should/shouldn't appear in the build path?
Should the classpath file for CHILD project contain: PARENT, SOME_OTHER_ARTIFACT1, SOME_OTHER_ARTIFACT2 for sure? not for sure? when and why one of them should/shouldn't appear in the build path?
Is it related to the flag (i.e $someflag) that was used when running mvn eclipse:eclipse?
Should the jars in the library appear also in the order of the dependencies in the project that is being initialized? i.e PARENT, SOME_OTHER_ARTIFACT1, SOME_OTHER_ARTIFACT2 (from top to bottom) necessarily? When and why should the order be different?
Thank you

Re "my question is also regarding the inheritance of poms"
See Maven: The Complete Reference, Project Inheritance:
You can avoid repeating yourself if your projects make use of inheritance via the parent element. When a project specifies a parent, it inherits the information in the parent project’s POM. It can then override and add to the values specified in this parent POM.
... and Multi-module vs. Inheritance:
There is a difference between inheriting from a parent project and being managed by a multimodule project. A parent project is one that passes its values to its children. A multimodule project simply manages a group of other subprojects or modules.

Related

Retrieving the top-level version from sub modules in Maven

This is a version of the question posted in Maven: retrieving the main module version from a sub-module, but I can't figure out how to apply the answer. I'm trying this on Maven 3.6.3. I've posted the repository this can be played around with at this GitHub project
I have a top-level project:
<groupId>com.vps</groupId>
<artifactId>main-module</artifactId>
<version>5.0</version>
<packaging>pom</packaging>
There is another multi-module project that needs to be parented by this top-level project, and it has independent versioning from the top-level project.
The projects are not expected to be in the same repository, and are generally released independently of each other.
I want to declare a property that I can further use to refer to the version of this top-level project parent (say to pull in artifacts with the correct version):
<artifactId>auxiliary</artifactId>
<version>1.0</version>
<parent>
<groupId>com.vps</groupId>
<artifactId>main-module</artifactId>
<version>5.0</version>
</parent>
<properties>
<main.version>${project.parent.version}</main.version>
</properties>
<modules><module>corelib</module></modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vps</groupId>
<artifactId>main-module-1</artifactId>
<version>${main.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
Now, the sub-module is to pull and use the dependency:
<parent>
<groupId>com.vps</groupId>
<artifactId>auxiliary</artifactId>
<version>1.0</version>
</parent>
<artifactId>corelib</artifactId>
<properties>
<!-- this doesn't work
<main.version>${project.parent.parent.version}</main.version>
-->
</properties>
<dependencies>
<dependency>
<groupId>com.vps</groupId>
<artifactId>main-module-1</artifactId>
</dependency>
</dependencies>
If I set main.version as a reference to ${project.parent.version} in the auxiliary POM, compilation of corelib fails because it tries to pull com.vps:main-module-1:1.0, which doesn't exist. I guess this is because the properties are resolved based on the effective POM being processed at the moment, and from there, the ${project.parent.version} is the version of corelib's parent.
If I override main.version in the corelib sub-module as ${project.parent.parent.version}, I get an error saying that effective version computed for com.vps:main-module-1 is '${project.parent.parent.version}', and is invalid. I guess this means that the property cannot be resolved all together, but I can't quite understand why.
So, how do I reasonably (i.e. without hardcoding the top-level in both the parent definition and another property) refer to that top-level version value from descendant submodules?

Maven POM packaging with dependencies

I'm trying to construct a codebase where subsystems can be developed as maven modules, without the importing POM needing to concern itself with the internal structure of the maven module.
The "importing" pom
<project>
<artifactId>application</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<artifactId>submodule-1</artifactId>
</dependency>
</dependencies>
</project>
The "imported" pom
<project>
<artifactId>submodule-1</artifactId>
<packaging>pom</packaging>
<modules>
<module>api</module>
<module>implementation</module>
</modules>
<dependencies>
<dependency>
<artifactId>api</artifactId>
</dependency>
<dependency>
<artifactId>implementation</artifactId>
</dependency>
</dependencies>
</project>
This does seem to work, at least partially; the generated JARs appear to be on the classpath during mvn package. IntelliJ shows the application has a dependency on submodule-1 and transitively on api and implementation. However, mvn dependency:tree fails while building submodule-1 saying
Could not resolve dependencies for project submodule-1:pom:1.0.0-SNAPSHOT: Could not find artifact api:jar:1.0.0-SNAPSHOT
I'm trying to determine if this is a valid pattern, that of having packaging of pom, with defined dependencies which are also defined modules in the POM.
Have I stumbled upon a working-but-not-supported edge case, or is the dependency plugin broken in some way, or I'm breaking it in some way, or something else?

Maven projects - how to read a property that is defined in the pom file of a project that is added as a dependency

I am working on a large project that contains many maven projects. We are using Maven 3.3.9.
I want to use a property that is defined in one maven project in another project, but i can't access the property.
The situation is: there is one maven project called "product-packaging", that has a pom file that includes some properties. This maven project only contains a pom file. It is used for generating a package that contains a set of components that are compatible with each other.
There is another maven project called "projectX" that has a dependency on "product-packaging". In "projectX" we want to use a property that is defined in "product-packaging".
I want to add xx-ws-rest as a dependency in projectX, and i want to set the version as xx-ws-rest.version, which is a property that is defined in "product-packaging"
The pom of "product-packaging" looks like:
<project ...>
...
<properties>
<xx-ws-rest.version>1.6.0</xx-ws-rest.version>
</properties>
...
</project>
The pom of "projectX" looks like:
<project ...>
...
<properties>
<product-packaging.version>1.6.0</product-packaging.version>
</properties>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.company.product</groupId>
<artifactId>product-packaging</artifactId>
<version>${product-packaging.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.company.product.xx</groupId>
<artifactId>xx-ws-rest</artifactId>
<version>${xx-ws-rest.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.company.product.xx</groupId>
<artifactId>xx-ws-rest</artifactId>
<type>war</type>
</dependency>
....
</dependencies>
</project>
AFAIK this is not possible. The usual way to define common properties for different projects is to use a parent POM. There, you can define properties and let the different projects inherit from that parent POM - that way, the properties are visible for all child projects.

Avoid wrong version interpolation if child's pom version is different from those of the parent's aggregator pom and its sub modules

Problem description
We have a Maven aggregator pom with some child poms (modules) all having the same version:
pom.xml (parent zoo, version 2.0.0)
|-- pom.xml (child module cat, version 2.0.0)
|-- pom.xml (child module dog, version 2.0.0)
|-- ...
Within the dependency management section all children are declared with the project version to ease declaration of dependencies.
The parent pom looks like
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.0</version>
<packaging>pom</packaging>
<modules>
<module>cat</module>
<module>dog</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<version>${project.version}</version>
</dependency>
<!-- other child modules go here -->
</dependencies>
</dependencyManagement>
The child poms are defined as
<parent>
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.0</version>
</parent>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>dog</artifactId>
</dependency>
</dependencies>
There is another pom which declares the parent pom as its parent too (inheritance) but is not listed as sub module in this parent (no aggregation). This pom has a different version.
<parent>
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.0</version>
</parent>
<groupId>com.acme</groupId>
<artifactId>boo</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>dog</artifactId>
</dependency>
</dependencies>
Actually we have expected that the version of the dependency com.acme.dog is pulled from the dependency management section of the parent pom com.acme.zoo and is equal to 2.0.0. However the Maven documentation on project interpolation and variables says
One factor to note is that these variables are processed after inheritance as outlined above. This means that if a parent project uses a variable, then its definition in the child, not the parent, will be the one eventually used.
That is: in the reactor build the variable ${project.version} used in the dependency management section of the parent pom com.acme.zoo is evaluated with respect to com.acme.bar and equal to 1.0.0 what is not as intended.
Note
There is a workaround with using a variable in the parent pom which has to be kept in sync with the parent pom versions. However, this solution is incompatible with the Maven Release Plugin.
Question
How can we achieve the desired behaviour
aggregator pom with children having the same version
declaration of children in the dependency management section to ensure that all dependencies have the same version
use of inheritance together with different versions
compatibility with maven-release-plugin
without the pitfalls of project interpolation of variables?
The maven release plugin is able to change the versions of the dependencies managed in the parent pom.
So if you define your maven parent like this:
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>cat</module>
<module>dog</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<!-- other child modules go here -->
</dependencies>
</dependencyManagement>
As you see the versions of the parent and the managed dependency are the same. I set them to a SNAPSHOT version because the release plugin will create the final versions on release:perform
Your child poms can stay as you had them.
Because in your setup, your parent project is also the reactor you can then call
mvn release:perform -DautoVersionSubmodules=true
which will update the version of the parent in all submodules when you run this command. That option is essentially the same as if you run
mvn versions:update-child-modules
meaning it will change the child poms.
After you run the mvn release:perform command your parent pom will look like this:
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>cat</module>
<module>dog</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<version>2.0.1-SNAPSHOT</version>
</dependency>
<!-- other child modules go here -->
</dependencies>
</dependencyManagement>
and your child poms like this
<parent>
<groupId>com.acme</groupId>
<artifactId>zoo</artifactId>
<version>2.0.1-SNAPSHOT</version>
</parent>
<groupId>com.acme</groupId>
<artifactId>cat</artifactId>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>dog</artifactId>
</dependency>
</dependencies>
The final versions will only exist in the tag created by the release:prepare command.
PS: You may define other versions for the final and the next development version when they are prompted after running the release:prepare command.
The simplest solution is modify pom of zoo and replace <version>${project.version}</version> with <version>2.0.0</version>
Please note:
when you change version to next number, for example 2.0.1, with
versions-maven-plugin, dependency management section will be also
updated.
Spring use simplest solution, see
http://central.maven.org/maven2/org/springframework/spring-framework-bom/4.2.7.RELEASE/spring-framework-bom-4.2.7.RELEASE.pom
Summary: using <version>${project.version}</version> in dependency management is wrong idea.
From Maven Introduction to the pom : http://maven.apache.org/guides/introduction/introduction-to-the-pom.html
Project Inheritance > Example 1 > The Solution
Alternatively, if we want the groupId and / or the version of your
modules to be the same as their parents, you can remove the groupId
and / or the version identity of your module in its POM.
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
My approach to that is to track it in the child POM. It's a bit less typing overall, close to where the actual dependency lives and is low maintenance for most projects. YMMV
<dependencies>
...
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>foo-sibling</artifactId>
<version>${project.version}</version>
</dependency>
...
</dependencies>

Is there a way to cascade the version of a parent pom?

I have a root pom.xml that acts as a parent for several child pom.xml files, which is great if you have one or two child pom.xml files. I am working on a project that has 50+ child pom.xml files, and several releases going on at once. Everything is great until I need to update the version of the parent pom.xml files, which can be tedious. Is there a way to cascade the version of the parent pom.xml down to all child pom.xml files?
I had the idea to just create a property in the parent pom.xml for the current version, but that's not working.
EDIT
Here is a sample from my child pom.xml files:
<parent>
<groupId>myGroup</groupId>
<artifactId>myArtifactId</artifactId>
<version>1.0</version> <!-- This is the value that I would like to parameterize in my child pom.xmls -->
<relativePath>../../pom.xml</relativePath>
</parent>
As an aside, I am using Maven 3.0.3
You can do it this way:
Have an aggregator POM project, in which you specify all your child modules and then run this goal on the this aggregator project:
mvn versions:update-parent
This will update all child modules with the new parent version.
Alternatively you can use the same before each release:prepare goal of your child module, thus avoiding creating the aggregator module.
So in case you want to release a child module, you just run this goal:
mvn versions:update-parent release:prepare
This will ensure that the parent gets updated with a new version before it is being prepared for a release.
I read in your comment you are missing an scm tag. Example of usage in case of subversions might be:
<scm>
<developerConnection>scm:svn:https://your.domain/scm/svn/yourModule/trunk/</developerConnection>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<tagBase>https://your.domain/scm/svn/yourModule/tags</tagBase>
</configuration>
</plugin>
</plugins>
</build>
Release plugin does not work without a properly configured scm.
You do not need to configure the tagbase tag in release plugin in case you follow "trunk, tags, branches" best practice in your svn repository, see this answer.
I assume you having a thing like this:
+--root (pom.xml)
+--- module1 (pom.xml)
+---
In the root pom.xml:
<project ..>
<groupId>the.company.project</groupId>
<artifactId>the-artifact</artifactId>
<version>1.0-SNAPSHOT</version>
...
</project>
whereas in the childs you should have:
<project ..>
<parent>
<groupId>the.company.project</groupId>
<artifactId>the-artifact</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>the-artifact-child</artifactId>
</project>
For such purposes you should use the maven-release-plugin which handles the updating of the version in root as well in childs. If you don't use maven-release-plugin you can use the versions-maven-plugin which can handle the same things.
I had the same problem and what I did was slightly different than anything suggested so far. Assume that your project has the following folder structure:
parent
+-- child1
+-- child2_of_parent
+-- child3_of_parent
+-- child4
+-- child5_of_child4
Do note that except for child5_of_child4, all the rest of the projects have as parent the top level project parent. This is regardless of the folder structure.
Parent pom.xml:
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>1.1-SNAPSHOT</version>
All children pom.xml except for child5_of_child4 that has as parent child4:
<parent>
<groupId>...</groupId>
<artifactId>parent</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../parent</relativePath>
</parent>
You go to the parent directory and change its version from version from 1.1-SNAPSHOT to 1.2-SNAPSHOT. Then you do (more details here):
mvn versions:update-child-modules
As this is not recursive, it only works on the direct children of your parent project. In other words, all sub-modules will be updated to point to parent 1.2-SNAPSHOT except for child5_of_child4.
In your child pom.xml:
<parent>
<groupId>groupId</groupId>
<artifactId>parent.artifactId</artifactId>
<version>version</version>
<relativePath>../parent-pom</relativePath>
</parent>
<artifactId>child.artifactId</artifactId>
Just don't put the version in the child poms. It's inherited automatically. It will show up as a warning in Eclipse plugin if you edit there.

Resources