I have a maven project depending on another maven projects. The project tree is the following:
final_project
|
|----sub_project
| |----jsf 1.2_09
|----jsf 2.0.3
How is it known what exactly jsf-library will be used in what project? I mean does it arise a conflict in such project?
UPD: Because of the different group id:
<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>1.2_09</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
and
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.0.3</version>
</dependency>
these dependencies is not overridable.
This is not so easy, see other questions:
Maven - transitive dependencies with different versions
Different versions of the same dependency in Maven
As reported earlier, for a robust result you can use the maven-shade-plugin to create a separate package for the old version, ie your.package.jsf12.jsfpackage
Just read your update. If the packages are different: no problem. If there is an overlap in package: see my note about the shade plugin
Related
I have a java spring boot application A that has dependency B which is a third party jar. B in turn has dependency C. When people need upgrade C (say from v1.0 to v2.0), a common approach is that in pom.xml of A, using Maven exclusion feature to exclude C from B, then either declare C-v2.0 as a direct dependency, or add C-v2.0 to dependencyManagement section.
This approach doesn't guarantee work in all situations. An example is org.glassfish.metro:webservices-rt:2.4.3 has dependency woodstox-core:5.1.0 which contains high security vulnerabilities and need to upgrade to 6.4.0.
My project A has (direct)dependency webservices-rt:2.4.3. Applying above approach doesn't exclude woodstox-core:5.1.0 from my project. Note: the maven dependency tree doesn't show woodstox-core:5.1.0 any more, but Aqua Scan still indicates that webservices-rt has dependency woodstox-core:5.1.0.
Below is part of my pom
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>6.4.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.metro</groupId>
<artifactId>webservices-rt</artifactId>
<version>2.4.3</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
</exclusion>
</exclusions>
</dependency>
It seems to me that whether above approach working or not depends on how jar B is packaged. Dose anyone has knowledge to share?
The much better approach is to set the desired version in <dependencyManagement>, i.e.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>6.4.0</version>
</dependency>
</dependencies)
</dependencyManagement>
Then you need no exclusions at all.
If the dependency tree does not show it, it will not be used, unless the dependency is a fat jar. So, avoid fat jars as dependencies (if at all possible), and furthermore check if your Aqua Scan maybe does it wrong.
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.
I have a project that needs a dependency on iText 5.5.2 and on iText 2.1.7 (Primefaces needs this specific version at runtime and won't work with iText 5 due to license issues).
So I have this in my pom.xml:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.2</version>
<scope>compile</scope>
</dependency>
<!-- iText 2.1.7 is necessary at runtime to have the 'Export to PDF' function of Primeface work -->
<!-- It won't conflict with iText 5 as the packages are different -->
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
<scope>runtime</scope>
</dependency>
The problem is that I don't want our developers to be able to import classes from iText 2.1.7 (com.lowagie.* package). I want to force them to use classes from iText 5.5.2 (com.itextpdf.* package).
Although iText 2.1.7 is in 'runtime' scope, Eclipse still adds the jar file in the build path, allowing developers to import the wrong package (com.lowagie instead of com.itextpdf).
Is there a way to exclude it from the build path ?
Unfortunately it seems not to be possible on Eclipse with a normal build, it is a known bug, check Bug 414645 and Bug 376616. Eclipse (m2e) can't properly manage Maven dependencies scope.
However, if you place the runtime dependencies on a profile, then Eclipse will not add them to the classpath (the profile shouldn't be active by default, though). I just tested it on Eclipse Mars and it works perfectly.
Hence, in your case you could add to your POM:
<profiles>
<profile>
<id>runtime</id>
<dependencies>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</profile>
</profiles>
As such, it can't be used to compile on Eclipse. However, your build would then need to use it at runtime, running with -Pruntime in this case.
Although adapting your POM and build to an issue of an IDE might not be ideal, it could be a good compromise to achieve your goal.
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.
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!