How to make specific maven dependency versions mandatory - java

I am working on creating a common library for my team which can be used by different micro-services of our team. Common library will be service-starter which includes : specific spring boot, spring version and other compatible versions and dependencies. Is it possible to guardrail using maven such that our whole team must be on specific MUST versions of some maven dependencies like spring boot version should be common across team (We will also have other maven dependencies which can be overridden in respective micro-service pom if needed.)

You cannot stop your team from defining their own version in their project. However, you can add a <dependencyManagement>tag in your project which will define the versions you wish them to use so they won't have to decide.
But, again, nothing to stop them to override these.

You can create a parent pom that you want and put in <dependencyManagement> the dependencies that you want to be used by applications that use this parent pom.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
so if another application uses as parent pom the one you have declared above and uses as dependency
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
</dependency>
</dependencies>
(It does not contain any specific version), it would retrieve by default the version which was delcared in parent pom of 1.0
But the child pom application would always be free to declare their own version if they want, and use that instead, effectively overriding what was declared in parent pom
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
More about Dependency management in Maven

Related

How to automatically reuse dependency versions in a multi-module Maven project?

In one module, I use spring-boot-starter-activemq:2.07.RELEASE which depends on activemq-broker:5.15.8 which depends on guava:18.0.
In another module, I would like to use guava, so I have to use:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
If I use an higher version in my pom.xml this version will be also used by activemq-broker due to the nearest definition rule of the dependency mediation (see Introduction to the Dependency Mechanism)
I don't want to provide a different version of Guava than what is asked by activemq-broker. So in order to synchronize the versions, each time there is a Spring Boot upgrade, I need to check manually the versions in order to synchronize them.
I use activemq-broker and guava as an example but my question is more general: How to automatically reuse a dependency version from one module into another?
I would define a parent for my project where dependency management will be handled.(You probably already have this). In the parents dependendency management section, I would import dependency management of activemq-parent. This way you can just define dependencies, without explicit versions in the childs.
Also you can make your parent inherit from spring-boot-dependencies to get versions properties. (In this example activemq.version is fetched from this)
Example: Parent pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-parent</artifactId>
<version>${activemq.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
.....
</dependencyManagement>
If Your parent doesn't inherit from spring-boot-dependencies, You would have to write specific version instead of ${activemq.version} for activemq-parent
After this in the child
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
Version of the guava will be same as activemq-parent. ( Because it is defined there)
In module where you are definign dependency
activemq-broker:5.15.8
also defibe and add which ever version of guava you like to use while other can inherit other versions of guava may be from grandparent pom.

Maven: Resolve dependencies using container dependencies first

I have a plugin project which is added to other container projects as a dependency.
Now, this plugin project uses many frequent dependencies like spring-security, commons-lang, etc.
Usually, the container projects contain their own versions of such frequent dependencies. So, when we add our plugin dependency there are conflicts and the dependencies are resolved based on regular maven dependency resolver and depending on scopes and optional tags provided in the plugin project dependencies.
Is there a way where all the dependencies are resolved using the version in parent dependencies first and iff they are not available then use the version specified in plugin dependency.
Note: optional and scope runtime have a problem that these dependencies are provided by the container and thus beats the aim to provide a hassle-free single dependency to add plugin dependency.
In your plugins pom define the version of a dependency as range of the versions you know the plugin to be able to use. If a container-dependency overlaps this will be used. If no overlapping version, of the dependency both container and plugin need, can be found, an error will be produced, since the negotiation failed.
Use no special scope for the dependencies, since you want them to be included if necessary into the container,
See:
https://maven.apache.org/enforcer/enforcer-rules/versionRanges.html
And:
https://books.sonatype.com/mvnref-book/reference/pom-relationships-sect-project-dependencies.html#pom-relationships-sect-version-ranges
Assuming that your container and plugin projects use the same parent pom you could utilize the <dependencyManagement> section in the parent to define the common artifacts. This allows you to omit the version in the plugins <dependencies> section.
parent:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
plugin/module:
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
</dependency>
</dependencies>
See https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html for further details.
you can exclude it when you build a plugin project and add a dependency to maven.
This is an example. Dependency and main project have conflicted due to logging library. Below is to exclude log4j in dependency project.
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zk.version}</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
P/S: Added from my comments:
I have also developed a system which has a similar architecture with yours. I separate this system into 3 main parts: 1. Commons which contains common code and required maven dependencies, 2. The main project, 3. plugin project. You can refer this.

Sharing src/test classes with Maven without version specification for test-jar

I'm sharing src/test classes between number of modules, in a similar way described in attaching tests guide and the following question.
So, I have the following pom.xml dependencies:
<dependency>
<groupId>com.myco.app</groupId>
<artifactId>foo</artifactId>
</dependency>
<dependency>
<groupId>com.myco.app</groupId>
<artifactId>foo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
BUT, in opposite to the question above, when attaching the test-jar, i don't want to specify the specific test-jar version. As in the compile level dependency:
<dependency>
<groupId>com.myco.app</groupId>
<artifactId>foo</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
In this case, my pom.xml become erroneous with message about the missing version. Why is this happen? Why i can specify dependency without versions but not the test-jar one? Is there a way to overcome this and make the test-jar to use the latest jar it can find?
The reason the main code dependency could be used without the version, is the existence of a "main pom" in our project that automatically generates appropriate version for each dependency in section. Therefore, each dependency can be specified without specific version number.
Test-jar dependency on the other hand, don't have it's version defined anywhere else in the transitive dependency so, the specific version must be specified.

download compatible dependency in maven

Supppose I use spring 4.0 in my pom file and I want to use junit. In that case how can I declare the junit dependency to download the which compatible with the given spring version with out specify any specific junit version. This can be any dependency where I take junit as a example.
In Maven there are two possible matching things. First the dependency management of the artefact itself. spring-core:4.2.0 defines that it depends on commons-codec:1:10. So there is nothing to do for you when you want to also use commons-codec since its already in your classpath. It did not define JUnit so it did not depend on it and should be compatible with all versions.
The second thing is aBOM pom. This is used to package a lot of dependencies together and let the user select the once he needs but the bom defines the versions for you already (and so they should be compatible). Especially spring has some of this bom poms in the repo.
For example spring-framework-bom which packaged everything related to spring which you could use in your app but you will define which parts you need and do not bothering yourself with the version numbers of the sub dependencies.
For example I want to use spring 4.2 and need webmvc the jdbc stuff and something for spring tests. So will define this:
<dependencymanagement>
<dependencies>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-framework-bom</artifactid>
<type>pom</type>
<version>4.2.0.RELEASE</version>
<scope>import</scope>
</dependency>
<dependencies>
</dependencymanagement>
<dependencies>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-webmvc</artifactid>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-jdbc</artifactid>
</dependency>
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-test</artifactid>
<scope>test</scope>
</dependency>
</dependencies>
This question doesn't really make sense. If spring 4.0 depends on JUnit (you don't say which spring module you're referring to), JUnit (or any other dependency) will automatically be included in your dependencies, since it will be inherited from the spring 4.0 dependency you have already declared, and the version will match whatever version the Spring module declares in its POM.
However, it seems likely that your particular Spring 4.0 dependency does not depend on JUnit, so in which case you may just pick which ever version is suitable for your requirements.
You can view the dependencies which are currently included in your project (explicit and inherited) by running the following command:
mvn dependency:list
This will trace down the dependency tree and show you all the dependencies which are currently included in your project.

maven dependency without version

Recently I've been working on some improvements in a project developed some time ago, and here's what I found. A lot of dependencies in the pom files go without versions specified, and yet they are resolved. The project consists of 1 root module and 2 submodules. The Aggregator pattern is used, meaning there's no dependencyManagement section at all. The upper-project simply aggregates 2 modules and that's all it does. Subprojects don't refer to it as to a parent. They have a different parent. What I can't grasp is that neither subprojects themselves nor their parent(as a matter of fact, it doesn't have dependencyManagement either) specify versions for some of the dependencies. For instance:
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>imap</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
Can someone help me figure this out? Is maven handling versioning with some default strategy? What is that default strategy?
Ok, I think I'm gonna answer it myself. Of course I took a look at dependency:tree, but all the dependencies that I mentioned were first-level members of the tree. What I failed to notice right away, is that dependencyManagement is not present in the parent, but it is however present in the submodules, and what is more interesting it contains:
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>1.0.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
I've never used Spring IO Platform before, so this is a totally new concept for me. As it turns out the platform includes quite a few preconfigured dependencies:
http://docs.spring.io/platform/docs/current/reference/htmlsingle/#appendix-dependency-versions
It is impossible for maven to work without defining versions of the artifacts. They should be defined somewhere in dependencyManagement tag either in the submodule or parent. Please check your pom hierarchy. Use mvn help:effective-pom in the submodule directory of the project. Also you can use mvn dependency:tree in order to find out which artifacts - along with full artifact information including version numbers - are resolved in the result of dependency management.
Use
mvn -P<my_profile_of_interest> help:effective-pom -Dverbose
Verbose mode (Since: 3.2.0) adds XML comments containing precise reference to a place where dependency declaration is coming from.
Each maven dependency defined in the pom must have a version either directly or indirectly for example, through dependencyManagement or parent. That being said, if the version is not given, then the version provided in the dependencyManagement or the parent pom will be used.
For example: in the pom (only important sections are mentioned) given below, no version is provided for the artifact jstl. However, in the "mvn dependency:tree", it shows that jstl version 1.2 is included. And looking at the spring-boot-starter-parent, for the version 2.3.3.RELEASE pom, it includes jstl version 1.2.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
<dependencies>
....
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
....
</dependencies>
In my case if i was using Spring boot starter parent to manage all dependency and lombok version is managed by Spring boot , This problem was coming due to higher java version JAVA 11 . I exported JAVA 8 in to my compile time environment and after using JAVA 8 this problem was gone.

Categories

Resources