Become a Maven ninja!
Tags: java, kotlin, maven, commandline
Published: 2022-10-17 16:43:34

Today we are going to look at some small tricks that will make you more effective when using Maven! Some of this will be simple, and some of them you might not have heard about. I've done some presentations at work and similar earlier about this, and there is almost always something new to people. The topics range from basic usage and flags, to ways of handling your dependencies. One or two might be a bit enterprise specific, but most can be useful no matter if you program inside a company or not. (no secret that I love those of you who, like myself, LOVE computers with a burning passion! <3 ) 


If you don't know, [Maven](https://maven.apache.org/) is a build automation tool (dependency management, building, running tests etc.) used for languages on the JVM (Java Virtual Machine). I use it when programming in [Kotlin](https://themkat.net/tags/kotlin.html) and [Java](https://themkat.net/tags/java.html), with the latter becoming less and less frequent (Kotlin rules!!). Several people will probably ask why I'm not using [Gradle](https://gradle.org/) instead, but that is a discussion for another time.


There is probably much more that could be covered, but I think this is the most important once you know the basics. If you are new to Maven, suggest starting with [an introduction like this](https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html). The guide covers creating projects as well, but many modern frameworks have easier and better generators. Spring Boot have [its own initializer website](https://start.spring.io/), and I've made [a CLI version](https://github.com/themkat/spring-starter-terminal). Quarkus also have [a nice web UI you can use to create new projects](https://code.quarkus.io/). 


My last self-promotion before we begin... General command line skills can be very useful when working with almost any command line tool, including Maven. If you need a refresher, I recently wrote [a guide to getting started with the command line](https://themkat.net/2021/10/02/no_nonsense_command_line.html) (important topics: piping, searching with grep, less).

## Basic usage and flags
### Check Maven version
I want to show this for one reason, it's useful when checking for possible errors. Simply type `mvn -v` and you will get information about the Maven and Java versions currently being used:
![Check Maven version](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m0ta5h39wnjw5a9d26fx.png) 
(remember that the Java version can be changed by changing where the environment variable JAVA_HOME points to!)


### package vs install
You may have noticed that you have a .m2-folder in your home directory. This can contain a settings.xml file (if you have specific local settings like proxies), as well as your local Maven repository (where Maven downloads and stores dependencies and artifacts locally). Why is this important? package builds your project (compiles, run tests etc.), and install does the same in addition to installing it (copying it) to your local Maven repository (.m2/repository). 

**NB! As package does not install to .m2 directory you can get some weird issues in multi-module Maven projects with dependencies to each other. Maven reads the dependencies from this local repository, and if it doesn't find it there, it will try the to download it.**

### using -f option to run a specific pom file
Just like the title says. If you do something like `mvn -f mymodule/pom.xml install`, Maven will build based upon the pom.xml file in the directory mymodule instead of the directory you are currently in. 

### using -X option to get debug information
`mvn -X goals` (replace goals with the actual Maven goals!) will show you looooots of information you can use when debugging possible issues. Just be aware that this is a lot of information! Ranging from all packages imported, what settings files are used (local for your user as well as global settings for the computer), complete configurations for things like [Surefire](https://maven.apache.org/surefire/maven-surefire-plugin/) (testing) and so on.


Now a little story time! I recently helped someone I know with some issues they were having with Maven. All dependencies (within an enterprise) timed out when downloading, and there was a note of a proxy we couldn't find in his local .m2/settings.xml file. How did we find the issue you may ask? Was it some global settings in a parent pom? Well, actually no! Within the first 100 lines of running `mvn -X install` we got our answer. A global settings file was put into Mavens install directory (probably by mistake and forgotten). By using the -X option we found the problem, without scratching our heads for days :) 


## Tests
### Run single test(class)
You can run only tests with `mvn test`, but did you know you can run just a single test class by using `mvn test -Dtest=MyClassTest`? If you have several test classes with that name, use the fully qualified name (including package, example: com.example.MyClassTest).


Want to run just a single test method within that test class? Just as simple! `mvn test -Dtest=MyClassTest#myMethod` will run the test myMethod within your test class.

### Don't trim stack trace
Sometimes you get unexpected nullpointers or other exceptions within the method you are testing. Some times you will se a very minimal stack trace with just your test method, and the rest cut off (aka trimmed). If you want the complete stack trace with causes, line numbers etc., then you can use the definition `-DtrimStackTrace=false`! (works with test, package install, other goals, etc.). Helps me a lot, especially since I prefer to use the command line instead of big bloaty IDEs.

### Skipping tests
Want to skip all tests when building? `mvn install -DskipTests` will run install like usual, but not run any tests (but they will still be compiled!). 


## Dependency plugin
### tree
`mvn dependency:tree` is one of the most useful commands for checking the dependencies in your project, including transitive dependencies (dependencies of your dependencies and so on). This include all versions of dependencies being used. These reports can be quite long for bigger projects, so it can be useful to pipe the result to less or search it using grep (if you have a suspicion of deprecated code and similar causing weird behavior). 

### analyze
Have a suspicion that you use conflicting versions of packages? Or have unused dependencies in your project? `mvn dependency:analyze` can help you here! It will print all info like this. (also useful to browse by piping the output to less!).

**NB! Some dependencies in big frameworks like Spring might not be used directly at compile time, so there might be some false positives in the unused packages report.**

### display-ancestors
Many enterprises (and maybe open source projects) have hierarchies of [parent pom files](https://maven.apache.org/guides/introduction/introduction-to-the-pom.html) to handle global settings, approved dependency versions and so on. Sometimes you may want to see what version of parent poms you are currently using (maybe to debug if you are using the correct one, because these things can be updated!). Then `mvn dependency:display-ancestors` is your friend! Running it with a new Spring Boot project will show you the version of the Spring Boot starter poms it's using:

![Checking Maven parent poms in a Spring project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dd9sm2mwdfantoqxlr10.png)


## Versions
Maven have a versions plugin that can be used for several operations relating to versions. The only command here I find useful is `mvn versions:set -DnewVersion=1.0.0`. This will set the new versions of your project (including submodules) to 1.0.0. No need to edit the files manually! Neat!


## Bonus: ZSH completion
Oh-My-ZSH has some really useful completions so you don't have to memorize any Maven commands. Just add mvn to your plugins list, open a new tab in your terminal (or new session) and you get nice completion! (you probably need Maven installed first, just to mention it...). Mine looks like this `plugins=(git z gh mvn thefuck)` on my personal machine (kubectl is also super useful if you use Kubernetes!).  


Let's do an example. Let's say I type `mvn dependency:` and press tab. Then ZSH will suggest the possible completions for me:
![Maven zsh completions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6rmwd096mljdfht5thw1.png)
(you can off course complete anything, including goals like package, deploy etc. I just wanted to show something that didn't cover my entire window ;) )


One thing worth mentioning is that this plugin completes the Spring Boot goals like `mvn spring-boot:run` and Quarkus goals like `quarkus:dev` as well! How cool is that?!?