Set Maven dependency versions in properties file - maven

We have a couple of different applications which may or may not interact together. When they interact together, there have been issues because of mismatch in third party library versions (Let it be Spring or something else).
The pom files for these applications are separate, but to solve the above issue, we want them to use the same versions of third party libraries. The easiest way to do this is to specify the versions in common properties file, and then let respective pom.xml read the versions from the properties file.
Usually I am used to specify the versions as properties in the parent pom, and let the module pom read it from there. Is there a way I can make pom.xml read the properties file for reading the versions?

Some projects, e.g. spring-cloud and spring-boot, express their 'release train' (a set of dependencies and their versions that are known to work well together) in a 'BOM' (bill of materials). The BOM is nothing but a POM with only a dependencyManagement section, where all these dependencies are listed with the correct version. That BOM is then included in each project's POM that should follow these dependencies/versions in its dependencyManagement section, with scope 'import'.
E.g.
You create your separate project 'my-bom', containing only a pom like this:
<project>
<groupId>your.organication.program</groupId>
<artifactId>my-bom</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.whatever</groupId>
<artifactId>somedependency</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.whatever</groupId>
<artifactId>someotherdependency</artifactId>
<version>4.5.6</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
And then you include that in each project that should be aligned with these dependencies/versions:
groupId>your.organication.program.project</groupId>
<artifactId>some-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>your.organisation.program</groupId>
<artifactId>my-bom</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencyManagement>
Within the projects the dependencies that are effectively used must still be referenced in dependencies-section, but without the version - the versions are managed by the BOM.

Related

spring-boot-starter-parent: Can this be included as dependency

I was understanding something in spring boot and to being with, used a very simple snippet, like adding this in pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
As I understand <parent> in this context means that in my pom.xml, there we have a parent pom.xml (saw the pom.xml file for spring-boot-starter-parent) which will have list of dependencies.
The important thing is that it is only pom packaging, and NOT a real jar / binary (please correct if I am wrong)
I saw the following in mvn repository:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
</dependency>
My doubt is:
How can we include it as an dependency , it is just a pom packaging (and not a real jar / war), which acts as central place which holds common dependencies? Is it allowed? I tried adding in my project, but saw errors in STS IDE.
How does this get downloaded? Can we see the contents of this "parent"
First off, you've probably missed the meaning of parent pom in this case.
Spring boot of any specific version (2.2.1 in this case) comes with a bunch of possible integrations with many technologies / libraries. So it provides "default" versions of the libraries to work with because its very hard to check that it compatible with all possible versions of all libraries. You can of course provide your own version but then you should test a compatibility as an application maintainer.
So If you'll checkout the source code of spring-boot-starter-parent pom, you'll see that it provides some plugins and plugin management and more importantly inherits from another pom called spring-boot-dependencies
Note it doesn't add any dependencies to your project. It only defines a dependencyManagement section. This means that once you'll use the dependency in your project (that inherits) from this pom, you don't have to specify a version, only group id and artifact id.
Again, that's because spring boot offers by default very specific versions of thirdparties - the version that it was verified that it's compatible with...
Now as for the second part of the question - indeed it doesn't make sense to include dependency with packaging pom like you've posted, could you please provide a link where exactly you've seen this?
Sometimes when people adopt spring boot in their projects they already have have some parent, so they can't use the inheritance, in this case they can use a very special maven scope "import" and use the dependency on pom treating it as BOM (bill of materials) - frankly a pretty advanced stuff in maven. But spring boot uses this feature for these cases.
The dependency inclusion looks like this:
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
Note, the `import line. From maven's site: This is meant to allow dependency management information such as versions and excludes be retrieved from a remote POM file.
Here is a tutorial about this topic
#CuriousMind, including the spring-boot-starter-parent as a dependency is like trying to instantiate an interface or Abstract Class in Java. As you noticed, its packaging is pom, meaning it is just a maven artifact to help configure your maven project. Jar and War will contain some java binaries. I think the MVN repository code automatically generate all sample as dependencies..

Import maven property used in bill of materials (bom)

We have a project layout with sub-modules and dependencies in bom files:
projectA
bom
module1
module2
The actual version numbers are defined as properties in the bom file, so for each dependency we have something like
<properties>
<guice-version>4.1.0</guice-version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice-version}</version>
</dependency>
</dependencies>
The top-level pom in projectA import the bom in the dependecyManagement section with
<dependencyManagement>
<dependencies>
<dependency>
<groupId>group</groupId>
<artifactId>bom</artifactId>
<version>1.0.0</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
This all works fine and we have centralized dependency definitions.
However, at one point during the build process we need to use the version of one of the dependencies. I was hoping that importing the bom in the dependencyManagement section would also import the properties into the top-level pom, but that is not the case. It is also not possible to make the bom a children of the top-level pom with a section because this creates a cyclic dependency between pom files.
I thought about putting the properties into an external file and read it with the maven properties plugin where needed. That would be obviously in the bom and in the pom file where we need to get the version of the dependency. However, since the bom is not packaged as a jar, so the path would have to be hard-coded.
I could fix it by duplicating the properties to two places, but I don't want to do that. Is there a way to get the version of a dependency, e.g. using a property defined by the dependency?
The problem seems to be common enough and I am wondering if we did something wrong in the project structure. What is the standard way to centralize properties in this case?
You can try using the BOM as the parent of your parent module as a BOM is technically some kind of minimal version of a POM. This is what the official Maven project describes here:
http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
I don't like this solution, because if you already extend from a parent, you get into a multi-inheritance problem here.
It appears that a BOM is not fulfilling your requirements. It only assembles a bunch of dependencies like an extract of a dependency management section of a parent project. However its internal structure should not matter to your project. If the BOM changes structurally, your project won't be influenced by that. Perhaps it's a more proper solution not to use a BOM here, but instead pick the dependencies and use your own version property here. Depends a little bit on how complex the BOM is.
So either use the BOM as a parent or dismiss the BOM at all, since you need more than your BOM gives you.
The actual purpose about BOM import is precisely to avoid having to declare the exact version of the dependencies declared in the BOM.
So, consider that you have a BOM witch declares a dependency like
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice-version}</version>
</dependency>
(we asume your BOM also declares the property in it).
So then, in your projects, you can declare the guice dependency without having to determine the version attribute as it is inherited from the BOM.
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
The benefit is that if you change your BOM version, this kind of dependencies will be updated accorndingly without having to do any change in the pom.xml of your project!

Adding a dependency existing internally as a dependency

My project is a fairly large project consisting of many maven modules (but not microservices). I was trying to do Moving from spring to spring-bom on WAS but seems lot of clashes in versions. So for example one of my modules is using commons-collectionsversion 2.6.0 and my current project is using 3.2.2. I want the same jar to be used across. Since its more of a migration project I cannot do changes in container or repository changes at this time. I should only make sure that all the version are compatible with each other. My plan :
I want to include a dependency which is with in some other dependency
into the current pom as a dependency.
Also I want other jars in this pom (which exists as a dependency) to included the dependency
Is there anyway to do it?
I didn't completely understand your question, but the can help you to define a cross-module dependency version, as long as you place it in the parent-pom file.
<dependencyManagement>
<dependency>
<groupId>com.group</groupId>
<artifactId>project-1</artifactId>
<version>1.0.0</version>
</dependency>
</dependencyManagement>
and then define the dependency in the relevant module without providing it a version (it will be inherited from the parent-pom's <dependencyManagment> tag:
<dependencies>
<dependency>
<groupId>com.group</groupId>
<artifactId>project-1</artifactId>
</dependency>
</dependencies>

Update pom to use released versions

Trying to find a way to update a pom to use latest versions of a RELEASED dependency instead of SNAPSHOT.
We have a assembly project that assembles an image to be deployed that during development uses SNAPSHOT dependencies.
But now I want to update the dependencies to use the latest released dependencies. Tried using versions:use-latest-releases but it only affects already released versions in the pom.
Any ideas?
EDIT (can not for security reasons post the pom but here's an example)
<project>
....
<dependencies>
<dependency>
<groupId>a.b.c</groupId>
<artifactId>c-d-f</artifactId>
<version>1.0.1-SNAPSHOT</version>
<type>war</type>
</dependency>
<dependency>
<groupId>a.b.c</groupId>
<artifactId>g-h-i</artifactId>
<version>1.1.6-SNAPSHOT</version>
<type>war</type>
</dependency>
...
</dependencies>
...
</project>
Given that component a-b-c and g-h-i has been released with version 1.0.1 and 1.1.6 I want to replace their versions in this pom with these version numbers. Basically remove any snapshot dependencies in the pom.
EDIT
I should add that is to be an automated process with minimal human interaction. For some reason I can only get versions:update-properties to work if versions are already in release state. If I have a snapshot version 0.0.1-SNAPSHOT and want to update it to 0.0.1 it doesn't happen and I have verified the release exists. Same thing with versions:use-latest-relese, and versions:use-releases does nothing at all.
I see two approaches here:
You can create multiple profiles in your maven pom. Best way is to create a profile of "snapshot" and one for "release". Described here: Different dependencies for different build profiles in maven
You can use maven pom properties to define variables for your dependency versions. See here: http://books.sonatype.com/mvnref-book/reference/resource-filtering-sect-properties.html#resource-filtering-sect-user-defined
Hope that helps!
You can use maven properties in your pom.xml, such as:
<properties>
<c-d-f.version>1.0.1-SNAPSHOT</c-d-f.version>
<g-h-i.version>1.1.6-SNAPSHOT</g-h-i.version>
</properties>
<dependencies>
<dependency>
<groupId>a.b.c</groupId>
<artifactId>c-d-f</artifactId>
<version>${c-d-f.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>a.b.c</groupId>
<artifactId>g-h-i</artifactId>
<version>${g-h-i.version}</version>
<type>war</type>
</dependency>
...
</dependencies>
and when you want to change the versions, you can use maven-versions-plugin, with the following command, such as:
versions:update-properties -Dproperties=[${release_version}] -DincludeProperties={c-d-f.version}
EDIT:
Note that if you wanna use SNAPSHOTS, you need to add -DallowSnapshots. Read here for more options. And yes, the version needs to exist in the repo, otherwise it will fail. BTW did you use brackets, such as -Dproperties=[0.0.1]? after you read the link I sent you, you will see that this commmand's input is a range, so you must use brackets in order to specify a unique version.

locking snapshot versions when depending on multi-module project

I have a multi-module project (B) that depends on various modules of another multi-module project (A). Each module of (B) might depend on different parts of (A), but they should all use the same version of (A). Current that version is specified as a property in the parent pom of (B).
I would like be able to lock the version used to a specific build (x.y.z-ts-buildnum) from a single command while keeping the version of (B) to use listed only once.
In parent:
<dep.version>4.1.0-SNAPSHOT</dep.version>
In a module:
<dependency>
<groupId>com.example</groupId>
<artifactId>B-foo</artifactId>
<version>${dep.version}</version>
</dependency>
I tried:
versions:lock-snapshots but that does not seem to lock versions set by properties
versions:update-properties which is for updating property versions but not locking snapshots
Writing a script around resolving the latests snapshot of A's pom from the local repository, but that does not work because each module has it's own timestamp. I could write a script to look at every module, but that's getting close to the amount of work a maven plugin would do.
I would suggest to define the dependencies to your module-A in your parent of the module-b like this:
<properties>
<module-a.version>6.5.0-12-SNAPSHOT</module-b.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>A-foo</artifactId>
<version>${module-a.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>A-bar</artifactId>
<version>${module-a.version}</version>
</dependency>
...
</dependencies>
</dependencyManagement>
Within your modules you now only need to write:
<dependency>
<groupId>com.example</groupId>
<artifactId>A-bar</artifactId>
</dependency>
which will give you the possibility to change the version of all modules only within a single place. At the root of your module-A.

Resources