Maven: Reuse single version definition when referencing parent pom - maven

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>

Related

Is it possible for a module of a multi module project to use the repository folder of another?

I was following a tutorial to learn multi-modules in maven, but what was being presented raised a question:
Is there a possibility to create a multi-module project where only one module accesses the database and the others use this connection for their respective controllers?
Basically what I want is to use the same repository folder to scan with each datasourceconfig in all modules.
The structure I imagined and even started to implement was:
|--main
| |--moduleOne
| |--|--Java
| |-----|-DataSource
| |-----|-models
| |-----|-repositories
| |--|--Resources
| |-----|-application.properties
| |--moduleN
| |--|--Java
| |-----|-controller
| |-----|-service
| |--|--Resources
| |-----|-application.properties
The first module run perfectyly, the other need a conetion and I did It, but when I run, this module use a h2 database or not connect because moduleOne is using repository folder.
How can I fix for that services access those repositories?
POM ModuleOne
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>sig</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>moduleOne</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>moduleOne</name>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<!-- SQL DEPENDENCIES -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<finalName>moduleOne</finalName>
</build>
</project>
POM ModuleN
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>sig</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>moduleN</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>moduleN</name>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<!-- MODULE ON WHICH IT DEPENDS -->
<dependency>
<groupId>com.example.sig</groupId>
<artifactId>moduleOne</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<finalName>moduleN</finalName>
</build>
</project>
"The bean 'RepositoryX', defined in
br.example.sig.moduleone.repositories.RepositoryX defined in
EnableJpaRepositories declared on ServiceX, could not be registered. A
bean with that name has already been defined in
br.example.sig.moduleone.repositories.RepositoryX defined in
EnableJpaRepositories declared on DatasourceConfig and overriding is
disabled.
Consider renaming one of the beans or enabling overriding by setting
spring.main.allow-bean-definition-overriding=true"
I had a service with the annotations "#EntityScan" and "#EnableJpaRepositories" pointing to the same directory as my datasource in one of the modules, I put it there and forgot it.
I deleted the annotations, that was what generated the conflict and not the use for different modules.

Flatten Plugin: Resolve dependencyManagement of bom without inherited

I created an example project for this problem: https://github.com/robeatoz/flatten-resolve-dependency-management-without-inherited
Following project structure is given:
foo-build as the parent for all modules
foo-module-a as child module
foo-module-b as child module
foo-module-c as child module
foo-dependencies as bom
I used the flatten-maven-plugin and the property revision for CI friendly builds in all modules:
<groupId>stack.overflow</groupId>
<artifactId>foo-build</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<properties>
<revision>0.1-SNAPSHOT</revision>
</properties>
The parent (foo-build) manages one external dependency:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>external.artifact</groupId>
<artifactId>module-managed-in-parent</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>
The bom (foo-dependencies) manages the foo dependencies:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-a</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-b</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-c</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
I want that the flattened pom of the bom contains only the resolved foo dependencies without the dependencies managed by the parent (foo-build) like this:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-a</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-b</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-c</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
How do you have to configure the flatten-maven-plugin to achieve this?
I already tried <flattenMode>bom</flattenMode>, but then the flattened pom does not resolve the versions:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-a</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-b</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-c</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>
With the following configuration
<pomElements>
<properties>remove</properties>
<dependencyManagement>resolve</dependencyManagement>
</pomElements>
the flattened pom contains the managed dependency of the parent:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-a</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-b</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>stack.overflow</groupId>
<artifactId>foo-module-c</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>external.artifact</groupId>
<artifactId>module-managed-in-parent</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>
It would be simpler to change your approach to more client-centric:
Make foo-dependencies a root project (./pom.xml).
with only foo-* dependencies in dependency management section
modules list with a single foo-build module (would be truncated by flatten plugin)
generic project properties (would be truncated by flatten plugin)
Make foo-build an intermediate project (./foo-build/pom.xml).
with third-party dependencies in dependency management section
with build-specific properties or profiles, required by your project (if any)
Retain foo-module-* leaf modules with foo-build as a parent
If you insist on plain project structure (./foo-module-*/pom.xml), you can use relativePath to point parent module, e.g.:
<parent>
<groupId>stack.overflow</groupId>
<artifactId>foo-build</artifactId>
<version>${revision}</version>
<relativePath>../foo-build/pom.xml</relativePath>
</parent>
<artifactId>foo-module-a</artifactId>
This way you will receive:
clear foo-dependencies as you wish;
zero copy-paste for foo-* dependencies;
flexibility to build whatever and however you like in foo-build without side-effects on foo-dependencies (neither now nor in the future).
I have like the exact same usecase and I solved it with the following configuration.
You need to apply a very specific configuration to the flatten-plugin within the pom file of the BOM module:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<configuration>
<updatePomFile>true</updatePomFile>
<pomElements>
<dependencyManagement>expand</dependencyManagement>
</pomElements>
</configuration>
</plugin>
expand means that the dependencyManagement block will be replaced with the one from the effective pom where all references are properly resolved. updatePomFile is necessary because otherwise by default, the flattened pom would not be published for poms with <packaging>pom</packaging>
Here are the relevant parts from the flatten-plugin's documentation:
updatePomFile: https://www.mojohaus.org/flatten-maven-plugin/flatten-mojo.html#updatePomFile
Explanation for expand: https://www.mojohaus.org/flatten-maven-plugin/apidocs/org/codehaus/mojo/flatten/ElementHandling.html#expand
You don't need to change the version with ${revision}, use ${project.version}, take a try

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 - Get non-inheritable pom version.

Assume a parent pom with version 1.0 and a child pom with version 2.0.
Now I define a dependency like this in the parent.
<dependency>
<groupId>somedep</groupId>
<artifactId>somedep</artifactId>
<version>${project.version}</version>
</dependency>
In the parent, the version evaluates to 1.0, but in child it evaluates to 2.0. Is there a way, in which I can make it evaluate to 1.0 in child too (Ofcourse no version harcoding in parent is permitted)?
EDIT:
If we look in http://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Project_Inheritance, we can see that:
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.
Which means that you can't rely on variables which get dynamically resolved in parent and child and are of the type `${project.version} if your child and parent have different versions, which is generally not what you'd want but very specific to your case. I guess what you are left over with is to hardcode the dependency in the parent using something like depedencyManagement:
Parent:
<project>
<groupId>example</artifactId>
<artifactId>masta</artifactId>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>someDep</groupId>
<artifactId>someDep</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>someDep</groupId>
<artifactId>someDep</artifactId>
</dependency>
</dependencies>
</project>
And child:
<project>
<parent>
<groupId>example</artifactId>
<artifactId>masta</artifactId>
<version>1.0</version>
</parent>
<groupId>example.masta</artifactId>
<artifactId>child</artifactId>
<version>2.0</version>
<dependencies>
<dependency>
<groupId>someDep</groupId>
<artifactId>someDep</artifactId>
</dependency>
</dependencies>
</project>
or, indeed, use ${parent.version} explicitly in the child. One thing to note is I'd generally not have aggregator projects like parent introduce any dependencies but have only dependencyManagement.
This is the second approach, without dependency management:
Parent:
<project>
<groupId>example</artifactId>
<artifactId>masta</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>someDep</groupId>
<artifactId>someDep</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
And child:
<project>
<parent>
<groupId>example</artifactId>
<artifactId>masta</artifactId>
<version>1.0</version>
</parent>
<groupId>example.masta</artifactId>
<artifactId>child</artifactId>
<version>2.0</version>
<dependencies>
<dependency>
<groupId>someDep</groupId>
<artifactId>someDep</artifactId>
<version>${parent.version}</version>
</dependency>
</dependencies>
</project>
But I guess none of the approaches actually fully satisfies what you want.

Use property defined in maven dependency artifact

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>

Resources