In my project there is a class implementing an interface. The interface comes from a dependency. I have another dependency that itself has a dependency on a jar that also contains the same interface, except a version with more methods; the two jars containing the same package-interface DON'T have the same groupId or artifactId.
Compilation is failing because the compiler complains that the class in my project is not implementing all the methods. I realized it is because the compiler is taking the interface reference from the wrong jar. My question is, why is maven using the interface from the transitive dependency instead of the one from the jar that I explicitly mention in the project POM? I can see the jar that is used appears earlier in the definition (so i imagine in the classpath as well), but i thought in these cases maven resolved it by using the colliding class/interface from the dependency with the shortest path
Here is part of the dependency tree. Note that this is grepped but it can still be seen that javax.servlet:servlet-api (the one actually used) is deeper in the tree compared to tomcat:servlet (the one that should be used)
[builder#ca-rd-build11 proj]$ mvn dependency:tree | grep servlet
[INFO] | +- javax.servlet:servlet-api:jar:2.4:compile
[INFO] +- tomcat:servlet:jar:4.0.6:compile
I'm using maven 3.0.4
why is maven using the interface from the transitive dependency
instead of the one from the jar that I explicitly mention in the
project POM?
Because, to Maven, the two have nothing to do with each other. Maven doesn't know about class or package names, Maven just knows about groupId and artifactId. Since those are not the same, maven doesn't have any reason to omit the transitive dependency.
And if I am correct, Maven places the dependencies on the classpath in the order they are defined, i.e. the transitive dependencies of dependency a appear before dependency b.
When you declare your dependency on the other jar file you can tell it to exclude the transitive dependency on the conflicting jar file:
<dependency>
<groupId>group</groupId>
<artifactId>artifact</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>othergroup</groupId>
<artifactId>ArtifactToExclude</artifactId>
</exclusion>
</exclusions>
</dependency>
For future visitors (since the title is generic):
In Maven you have two categories of dependencies:
(external) dependencies: what you define directly in your pom.xml files inside <dependencies>
transitive dependencies: the dependencies your pom.xml dependencies require (automatically included, together with their dependencies, and so on)
As per the official Maven documentation the following mediation is applied when multiple versions are encountered as dependencies:
Maven picks the "nearest definition". That is, it uses the version of the closest dependency to your project in the tree of dependencies. You can always guarantee a version by declaring it explicitly in your project's POM. Note that if two dependency versions are at the same depth in the dependency tree, the first declaration wins.
Example: if dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A -> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter. You could explicitly add a dependency to D 2.0 in A to force the use of D 2.0.
In the above example, A is the actual project, B and E are external dependencies defined in its pom.xml file, and C and D are transitive dependencies.
Related
I do not know if it is possible for maven to act in this way :
An artifact does not exist or is not accessible
Mark this artifact as optional
...I am trying to generate a dependency does not exist and mark it as optional and make a buil with Maven in Eclipse ... but it seems that it does not like ..:
<dependency>
<groupId>com.x.y</groupId>
<artifactId>myOptionalArtifact</artifactId>
<optional>true</optional>
</dependency>
..... but Maven crashes.... :
BUILD FAILURE
Could not find artifact com.x.y:myOptionalArtifact:jar:1.0
I'm starting to guess that the optional tag can NOT be used in this sense ???
Maven treats all dependencies you list in the <project><dependencies> section of your POM as required for your project to build; therefore, any failure to find one of those dependencies fails the build, and this is expected behavior.
The <optional> tag you reference is used for when your project is a dependency of another project, indicating to Maven that the optional dependency should be automatically excluded when resolving the transitive dependencies in your main project.
From https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html:
Optional dependencies - If project Y depends on project Z, the owner of project can mark project Z as an optional dependency, using the "optional" element. When project X depends on project Y, X will depend only on Y and not on Y's optional dependency Z. The owner of project X may then explicitly add a dependency on Z, at her option. (It may be helpful to think of optional dependencies as "excluded by default.")
If you really want to remove a dependency from the dependency tree, you need to figure out all transitive place where it is used and add exclusions to the respective dependencies.
Optional or provided won't help. The artifact remains on the classpath and therefore, Maven tries to load it.
I have a problem with maven. I have a huge multi-module project with limited possibilities to change the structure of it.
So, let's say I have 3 modules: A,B,C.
A is a parent of B and C.
C uses classes from B, so we have a B as a dependency in C's POM file.
B doesn't need to have a C as a dependency to be successfully compiled.
For now, there aren't any problems.
Unfortunately, B uses C during the runtime (spring, ioc, ...), so someone added C as B's dependency, so we have a horrible cycle in Maven. Build finishes with failure (something like "cycle detected" in log).
I would like to keep it this way (provide somehow C dependency in B module) as I need to compile and deliver B with all needed JAR archives (including JARs from C).
Can I somehow build C and copy its JARs to B's target directory after the full compilation of B? Is there a plugin or tool which can be used by maven to do this?
If this post is not clear, I will try to describe it in more details.
Thanks in advance ;)
It sounds like there are two issues:
How to tell Maven about a runtime-only dependency between artifacts.
How to get Maven to leverage the dependency to pull together all the relevant dependencies.
Maven has a feature of dependency management that allows you to inform maven of such nuances using the "scope" element of the dependency element. In this case, I think you want
<scope>runtime</scope>
See the documentation. In particular:
runtime - This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
Proper utilization of the runtime scope should resolve the circular dependency issue.
Regarding the second issue, you have not supplied enough information to provide a definitive answer. However, you almost certainly want to use a maven plugin in order to leverage maven's information about the dependencies. For example, if you want to produce a single "fat" jar that contains everything, you want to look at maven-shade-plugin. Another option is maven-assembly-plugin, which is extremely flexible and can include all dependencies in the assembly. There are other plugins that excel at handling various other common circumstances. You may want to formulate a separate question if you have problems with how to use a specific plugin.
Here is how I would do it. From C's pom file:
<profile>
<id>compile</id>
<dependencies>
<dependency>
use B here but do not use in the main dependencies section
</dependency>
+ other dependencies
</dependencies>
</build>
</profile>
For example you can compile C module using mvn compile -Pcompile
From B's pom file:
<profile>
<id>run</id>
<dependencies>
<dependency>
use C here but do not use in the main dependencies section
</dependency>
+ other dependencies
</dependencies>
</build>
</profile>
you run B module using mvn yourcommandforrunning -Prun
In this way you can escape the cyclic dependencies issue.
I have below dependency in my pom.xml.
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-server-client</artifactId>
<version>4.7.0-HBase-1.1</version>
</dependency>
The above is for phoenix query server interacaction
This dependency has org.apache.calcite:calcite-avatica:1.6.0 transitive dependency. The calcite-avatica dependency has jackson-databind(2.1.1) one of its transitive dependency. So jackson-databind(version: 2.1.1) dependency should be included in classpath of my project. But instead of that, all of the classes in the jackson-databind(version: 2.1.1) are included in calcite-avatica jar. I have declared jackson-databind( version: 2.7.2) as direct dependency in my pom.xml.
I can exclude the jackson-databind(2.1.1) through tag. . <
org.apache.phoenix
phoenix-server-client
4.7.0-HBase-1.1
com.fasterxml./*
jackson-databind
But it is not getting excluded since it has been bundled in calcite-avatica:1.6.0 jar. Is there any solution for that. I have tried maven shaded plugin. but in vain.
There are different approaches, none of them is perfect:
If you don't need calcite-avatica jar, exclude it (with the Maven exclude mechanism.
If you need some classes from calcite-avatica jar, but not the jackson-databind classes, alter the order in which you declare the dependencies. Because Java can load each class only once, either the classes of calcite-avatica jar hide those of jackson-databind or vice versa.
Create a "hacked" calcite-avatica jar which does not contain the doubled classes.
If you really, really need jackson-databind in two different versions, you need try to construct this with the shade plugin, but it is not easy.
Dependencies in Maven have a type element which defaults to jar, but can be set to ejb, war, ear, etc. The type ejb is a special case because it does not lead to a different file ending: The ejb has still the ending .jar.
I have an ear project where the same dependency is referenced once with type ejb and once with type jar (in the transitive dependency tree). Both entries ask for the very same file, with different Maven "coordinates".
From the perspective of the dependencyConvergence rule of the enforcer plugin, both dependencies seem to be different - the version of the <type>jar dependency is seemingly not managed by dependencyManagement. Nevertheless, only one of the dependencies makes it into the ear - namely the <type>ejb one.
When does Maven "drop" the second dependency and what can I do to influence this?
Please note: I know that you shouldn't have ejbs as jars on your dependency list, but if I kill the responsible developers, I might go to prison.
I created two sample projects in Eclipse: one EAR, one EJB.
If the order in the EAR's POM is:
<dependency>
...
<type>jar</type>
<dependency>
...
<type>ejb</type>
the ejb.jar is put to .ear's /lib only.
If the order in the EAR's POM is:
<dependency>
...
<type>ejb</type>
<dependency>
...
<type>jar</type>
the ejb.jar is put to .ear's root and /lib.
Apparently one of the rare cases where order of declaration in the POM matters.
BTW, just to make it clear: Your "the same dependency is referenced [...] with different Maven 'coordinates'" is contradicting. Maven coordinates are groupId, artifactId and version (GAV), not packaging and/or classifier, because the latter two don't specify the "Where?" but the "What?". It's probably that why you quoted "coordinates".
I have a maven project that I'd like to share with several of my other projects. It has some custom code, and then a few dependencies on things like log4j, jasypt, etc.
I build it and install it to my local maven repo. I can see it's successfully put there. Looking at .m2/repository/derp/Foo/1.0 it has a .pom with all its dependencies defined.
I can also define it as a dependency in my higher level projects, and it compiles.
<dependency>
<groupId>my.group</groupId>
<artifactId>Foo</artifactId>
<version>1.0</version>
</dependency>
I can see the Jar in my 'Maven Dependencies' in eclipse, and expanding that jar I can see it has the correct pom with dependencies in META-INF/maven/derp/Foo/pom.xml.
But my top level project above Foo isn't getting the dependencies that Foo needs. I get runtime exceptions, and I can see none of the transitive dependency jars are in my maven dependencies in eclipse.
What do I need to do to make sure Maven knows to look at the Pom for Foo in my local repo, so it will get all the transitive dependencies it needs?
----- edit -----
Answer to comment below, they are defined like this, with the dependencies tag at the top level under the project tag.
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.2</version>
</dependency>
etc...
These are the jars that maven correctly finds when I am just building and running this Foo project, but maven doesn't include these jars if a project depends on Foo, (Bar), and I find out when I try to run Bar.
What does "top level project above Foo isn't getting the dependencies" mean?
Anything "above" Foo in the build reactor should depend directly on Foo as you have stated. The <dependency/> specified will resolve to Foo's dependencies (within the scope that Foo specifies).
Without understanding the specifics of your project, it's improbable that we can to help you any further.
Some possible common situations:
You expect to be able to get access to test scoped dependencies in some non-test phase of execution. Just not true.
You expect that specifying a dependency on an artifact causes the java runtime to load those dependencies for you automagically. That's also not true. You'll want to invoke the exec:java goal on the maven exec plugin and specify your desired resolution scope within the <configuration/>, possibly also for that <execution/>.
You've mistaken <dependencyManagement> for <dependencies>. This happens way more than I would have expected.