Love it or hate it (and a lot of people seem to hate it), Maven is a widely used tool – with 64% of Java developers applying it at some point (source – Java Tools and Technologies Landscape for 2014).
Most experienced developers have already had their share of Maven headaches. Usually in the hard way, banging their head into a brick wall. Unfortunately, I feel that new developers are going through the same hard learning process.
Looking into the main Java conferences around the world, you cannot find any Maven related sessions that guide you through the fundamentals. Maybe the community assumes that you should already know them, like the Java language itself. Still, recycling this knowledge could be a win-win situation for everyone. How much time do you or your teammates waste with not knowing how to deal with Maven idiosyncrasies?
If you are reading this, I’m also going to assume that you grasp the basics of Maven. If not, have a look into the following articles:
There a lot of other articles. I see no value in adding my own, repeating the same stuff, but if I feel the need I may write one. Let me know if you support it!
Anyway, I think I can add some value by pointing out the main issues that teams came across when using Maven, explain them and how to fix them.
Why is this jar in my build?
Due to the Maven transitive dependencies mechanism, the graph of included libraries can quickly grow quite large.
If you see something in your classpath, and you didn’t put it there, most likely is because of a transitive dependency. You might need it or maybe not. Maybe the part of the code of the library you’re using doesn’t require all those extra jars. It feels like a gamble here, but you can get a rough idea if you use
mvn dependency:analyze. This command will tell you which dependencies are actually in use by your project.
I mostly go by trial and error here, excluding what I think I don’t need and running the code to see if everything is OK. Unfortunately, this command doesn’t go so far to tell you if the transitive dependencies are really needed for the dependencies that you are using. Hey, if someone knows a better way, let me know!
I can’t see my changes!
This can happen for multiple reasons. Let’s look into the most common:
Dependencies are not built in the local repository
You may have Module A and Module B. Module B has a dependency to Module A. The changes you made to Module B are not visible in Module A.
This happens because Maven look into it’s own local jar repository to include in the classpath. If you make any changes, you need to place a copy of new jar into the local repository. You do that by running
mvn install in the changed project.
Dependency version is not correct
This can be as simple as changing the version of the dependency that you are using, or conversely, a real pain to figure it out. When Maven performs the dependency lookup, it uses the rule Nearest Definition First. This means that the version used will be the closest one to your project in the tree of dependencies. Confused? So am I. Let’s try an example.
You want to use dependency
Dv1 in your project
A, but you’re getting
Dv2, and you have the following dependency tree:
A -> B -> C -> Dv1
A -> E -> Dv2
Which dependency of
D is included?
Dv2? In the case
Dv2 because of the Nearest Definition First rule. If two dependency versions are at the same depth in the dependency tree, it’s the order in the declaration that counts.
To fix this problem you could explicitly add a dependency to
A to force the use of
Dv1 or just exclude
If you use the command
mvn dependency:tree it will output a tree will all the dependencies and versions for the project. This is very helpful to debug these kind of problems.
Remote repository has overwritten your changes
It’s usual for companies to have an internal Maven repository to cache artifacts, store releases or serve the latest changes of the project you are working on. This works great most of the time, but when you’re working with SNAPSHOT versions, Maven is always trying to pick up the latest changes to that dependency.
Now, you are happily working on your
Project B changes which has a dependency to
A. You build everything locally and proceed to integrate the changes in
A. Someone or something, upload a new SNAPSHOT version of
Project B. Remember, your changes are not visible yet, since you have everything locally and did not commit to VCS yet. The next build you make of
Project A it’s going to pick the
B from the company repository and not the one in your local repository.
The jar is not included in the distribution!
To add a little more confusion, let’s talk about scopes. Maven has four scopes:
test. Each dependency has a scope and the scope defines a different classpath for your application.
If you are missing something, and assuming that you have the dependency defined correctly, most likely the problem is in the scope. Use the
compile scope to be on the safe side (which is the default). The commands
mvn dependency:analyze and
dependency:tree can also help you here.
The artifact was not found!
Ah, the dreaded “Could not resolve dependencies…Could not find artifact”. This is like the Java NPE! There are many reasons for why this happens. A few more evident that others, but a pain to debug anyway. I usually follow this checklist to try to fix the problem:
- Check that the dependency is defined correctly
- Check if you are pointing to the correct remote repositories that store the dependency
- Check if the remote repository actually holds the dependency!
- Check if you have the most recent pom.xml files
- Check if the jar is corrupted
- Check if the company repository is caching the internet repositories and didn’t not issue a request to get the new libraries
- Check if the dependency definition is being overridden by something. Use
help:effective-pomfor the actual maven setting building the project
- Don’t use -o
Maven is not a perfect tool, but if you learn a few tricks of the trade, it will help you and save time debugging build problems. There are of course other ways to fix a few of these problems, but I don’t have enough knowledge to voice my opinion about them.
Anyway, a big chunk of projects use Maven as a build tool, and I believe that developers should know about their build tool to be able to perform better in their everyday work. Hopefully this post will be useful for you.
Feel free to post any other problem not covered here. Unfortunately, Maven sometimes seems a box full of surprises.
One last piece of advice: Never trust the IDE! If it works on the command-line, then it’s an IDE problem.