Use property defined in maven dependency artifact - maven

Is it possible, to access the properties defined in a dependent maven artificat without making it the parent artifact of current project?
Example:
My 3rd party dependent artifact has the following pom:
<project>
<groupId>3rd</groupId>
<artifactId>party</artifactId>
<version>1</version>
<properties>
<test>this is a test</test>
</properties>
</project>
My own project depends on this 3rd party artifacts and wants to reuse the property in some way:
<project>
<groupId>my</groupId>
<artifactId>own</artifactId>
<dependencies>
<dependency>
<groupId>3rd</groupId>
<artifactId>party</artifactId>
<version>1</version>
</dependency>
</dependencies>
<properties>
<mytest>${test} - in my artifact</mytest>
</properties>
</project>

Related

How does Maven handle transitive dependencies inherited from parent?

Given the parent and child pom below and lib1 and lib2 both include the class foo.bar.Test.
parent pom
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>foo</groupId>
<artifactId>foo-parent</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>my.transitive</groupId>
<artifactId>lib1</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
child pom
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>foo</groupId>
<artifactId>foo-parent</artifactId>
<version>1.0</version>
</parent>
<artifactId>foo-child</artifactId>
<dependencies>
<dependency>
<groupId>my.transitive</groupId>
<artifactId>lib2</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
If I include foo-child as a dependency in myApp and instantiate foo.bar.Test, which version of the class would Maven resolve to? And why?
my app pom
<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>myApp</artifactId>
<groupId>myApp</groupId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>foo</groupId>
<artifactId>foo-child</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
The short answer would be: it depends on which one is found on the classpath first.
Having 2 of the same classes packaged with an application is not ideal as it can lead to many difficult to debug errors... If your myApp project is just going to be a jar then it would be best to compile it using the same library as what is going to be available to it at runtime.
I believe maven uses the order it is written to the pom to build. One way of looking at this would be to run the following command for myApp:
mvn dependency:tree -Dverbose
This will print the dependencies in the order that they should appear on the classpath per spec. You can always use exclusions to exclude any inherited library you might not want. Hope this helps.

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>

Maven: Reuse single version definition when referencing parent pom

I have the following pom definition (bottom).
I have many child poms (50 projects), requiring me to update all the poms on each release, for example, when moving from 1.0 to 1.1.
How can I define the version in a single place, and reuse it in all the poms?
EDIT- Some motivation about the request: I'd like to make as little footprint as possible when switching version. As little files to change. As little commits to push. Etc.
EDIT - Cannot use parent properties before the parent is loaded.
<parent>
<groupId>info.fastpace</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>child-1</artifactId>
I can use parent's properties and reference the parent using relative path instead of version. Example:
Parent:
<groupId>info.fastpace</groupId>
<artifactId>parent</artifactId>
<version>${global.version}</version>
<properties>
<!-- Unique entry point for version number management -->
<global.version>1.0-SNAPSHOT</global.version>
</properties>
Child:
<parent>
<groupId>info.fastpace</groupId>
<artifactId>parent</artifactId>
<version>${global.version}</version>
<relativePath>..</relativePath>
</parent>
<artifactId>child-1</artifactId>
Disadvantage: Requires the parent pom to exist in the file system and make all developers use the same relative file structure.
See more info here.
You can use maven properties to build a single version numbering scheme.
Like this:
<properties>
<my.version>1.1.2-SNAPSHOT</my.version>
</properties>
And then reference it like this:
<version>${my.version}</version>
Look here for more information:
Maven version with a property
The use of properties is recommended when you have multiple dependencies of the same release. For example:
<project>
...
<properties>
...
<dep.jooq.version>3.7.3</dep.jooq.version>
...
</properties>
...
<dependencies>
...
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>${dep.jooq.version}</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-meta</artifactId>
<version>${dep.jooq.version}</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen</artifactId>
<version>${dep.jooq.version}</version>
</dependency>
...
</dependencies>
...
</project>
Instead, if you have to use the same dependency in different points in the POM file or if you are in module and you would use the same dependency version of the parent, I suggest to use the following way:
<project>
...
<dependencyManagement>
<dependencies>
...
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
</dependency>
...
<dependencies>
</dependencyManagement>
...
<dependencies>
...
<!-- The following block could be in a module -->
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<!-- It is no more ncessary to use the version -->
</dependency>
...
<dependencies>
...
</project>

Dependency hierarchy not using property from parent pom?

I have a problem I wonder if someone could help me to resolve.
I have a module structure in my project where I resolve dependencies using Maven. For this structure I have versions with different content I distinguish using classifiers. For each classifier I have defined a profile in a parent pom with the string for the classifier in a property. This way in my modules I use this property and is the profile I defined who decides the classifier constant.
The problem I'm stuck with now is the dependency hierarchy not recognizing the classifier when a dependency is inherit from the one I define in the pom of one of my modules.
For example, if I have projects A, B and C, B depends on A and C depends on B, from C I'm getting B with the classifier but not A with it.
This happens if I use the property from the parent pom. If I use directly a constant string instead, the dependencies get caught correctly.
The only solution I see is using profiles on each pom defining the dependencies inside them. But I have 5 profiles! Isn't there any other way to resolve this?
I'm using STS 3.8 with m2e plugin as my IDE.
Thank you in advance!
I add the poms
parent pom:
<profiles>
<profile>
<id>TRUNK</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<svnBranch />
</properties>
</profile>
<profile>
<id>MON</id>
<properties>
<svnBranch>MON</svnBranch>
</properties>
</profile>
<profile>
<id>LOLA</id>
<properties>
<svnBranch>LOLA</svnBranch>
</properties>
</profile>
<profile>
<id>NBA</id>
<properties>
<svnBranch>NBA</svnBranch>
</properties>
</profile>
<profile>
<id>TEST</id>
<properties>
<svnBranch>TEST</svnBranch>
</properties>
</profile>
<profile>
<id>PROD</id>
<properties>
<svnBranch>PROD</svnBranch>
</properties>
</profile>
</profiles>
Project A:
<parent>
<groupId>com.myproject</groupId>
<artifactId>pom</artifactId>
<version>1.0.10</version>
</parent>
<artifactId>core-services</artifactId>
<version>1.1.0.41-SNAPSHOT</version>
Project B:
<parent>
<groupId>com.mycompany</groupId>
<artifactId>pom</artifactId>
<version>1.0.10</version>
</parent>
<artifactId>olb-services</artifactId>
<version>1.1.0.41-SNAPSHOT</version>
<properties>
<module.core-services.dependency.version>1.1.0.41-SNAPSHOT</module.core-services.dependency.version>
</properties>
<dependencies>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>core-services</artifactId>
<version>${module.core-services.dependency.version}</version>
<classifier>${svnBranch}</classifier>
</dependency>
</dependencies>
Project C:
<parent>
<groupId>com.mycompany</groupId>
<artifactId>pom</artifactId>
<version>1.0.10</version>
</parent>
<artifactId>nba-services</artifactId>
<version>1.1.0.41-SNAPSHOT</version>
<properties>
<module.olb-services.dependency.version>1.1.0.41-SNAPSHOT</module.olb-services.dependency.version>
<module.core-services.dependency.version>1.1.0.41-SNAPSHOT</module.core-services.dependency.version>
</properties>
<dependencies>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>olb-services</artifactId>
<version>${module.olb-services.dependency.version}</version>
<classifier>${svnBranch}</classifier>
</dependency>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>core-services</artifactId>
<version>${module.core-services.dependency.version}</version>
<classifier>${svnBranch}</classifier>
</dependency>
</dependencies>
Using the ${svnBranch} in the classifier tag for each dependency doesn't work. It looks like in project B, when is referenced by project C, the property ${svnBranch} is empty nevertheless it comes from the parent pom.
In maven, you can only use a profile defined at the parent level in your child pom, if you can only activate it at built time by passing -D{activation.property}=value or -P{profile.id/s} .
You cannot define a profile in your parent and try it to activate in your child pom as profile can not be inherited(you are not even trying to activate in the child pom in your case as per your example).
in another word,unless the profile is activate by default maven doesn't know about it (you might be tempted to activate everything by default in your case, but bear in mind only one profile can be activate by default at the time)
your problem is ${svnBranch} from TRUNK is only present in your child pom and has no value, therefore maven only acts on the GAV and not the classifier. and to prove that check your child's effective pom (mvn help:effective-pom). also you can check which of your profile are active and which are not (mvn help:all-profiles).
I don't think using profiles is the best approach for what you are doing. A better/simpler approach maybe be to just declare your branch names in normal properties in your parent for example.
<properties>
<svnBranch.lola>LOLA</svnBranch.lola>
<svnBranch.nba>NBA</svnBranch.nba>
</properties>
then your child uses as needed.
<dependencies>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>olb-services</artifactId>
<version>${module.olb-services.dependency.version}</version>
<classifier>${svnBranch.lola}</classifier>
</dependency>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>core-services</artifactId>
<version>${module.core-services.dependency.version}</version>
<classifier>${svnBranch.nba}</classifier>
</dependency>
</dependencies>

Maven 3 regression: Profile dependencies lost?

I observed a change behavior between Maven 2 and Maven 3. Is this a bug or a feature? I couldn't find anything in the Maven 3.x Compatibility Notes
I use two different profiles to add dependencies for different environment in a multi-module project.
parent-pom:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>group</groupId>
<artifactId>main</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<modules>
<module>common</module>
<module>portal</module>
</modules>
</project>
The common-pom has the profile in it:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>group</groupId>
<artifactId>common</artifactId>
<packaging>jar</packaging>
<version>1.0.0-SNAPSHOT</version>
<parent>
<groupId>group</groupId>
<artifactId>main</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<profiles>
<profile>
<id>development</id>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>production</id>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
The portal-pom has only the common dependency and should include the transitive dependency from the common module:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>group</groupId>
<artifactId>portal</artifactId>
<packaging>war</packaging>
<version>1.0.0-SNAPSHOT</version>
<parent>
<groupId>group</groupId>
<artifactId>main</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>group</groupId>
<artifactId>common</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
Building this project (from the parent) via Maven2 mvn -P production package results in a WAR which includes the transitive dependency. (I used those simple dependencies for easy reproduction)
Executing via Maven3, I get only the common.jar in the WAR, but not the transitive dependency.
Is this a desired behavior?
To make things even "interesting": If one of the profiles is activated by default (explicit in the common-pom as the activation is not derived from the parent to the child modules) these transitive dependencies are always add to the portal.
But filtering or property-setting via profiles works as expected.
This comment solves it the one way:
the situation described above does work when profile activation using properties is used
With property activation (and not via -P) it works in Maven2 and 3
But the real solution was "caused" by the release plugin:
The profile must be submitted to release-plugin via
-Darguments=-Pproduction
Not a solution, but your use case looks similar to this open maven bug. Interestingly, according to the bug details, it happens on earlier maven versions as well.

Resources