How to use different version dependencies for each JAR - java

I have a maven project A that uses some Java library B, which is dependency stated in POM. That library uses some other library C that uses library D. The problem arises in compiling where both A and C are using that library D but different versions. It looks like this:
A ----- B
| |
D(v1) C
|
D(v2)
A can not change its dependency to D(v2), but also if I exclude D(v2) in A's POM:
<dependency>
<groupId>...</groupId>
<artifactId> C </artifactId>
<exclusions>
<exclusion>
<groupId>...</groupId>
<artifactId> D </artifactId>
<version> v2 </version>
</exclusion>
</exclusions>
</dependency>
I will get compilation error that some class MissingClass is not resolved in class C. The most annoying thing is that only D(v2) has that Missing Class.
I am not somewhat skilled with Maven so is there some way to make Maven is using D(v1) dependency in A's case, and D(v2) in B's case?

This is more a problem of Java classpath.
Could your scenario work if you run things via cmd line, without Maven? (i.e. run your app, and manually specify your classpath).
If the answer is yes, then you probably can do it in Maven; but my understanding from your description is that no, you couldn't run via cmd line.

Related

How maven dependency exclusion works for this scenarios

I am having a hard time understanding maven dependency management and how dependency exclusion works. What I know is that when some object of class A send messages (invokes method of) to another object of another class B, then class A is coupled to class B (class A needs class B to exist).
I am using Maven in the project and have this dependency in pom:
<dependencies>
<dependency>
<groupId>org.libraries</groupId>
<artifactId>library-A</artifactId>
</dependency>
</dependencies>
Now assuming class A is from library-A, and it depends on class B in library-B, but I dont use the class A in my project (I use another class of library-A not coupled to any class of library-B). Maven will download and install in local repository the dependency even if not used in my project?
Now assuming a different scenario I use class A from library-A in my project, which depends in class-B of library B, but I exclude the dependency of library-B in the pom:
<dependencies>
<dependency>
<groupId>org.libraries</groupId>
<artifactId>library-A</artifactId>
<exclusions>
<exclusion>
<groupId>org.libraries</groupId>
<artifactId>library-B</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
As I dont have any other dependency in pom that depends on library-B, would the project compile but the execution of the program fails during class loading because the class is not found?
Now assuming I will use class A from library-A in my project, which depends in class-B of library B, but I exclude the dependency of library-B in the pom, though I have a dependency of library-C that depends (like library-A) on library-B:
<dependencies>
<dependency>
<groupId>org.libraries</groupId>
<artifactId>library-A</artifactId>
<exclusions>
<exclusion>
<groupId>org.libraries</groupId>
<artifactId>library-B</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.libraries</groupId>
<artifactId>library-C</artifactId>
</dependency>
</dependencies>
Now though I exclude the transitive dependency library-A has on library-B, **will the project compile and execute fine and the class A in library-A would use library-B because the transitive dependency library-C has on library-B (assuming this library-B version is compatible with library-A)?
Last question is, when I exclude a dependency library-A has on library-B and use dependency:tree -Dverbose to see the dependency graph, it wont show in the graph library-A has a library-B dependency, although it could be really using that dependency that comes transitively because another dependency am I wrong? If I am not wrong, how I can know that library-A is using actually that dependency or no?
Let me try to answer you questions more generally:
Maven will not analyse which classes you use (or don't use). It just determines the tree of transitive dependencies.
In the end, Maven creates a classpath. The classpath is flat and it does not matter from which side a given dependency came.
Missing transitive dependencies can cause problems both during compile time and runtime. The former problems are rare, but if e.g. the transitive dependency is used as a super class or in the interface this may occur.

Maven: Project A not respecting Project B's exclusion

I have two projects A, and B.
Project A depends on Project B. Project B depends on a library C which depends on a library D.
I own both A and B but they live in separate code bases and are independent. Project B is like an internal common helper library.
- A
-- B
--- C (version 1.1)
---- D (version 1.1)
I want to upgrade D to a newer minor version, let's say 1.5.
So in B's pom.xml file, I imported D (v1.5) directly. Then excluded D from C. Example:
<dependency>
<groupId>D</groupId>
<artifactId>foobar</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>C</groupId>
<artifactId>fizzbuzz</artifactId>
<version>1.1</version>
<exclusions>
<exclusion>
<groupId>D</groupId>
<artifactId>foobar</artifactId>
</exclusion>
</exclusions>
</dependency>
Next if I run
[~/projectB] $ mvn dependency:tree
I confirm that only 1.5 is used, not 1.1. Next I build a new local snapshot of B. And specify Project A to use that one.
My problem is when I build Project A, it continues to use v1.1 and ignores the exclusion in B.
This always returns 1.1 instead of the 1.5 that I want.
[~/projectA] $ mvn dependency:tree
Project A never imports C or D directly, it only get library D from importing Project B.
I've tried:
Reloading the maven imports
Running mvn clean install numerous times.
Deleting the folders from my .m2/ directory to force reimports
I'm out of troubleshooting ideas. Does anyone else have any tips?

Can I overwrite a maven dependency version through my local repository?

I have a bit of a dependency hell situation here that I'm trying to resolve: I have three projects, A, B and C. A and B both depend on C. Now A is my own module that I have direct control over, B is a library I'm using, C is a library that is used both directly from my module A and by my dependency B.
To visualize this:
C
^
/ B
| ^
\ /
A
For various reasons I now needed to make a small change to C that I need locally but don't want to (or can't) deploy to the global repository from which C is downloaded normally.
I tried to do this by tagging my modified version of C installed in my local repository with a classifier and changing the dependency to it in A's POM to include the classifier like this:
<dependency>
<groupId>foo</groupId>
<artifactId>C</artifactId>
<version>0.7.16</version>
<classifier>myclassifier</classifier>
</dependency>
But mvn dependency:tree now shows that I have both the version with the classifier and the version without it in my classpath because of the transitive dependency:
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) # A ---
[INFO] org.example:A:jar:0.1-SNAPSHOT
...
[INFO] +- foo:C:jar:myclassifier:0.7.16:compile
[INFO] +- bar:B:jar:3.2.5:compile
[INFO] | +- foo:C:jar:0.7.16:compile
Is there any way I can force my project / maven to just use my modified version in this context?
Edit: Solution
For now, I've solved it using exclusions like this in A's pom.xml thanks to the answers by Filipe and Samuel.
<dependency>
<groupId>foo</groupId>
<artifactId>C</artifactId>
<version>0.7.16</version>
<classifier>myclassifier</classifier>
</dependency>
<dependency>
<groupId>bar</groupId>
<artifactId>B</artifactId>
<version>3.2.5</version>
<exclusions>
<exclusion>
<groupId>foo</groupId>
<artifactId>C</artifactId>
</exclusion>
<exclusions>
</dependency>
Note: This of course only works as long as the edits in C are really minor and don't change the API used by B, which for me is the case.
You're saying that C is the official version of the library and that your minor change (Let's call it C2) would only be used by A. You're also saying that by declaring in A the direct dependency on C2, than it's unfortunately expected that you end up with C2 and C. C will be a transitive dependency from B. Unfortunately too, the Maven reactor treats libraries with the same version but with a different classifier as different libraries, giving you exactly this result (of having both C and C2).
If you only need C2 in project A, you could explicitly add exclusions to C into A's POM.
Obviously this new version of C is for you not a new artifact, but a new version of this artifact.
So you should not use here a classifier but a version number increase instead.
Your project will be built with the last version (and even if you have a problem to resolve the last version, you can exclude the transitive dependency in your pom)
However, you must be very carefull when doing this, because your B project will have been compiled with the old version of C. So if you modify method erasure, or remove methods or classes, you will have runtime trouble.
If you only add classes or methods in your C library, then it should work.

How do I get depend on all artifacts from a group of a version from maven?

I'm new to Maven and I'm trying to build a project for the first time. I want to write some code that depends on apache lucene. Here's a list of artifacts in maven that I'm trying to get.
Is there any way instead of explicitly listing each artifact, I could simply depend on all artifacts of a given version? I tried this:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>*</artifactId>
<version>3.6.1</version>
</dependency>
which gave me the error
'dependencies.dependency.artifactId' for org.apache.lucene::jar with value '' does not match a valid id pattern. # line 19, column 19
I can verify that I can download dependencies when I explicitly state them. IE this works fine:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>3.6.1</version>
</dependency>
I realize depending on everything in lucene is probably sub-optimal, but for doing something quick-and-dirty I'd hate to have to manually populate all these little lucene libraries. What is the typical practice for getting a large set of related dependencies in maven?
Short answer: you can't. Remember you just do this once and later you can simply copy-paste dependencies (not very DRY though). Also consider creating an archetype that will quickly create a skeleton with all required dependencies (for quick and dirty projects).
Longer answer: well, you can work around that. Create a separate pom.xml with:
<packaging>pom</packaging>
and declare all Lucene dependencies there manually, one after another. Once and for all. Later you can simply add a dependency to your pom.xml (that is to groupId/artifactId/version defined there) which will transitively include all dependencies of that pom.xml.
Talking about transitivity: if you depend on a JAR in maven and that JAR has other dependencies, you get that transitive dependencies implicitly. Examine Lucene poms, maybe it's enough to import few of them and rely on transitive dependencies?
Inside a single dependency for a groupId add different artifactId's
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<artifactId>spring-context</artifactId>
<artifactId>spring-beans</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>

How to handle sub projects dependencies in Maven

My project is made of 5 sub projects. One is a War, and the other 4 are jars. Basically the war project needs all 4 jar projects, and their dependencies.
I can strip down the dependencies to have something like war->A->B->C->D. Every sub project add their share of external dependencies (spring, struts, hibernate) so that in the end the war gets everything needed to run.
This looks pretty well organised and square, but then I ask myself if this is very practical to make changes.
Imagine I have to change one line of code in project D, without changing anything to its Maven dependencies. I would have to re-release project D obviously, but then I have to re-release projects C, B, A, and the war just to reflect this change in their pom files. This can be long and annoying, especially if you have to quickly release a new version to fix something in production.
I could make the war depend on all 4 projects, so then I just have to change project D version number in the war pom file. But then I have project A depending indirectly on project D 1.0 and the war specifying project D 1.1. I think that the war direct dependency would win in that case wouldn't it ?
This would make the new war release quicker, but it would also mess my sub projects dependencies, as they would be outdated.
What would be an acceptable way to handle this situation ?
There is no simple answer to your problem.
If you indeed do have a chain of transitive dependencies (A->B->C->D), then releasing each modules up the chain independently is not a bad option. Although it is tedious, there is a good chance your nested dependencies are simple lib jars and will not see changes too often. Hopefully you will not be forced to go through that process frequently. Pretend it would be the same situation as if log4j was updated and all of your modules needed to be updated as well.
Another thing to consider is your WAR's dependencies. Yes, Maven will pull dependencies in automatically for you but it is often a good practice to declare your known dependencies explicitly so you can specify a version number yourself for each module. This would mean A depends on D and the others directly. Unfortunately, if you have conflicting version numbers, as you've described, then you are looking for trouble on your classpath. If you really need to do this though, maven does allow you exclude transitive dependencies explicitly:
<project>
...
<dependencies>
<dependency>
<groupId>my.project</groupId>
<artifactId>module-B</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>my.project</groupId>
<artifactId>module-C</artifactId>
</exclusion>
<exclusion>
<groupId>my.project</groupId>
<artifactId>module-D</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>my.project</groupId>
<artifactId>module-C</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>my.project</groupId>
<artifactId>module-D</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>my.project</groupId>
<artifactId>module-D</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
...
</project>
Here is the documentation describing these optional dependencies and exclusions.
Do you actually need to release B, C, and D independently? If not, consider using an Aggregator pom.xml file at the root of your modules. This will allow you to use SNAPSHOT versions throughout your modules and then release the bunch at once. This is the way our team manages our multi-module project. Using SNAPSHOT dependencies ensures you use the version that was JUST built when those artifacts are needed.
Do you actually release any of projects A to D independently, without the WAR? If not, I don't see any problems with your current setup. You should absolutely use the same version of any module throughout the project. Otherwise you open the door to classloader hell - believe me, you don't want to get there :-(
To make releases easier, the maven-release-plugin may help you.
The best answer these days is now use gradle which is best of ant and maven. I never really liked maven but gradle took alot of the common concepts but made it more like ant in that it is flexible so that there is no an easy answer to your question in gradle ;).

Categories