maven dependency without version - java

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.

Related

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.

Why version number in maven dependency is skipped at times?

I am fairly new to maven's capabilities..
I have seen that in pom.xml where dependencies are put, at times, only groupID and artifact id are mentioned and version is skipped. why is this?
For example the below dependency is from springsource website http://spring.io/guides/gs/authenticating-ldap/
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-server-jndi</artifactId>
<version>1.5.5</version>
</dependency>
</dependencies>
But elsewhere in stackoverflow it was also mentioned that version is not optional. I would be glad if someone could explain this.
Yes, version is not optional.
Consider a multimodule application which has 10 modules, say module1, module2.. module10.Assume that all of these 10 projects use the spring-boot-starter-web. In case these 10 modules are interdependent, you might want to use the same version of the spring-boot-starter-web in each of these 10.
Now just imagine how complicated it would be if you were to maintain the same version number in all of these 10 pom files and then update all of them when you want to use a newer version of spring-boot-starter-web. Wouldn't it be better if this information can be managed centrally?
Maven has got something known a <dependencyManagement/> tag to get around this and centralize dependency information.
For the example which you have provided, below set of links will help you understand how the version number is resolved even though it's not present in the pom which you are looking at.
Look at the parent tag of the pom you are looking at (https://github.com/spring-guides/gs-authenticating-ldap/blob/master/complete/pom.xml)
Now lets go to that parent and see if the versions are specified in the dependencyManagement section of that pom(https://github.com/spring-projects/spring-boot/blob/master/spring-boot-starters/spring-boot-starter-parent/pom.xml). No it's not defined there as well. Now lets look at the parent of parent. https://github.com/spring-projects/spring-boot/blob/master/spring-boot-dependencies/pom.xml. Oh yea, we have got the version numbers there.
Similar to dependencyManagement, plugins can be managed in the pluginManagement section of the pom.
Hope that explains it.
Refer : dependencyManagement, pluginManagement
A few additions to the excellent answer by coderplus:
In a multi-module project, it is considered to be a good practice to configure the artifacts used by the project in the dependencyManagement of the root pom.xml so that you don't have to write versions in child module pom.xmls (like in some dependencies in your example).
It is also considered to be a good practice to declare versions of the external libraries that you use as properties and then use these properties in dependencyManagement/dependencies/dependency/version. This is more or less done here:
<properties>
<logback.version>1.1.2</logback.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
In a multi-module project, you should also declare your own artifacts in dependencyManagement.
But please do not write the version explicitly (like Spring people do here), use ${project.version} instead.
So it would have been better to write:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${project.version}</version>
</dependency>
instead of
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>1.2.0.BUILD-SNAPSHOT</version>
</dependency>
here.
The whole purpose is DRY, don't repeat yourself. The more redundant declarations you have in your POMs, the harder they can hit. Hunting for the obsolete dependencies is so much fun.
If the <version> isn't specified then the <version> of <parent> is used. If there is no <version> in the <parent> then the <version> in the <parent> of the <parent> is used. etc.

Maven transitive dependecy breaks build

I have a following problem - I am trying to use apache commons-lang version 2.6 in my project (which is defined in the pom.xml) but due to transitive dependency maven always add version 3.2.1 which breaks my build.
Here is relevant part of pom.xml
<properties>
<commons-lang.version>2.6</commons-lang.version>
</properties>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang.version}</version>
</dependency>
and when I try to run mvn dependency:tree I can see the reason is transitive dependency of
+- org.seleniumhq.selenium:selenium-api:jar:2.26.0:compile (version managed from 2.26.0)
+- net.sourceforge.htmlunit:htmlunit:jar:2.10:compile
+- org.apache.commons:commons-lang3:jar:3.1:compile
So I can see the problem but I have really no idea how to fix it. Thanks for any suggestions:-)
Look into using an exclusion tag inside the dependency that's causing the problem. An exclusion tag tells maven that you don't want maven to bring in an indirect dependency and is used in just this situation.
For example, if one of my dependencies A brings in a version 1.0 of B but I want to use version 2.0 of B instead, I could do this:
<dependency>
<groupId>org.mycorp</groupId>
<artifactID>A</artifactID>
<version>4.0</version>
<exclusions>
<exclusion>
<groupId>org.mycorp</groupId>
<artifactId>B</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mycorp</groupId>
<artifactID>B</artifactID>
<version>2.0</version>
</dependency>
The exclusion tag says to not bring in the indirect dependency (B 1.0) in this case. Note that you don't have to give the version. Once you've told maven not to automatically bring in that version of B, you follow with an explicit dependency that defines which version of B (version 2.0, in this case) you do want.
This particular dependency should not break your build, because Commons Lang 3 uses different package naming than Lang 2. Your code should use the classes from Lang2, while HTMLUnit will use the classes from Lang3, and both JARs can co-exist.
Perhaps you should describe how you think this breaks your build, with relevant extracts from the build output.
My collegue forgot to declare version in dependencyManagement in parent pom so that was it. Thank you for your suggestions!

Maven error when resolving dependency

I am new to Maven and am trying to set up one of my first POMs. My application will cache using EhCache. Going to Maven Central Repo (link here) I copy-n-pasted the <dependency> tag and copy it into my pom.xml like so:
...many dependencies above this point
<dependency>
<scope>compile</scope>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.0.1.Final</version>
</dependency>
<dependency>
<scope>compile</scope>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<scope>compile</scope>
<groupId>jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>3.5.3</version>
</dependency>
...many dependencies below this point
When I save the changes, Eclipse builds the workspace and gives me an error on the opening <dependency> tag for EhCache 2.5:
Missing artifact net.sf.ehcache:ehcache:jar:2.5.0
So I figured that perhaps v.2.5.0 has something wrong with it, and repeated the same for 2.4.7 (the last 2.4.x release before 2.5.0). Same deal.
Since I'm so new to Maven, I don't even know where to begin looking. I tried Project >> Clean and even restarted Eclipse to see if it was just a typical Eclipse "quirk". Nope.
I am thinking:
Could EhCache be publishing bad JARs to the Maven repo?
Could Maven Repo have something wrong with it?
Could this be due to something else configured wrong in my pom.xml?
Could this be a "JAR hell" issue where I have a conflict somewhere on my dependency graph?
How would SO start tackling this problem? Thanks in advance!
It is usually safer to refer to search.maven.org. Dependency from there:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.5.0</version>
<type>pom</type>
</dependency>
Mind type pom. From module's pom:
This is a pom artifact to pull in ehcache-core and ehcache-terracotta
for clustering. Make sure to set 'type' to 'pom' in your dependency.
Aparently when someone does not need terracotta, ehcache-core will do perfectly fine as other answer states.
They use ehcache-core in the official documentation. Maven Central does not have a jar artifact for ehcache 2.5 which explains your error message.
Using ehcache-core changes the dependency to:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.5.0</version>
</dependency>
Which successfully downloads on my machine (ehcache does not).
I dropped this into IntelliJ and it found it. I suspect there is something wrong with your settings. Try creating a project with only this dependency in it. If it fails to download, I would check your setting. e.g. .m2/settings.xml Are you using a Nexus server or maven proxy/cache?
BTW: A simpler way to search for JARs is to use http://mvnrepository.com/ which will find all the available versions and show you the XML you need to add.

Categories

Resources