Multiple Maven modules with dependency on a JAR - maven

In my multi-module Maven project, suppose I have two modules, car and horse. They both depend on a JAR file, transport.jar, a file not available in any online Maven repositories. As such, I need to find a way to make these modules depend on a file found somewhere in the project folder structure.
From what I understand, the default Maven solution would be to manually register the JAR file in the local repository. While this would work on a development machine, it breaks on the build server, which clears its local repository before each build.
I've been searching online on how to do this on and off for a while and found some helpful things, but nothing that completely works.
For instance, a common answer is to add a dependency to the file using <scope>system</scope>. However, not only do others claim that it's extremely bad practice to do so, it also doesn't work on the build server. (On a side note, I would also like to point out that using absolute paths to the JAR is also out of the question due to, again, it being built on several different machines.)
A more useful method I found was to define a local repository in the POM file, pointing towards the path file:${project.basedir}/lib. (Such as in this article) Unfortunately, if I place the JAR and repository definition in the car POM, I cannot successfully add a dependency to the JAR in horse. I've tried both with and without an additional reference to car in horse, as well as defining a second repository in horse, pointing to file:${project.basedir}/../car/lib. This problem would also remain if I tried to make a third module, transport-lib, specifically for wrapping the JAR dependency.
I could most likely add the JAR file to both modules and define two separate module-local repositories, but I really don't want to unless I have to due to the need to keep the two (often updated) JARs in sync etc.
So, my question is as follows: Can someone give me a confirmed-to-work method to have two modules depend on the same JAR file inside the project, given the parameters and restrictions mentioned?

Best solution is to use a repository manager like Archiva, Artifactory or Nexus and install that artifact into the repository manager. Afterwards you can use this artifact directly in your pom files without any issue.
Don't use the scope system, cause it will cause other problem after a release for other etc.

Related

Maven module dependency source instead of repository jars

I have a multi-module project, i.e.
parent
module1
module2
In one dev cycle, I added a class mod1.A to module1. Class mod2.B in module2 depends on it.
I do not have the artifacts in my local .m2/repository. Running this:
$ cd prj/module2
$ mvn -o exec:java -Dexec.mainClass=mod2.B
results in an error along the lines of:
The following artifacts could not be resolved: com.example:module1:jar:1.0-SNAPSHOT
After I install the artifacts via mvn install while in the prj folder, it all works as expected.
However, this presents an issue in at least two ways:
I have to go through the slower install phase instead of the faster compile phase
I have two versions of the same project and conflicting modifications in these. I cannot run the same Java class with their respective modifications, only the currently installed modifications, considering they are both the same SNAPSHOT version
There are workaround for both (skip parts of the build for the first, different snapshot versions for the second), but they are far from usable in practice.
Is there a way to make maven use the local modules, instead of using artifacts from local maven repository?
If I understand your question correctly, it seems like you are living a bit outside the norm here: you have two local "copies" of the project with different modifications, that you want to work with alternately when running "exec:java". And Maven is getting in your way: it expects your local .m2 repository area to be in play, but the version strings in each copy are the same, so you end up with the changes interfering among the copies.
To me, it sounds like what you are trying to do is to test your changes. I suggest you just write an actual JUnit or TestNG test in module2 that tests what you want (it can just call mod2.B Main if you want). Then, from your chosen project directory, you can run mvn test -Dtest=MyTestName. It won't "install" anything and it will find the dependencies the way you want it to.
Otherwise, I can see three options.
Change the version string locally in one of the copies (mvn versions:set -DnewVersion=B-SNAPSHOT can do this for you). That way any "installed" jars from your work on that copy will not be considered by the other copy, and vice-versa. You refer to this as being "far from usable" ... I think it should be fine? These are different versions of the project! They should have different version strings! I strongly recommend this option out of the three. (You can do mvn versions:revert when done if you used :set, or you can rely on version control to undo the change.)
Select a different local repository used by Maven when working on one of the projects, with a command-line flag as per https://stackoverflow.com/a/7071791/58549. I don't really think this is a good solution, since you would have to be very careful about using the right flags every time with both projects. Also you'd end up having to re-download Maven plugins and any other dependencies into your new local repository anyway, which is kind of a waste of time.
Try to avoid using any local repository at all. You seem to be trying to make this option work. I don't think this is a great approach either; you're fighting against Maven's expectations, and it limits your flexibility a lot. Maven will indeed find dependencies from the "reactor" (i.e., the executing mvn process) first, but this means all of the required modules must be available in the reactor to be found, which means you can only run mvn at the top level. So if instead you want to just do "mvn exec:java" inside a single module, mvn needs to find that module's dependencies somewhere ... and that's what the local repo is generally used for.
If you're dead set on going with option 3 (instead of option 1), then I suggest you follow the comments on your question and create a profile that runs your exec selectively against module2 and binds it to a lifecycle phase. But this is in practice very close to just wrapping it with a test.
For IntelliJ users:
I solved this problem using IntelliJ's Run configuration. It has the options Resolve workspace artifacts and Add before launch task -> Build. See this picture for clarification:
Run configuration example
The whole point of modules in Maven is to create decoupling between them. You either build each module independently, so that you can work on one module without touching the other, or include both modules as sub-modules in the parent pom and build the parent, which will resolve dependencies between its sub-modules and trigger their builds.
It looks like you have two options here:
Review the structure of your project. Do you really need to split it into two separate modules, if you change code in both of them simultaneously?
Import the project into a Maven-aware IDE (IntelliJ IDEA is very good at working with Maven), and let the IDE handle the compilation. Once finished and stabilized the code-base, build normally with Maven.

Determine Maven provided dependencies

I've inherited a few maven projects which have added a /dependencies directory to capture Java jar libraries that aren't part of the project war and must be installed by a DevOps into a Tomcat installation.
The libraries in this directory seem to fall into four categories:
"provided" scope libraries,
downstream dependencies of those provided libraries, and
discoverable implementations of api jars
"mystery" libraries, i.e., not available in an external repository, and maybe unsure where they ever came from.
Is there a strategy to get Maven to help manage these dependencies and perhaps fetch them for external install?
There are probably several strategies to choose from.
Number one: leave it as it is. If it works and the build is reproducible (on different environments) that seems one valid solution.
The "mystery" part of the build might not be more of an issue for new people working with it.
I think it is valid to create an own maven module to be delivered to the infrastructure team. This module can contain the jars in the /dependencies folder.
What you would need to do is create a pom.xml and add all dependencies currently in that directory (of course not the transitive ones). The magic ones would need to go in a repository proxy (nexus, artifactory, ...). If you don't have a maven repository yet: you want one! (its easy to setup and it does help a lot!)
I would then use the assembly plugin or some ant task to build the zip do be delivered. So the infrastructure team is able to just unzip / copy the files where they need to be. This step can then even be scripted (so the upload / unzip is done through SSH or something like that).
This is probably only one way to do it. I would assume to resolve the jar's in the /dependencies directory may be a bit of a pain.
The advantage is obviously that you document and simplify the management of those libraries. I would also assume if you update some of them it is easier across branches to merge since there are no binary files around. So it may be worth the effort.

Obtaining all parent poms in a repository

I have a huge local repository, which also contains unneeded jars (they are needed for other projects, but not for the task at hand). I've extracted the dependencies of my project using the maven dependency plugin and parsed that information into deploy commands in order to deploy those jars to another, remote repository. I couldn't have copied directly, because of access restrictions.
However, now compilation fails and I discovered that many of the issues I've already solved were due to the fact that the parent poms for some of the jars I was using were missing.
Is there a way to programmatically obtain all the parent poms of the dependencies of a certain project, similar to finding the dependencies themselves?
I would try parsing the directory tree directly and deploying every pom which doesn't have a jar counterpart, but I really hope there are better alternatives.

How to depend on a local library with maven

I have a project contains two sub projects:
A. a common library for external api
B. a program depends on above library
They are inside same directory. How I made B refer to A with maven?
Normally you will always share through a maven repository. That is mavens way to ensure a consistent and correct solution and a solution shareable by all developers.
You should search for a public maven repository with project A (e.g. http://search.maven.org or http://mvnrepository.com) and include in your pom
If it does not exist in public (is proprietary in someway or other), consider using an enterprise-wide maven repository such as nexus or artifactory to push to repositories.
Finally, some developers resort to either installing a mvn-local file if you are ever only going to work on an explicit workstation.
If you still prefer a filebased acces, it is possible to define a maven file repository and reference it in your pom. E.g. Heroku use this for bundling extra dependencies into their system.
Declare A as dependency in B's pom.xml. Make sure A has valid pom.xml and is deployed to your repository (local/nexus). We do that all the time. Take care to assign SNAPSHOT version if you always want latest to be pulled from repository.

View a dependency tree in Maven?

I'd like to make sure I'm not including duplicate libraries in my Maven project. I'm pulling in quite a few dependencies from a few different repositories including main, Spring's repo, and JBoss' repository. How can I see a graph of the dependencies so I can make sure I'm not depending on multiple versions of a single library?
It would be kind of a bummer if I was including something like org.springframework:spring-core:3.0.1.RELEASE and org.springframework:org.springframework.spring-core:3.0.5.RELEASE which actually do show up as different dependencies, as weird as it sounds, because Spring's repository names things weirdly. What can I do to make sure I don't have duplicate dependencies?
The dependency:tree maven plugin should do what you want and show the tree.
Alternatively force Maven2 to copy dependencies into target/lib to copy the the artifacts in the target/lib directory which should also show duplicates but you would still need to grep all the POMs in the ~/.m2/repository to see which library is pulling in which version manually and that would be time consuming for large local repositories.
Duplicate libraries can be a problem, but duplicate classes can exist even if no libraries are duplicated. JBoss Tattletale can analyze a set of jar files and produce a report which lists all duplicated classes. There’s a Maven plugin for running the report - see http://docs.jboss.org/tattletale/userguide/1.2/en-US/html/maven.html
If you'd like to get a graphical, searchable representation of the dependency tree (including all modules from your project, transitive dependencies and eviction information), check out UpdateImpact: https://app.updateimpact.com (free service).
Using the search, you can find out how many times a given library is imported, by what modules and in which versions, as well as verify if older versions of a library are evicted by newer ones.
Disclaimer: I'm one of the developers of the site

Resources