Optional Dependency for Maven when artifact does no exist - java

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.

Related

Get all 3rd Party dependencies module is using in Maven

We have a multi-module maven project. I have a use case where I want to know to get a list of all the dependencies which is being used in code with version:
If its declared in pom and being used.
Not declared in pom but still being used (transitively imported).
Bonus would be if the approach can exclude the deps which are being declared in pom but not being used in the code.
Please suggest the best way to achieve this. TIA.
Just use the mvn dependency:tree command.
There's the Maven Dependency Plugin:
The dependency plugin provides the capability to manipulate artifacts. It can copy and/or unpack artifacts from local or remote repositories to a specified location.
with its tree goal:
Displays the dependency tree for this project.
Regarding your bonus there's the analyze goal:
analyzes the dependencies of this project and determines which are: used and declared; used and undeclared; unused and declared.
and the analyze-only goal:
is the same as analyze, but is meant to be bound in a pom. It does not fork the build and execute test-compile.

How to apply both import and provided scope to maven dependency?

I have a java maven project X which depends on project Y built by other team. That team provide us with new versions of y.jar. We wanted to dynamically load y.jar.
So, we provided path to y.jar in our project X and project X loads y.jar from that path whenever new version is available. We have specified dependency of project Y in project X's pom with provided scope (so that y.jar wont get bundled inside x.jar).
But then this does not include dependencies specified in project Y in project X. And during run time, we get NoClassDefFoundError error for those classes included in Y's dependencies.
How can I include project Y's dependencies in project X? Usually we import dependencies of other pom with import scope. But I have already specified project Y with provided scope. (Note that x.jar is fat jar and contains all dependencies specified in X's pom.)
What could be best approach to manage dependencies in this scenario. Should y.jar be fat jar?
If your scope for Y is marked as provided then yes Y should be on the classpath and be a fat jar especially if the POM is available and has its dependencies listed. If you are still getting NOCLASSDEFFOUND, I would explore the y.jar - I would assume its POM is faulty ie declaring dependencies not included in the jar. If Y is not a fat jar or its POM is faulty then you need to explicitly exclude its dependencies and then add them as a compile time dependency. Possibly shading them in. You can use exclusion statements under dependencies.
Read about that here
https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html
Personally, I hate relying on derived dependencies and usually explicitly declare them in my POM. If they are provided by Y then I would scope them as provided, otherwise scope as compile and ensure they are shaded into my jar.

Transfer a Maven dependency + all transitive + parent POM

My project stores its dependencies in a Maven repository. I would like to be able to move certain dependencies to another Maven repository. The move is the easy part. But it's what to move that is difficult for me to get right.
In order for build tools such as Maven or Gradle to be able to use the moved dependency in a build, I need to also transfer (1) transitive dependencies (recursively) and (2) the project's parent POM file, performing (1) again on the parent until all nodes in the dependency graph are exhausted.
This seems like a very common usecase and I'm hedging my bets on the fact it has been implemented many times over.
Question: Are there common libraries that implement this functionality out-of-the-box?
If not, I'll probably have to implement a custom POM parser. Are my assumptions above about what needs to move correct?
The copy-dependencies goal of the maven-dependency-plugin may help you on this task:
Goal that copies the project dependencies from the repository to a defined location.
It also provides an option, addParentPoms to also copy the parent poms required by the build (hence, the whole hierarchy). This option is not enabled by default though.
Moreover, via the different include/exclude options (by group Id, by artifact Id and so on) you may filter what you actually need to move.
Via its excludeTransitive option you may also check whether transitive dependencies are required or not: by default is set to false, hence transitive dependencies will be copied too.
Via its outputDirectory option you can specify where to copy dependencies, transitive dependencies and hierarchy of pom files, according to any specified filter.
You may also be interested in the combination of the purge-local-repository goal of the maven-dependency-plugin, to delete from your local repository whatever required by the project (including transitive dependencies, hierarchy of pom, plugin dependencies) and the go-offline goal to prepare the project for off-line mode, that is, to resolve (download) whatever required. Again, both goals provide include/exclude mechanisms and transitive dependencies management so that you may refine your strategy and outcome.
mvn dependency:list will give you list of all dependencies of your project, including transitive dependencies and dependencies specified in your parent pom.

Maven - installed to local repo, not getting transitive dependencies

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.

Maven dependency order

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.

Categories