You can use this guide to understand what a 'mvn clean install' really does. Also: A crash-course on Maven and workarounds for its most common pitfalls.
The short answer
Apache Maven is a popular build tool, that takes your project’s Java source code, compiles it, tests it and converts it into an executable Java program: either a .jar or a .war file.
mvn clean install is the command to do just that.
You are calling the mvn executable, which means you need Maven installed on your machine. (see section_title)
You are using the clean command, which will delete all previously compiled Java sources and resources (like .properties) in your project. Your build will start from a clean slate.
Install will then compile, test & package your Java project and even install/copy your built .jar/.war file into your local Maven repository. (see section_title)
The (short) long answer:
There is more to Maven than a couple lines on 'mvn clean install'. If you want to learn about how Maven’s dependency management and build cycle works, or how to avoid the most common pitfalls when working with it: Read on.
Maven is one of the most popular build tools in the Java universe (others being Gradle or old-school Ant). You can not only build Java projects with it, but pretty much every project written in a
JVM language like Kotlin or Scala, as well as other languages like C# and Ruby.
Now what exactly does a build tool do? Maven does three things rather well:
Compilation through convention: In theory you could compile big Java projects with a ton of classes, by hand with the javac command line compiler (or automate that with a bash script). This does however only work for toy projects. Maven expects a certain directory structure for your Java source code to live in and when you later do a mvn clean install , the whole compilation and packaging work will be done for you.
Everything Java: Maven can also run code quality checks, execute test cases and even deploy applications to remote servers, through plugins. Pretty much every possible task you can think of.
Technically, any directory that contains a pom.xml file is also a valid Maven project. A pom.xml file contains everything needed to describe your Java project. Let’s have a look at a minimal version:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.marcobehler</groupId> <artifactId>my-project</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
We are defining a project called 'my-project'
With a version number of 1.0-SNAPSHOT, i.e. work-in-progress
Using Java 1.8 for compilation
With one dependency needed for unit testing: junit in version 4.12
Apart from a pom.xml file, you also need Java source code for Maven to do its magic, whenever you are calling mvn clean install.
Java source code is to be meant to live in the "/src/main/java" folder
Maven will put compiled Java classes into the "target/classes" folder
Maven will also build a .jar or .war file, depending on your project, that lives in the "target" folder.
In the end, your project will look like this:
+ myproject + -- src + -- main + -- java MyApp.java + -- target + -- classes (upon mvn compile) MyApp.class myproject.jar (upon mvn package or mvn install) pom.xml
Now that you have a pom.xml file, as well as a src folder, you still need Maven installed on your machine. Let’s do that now.
Installing Maven is rather simple. Similar to Java it is just a .zip file that you need to download and put anywhere on your harddrive. The .zip file’s contents look like this:
Directory c:\dev\apache-maven-3.6.1 12.07.2019 09:25 <DIR> . 12.07.2019 09:25 <DIR> .. 12.07.2019 09:25 <DIR> bin 12.07.2019 09:25 <DIR> boot 12.07.2019 09:25 <DIR> conf 12.07.2019 09:25 <DIR> lib 12.07.2019 09:24 13.437 LICENSE 12.07.2019 09:24 182 NOTICE 12.07.2019 09:24 2.533 README.txt
Now you need to make sure to add the /bin directory to your PATH variable, otherwise you cannot call 'mvn' (think: mvn clean install) from anywhere. That’s it.
If you are unsure about any of these two steps, there’s a great video on Youtube, showing how to install the latest Maven 3.6 on Windows.
Now what really happens when you execute a mvn clean install in your project? Maven has the concept of a build lifecycle, which is made up of different phases.
Here’s what Maven’s default lifecycle looks like (note: it is missing 'clean').
When you call "mvn deploy", mvn will also execute every lifecycle phase before deploy, in order: validate, compile, test, package, verify, install.
Same for verify: validate, compile, test, package. Same for all other phases.
And as 'clean' is not part of Maven’s default lifecycle, you end up with commands like 'mvn clean install' or 'mvn clean package'. 'Install' or 'package' will trigger all preceding phases, but you need to specify clean in addition.
Contrary to other languages, where project dependencies are stored in your project’s directory, Maven has the concept of repositories.
There are local repositories (in your user’s home directory: ~/.m2/) and remote repositories. Remote repositories could be internal, company-wide repositories like Artifactory or Nexus or the (reference) global repo at https://repo.maven.apache.org/maven2/.
Maven will always download your project dependencies into your local maven repository first and then reference them for your build. When you think back at your pom.xml file from before:
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
Then mvn will, once you try and "mvn test" your project, download the junit dependency into ~/.m2/repository/junit/junit/4.12/junit-4.12.jar and reference it via Java’s classpath mechanism for your build.
For more info on using repositories, see the official documentation at https://maven.apache.org/guides/introduction/introduction-to-repositories.html.
If you followed the guide, this should be pretty much clear by now.
clean: deletes the /target folder. So, the same result for both commands.
package: Converts your .java source code into a .jar/.war file and puts it into the /target folder.
install: First, it does a package(!). Then it takes that .jar/.war file and puts it into your local Maven repository, which lives in ~/.m2/repository.
In theory, calling 'mvn install' would be enough if Maven was smart enough to do reliable, incremental builds. That means figuring out what Java source files/modules changed and only compile those.
Before Maven 3.1 incremental compilation was basically non-existent, and even with the latest Maven and compiler plugin versions there’s bugs and documentation issues in the incremental compilation support.
Hence developers got it ingrained to always call 'mvn clean install' (even though this increases build time a lot in bigger projects).
Unfortunately, this is something that happens in multi-module projects and other build tools like e.g. Gradle have no problem with it. Imagine your Maven build looks like this:
+ stocks-broker-app (parent) + stocks-data-module + stocks-rest-module (depends on stock-data) + stocks-ui-module (depends on stock-data)
and you are doing the following:
cd stocks-ui-module mvn clean install // or another appropriate goal
The problem is: Maven will NOT be smart enough to automatically build stock-data as a needed sibling dependency. Instead, you will need to have stock-data built already, yourself.
There’s a workaround though. You don’t always have to build the whole parent project, instead you can specify the list of submodules to build and do a dependent build. In our case, this would look like:
cd .. // so you are in the parent project mvn -pl stocks-ui-module -am clean install // or another appropriate goal
-pl lets you specify the submodules to build
-am stands for also make, which will build dependent modules as well
Sometimes, if your project depends on SNAPSHOT dependencies, Maven will not update your local Maven repository with the very latest snapshot version.
This is a bit oversimplified, but if you want to make sure that Maven always tries to download the latest snapshot dependency versions, invoke it with the -U switch.
mvn -U clean install
Some projects come with a mwnw executable, which does not stand for Maven (on) Windows, but rather for Maven wrapper.
This means you don’t have to have mvn installed on your machine to build your project - rather, mvn is embedded in your project directory and you can call it with the mvnw executable.
Learn more about the Maven wrapper here.
This guide is just a quick overview of what Maven can do for you and how to work around its most common pitfalls. If you want more thorough explanations, check out the Mastering Maven course.
If you have any comments or feedback, or want to suggest a another common Maven question, simply leave a comment below.
This article originally appeared on www.marcobehler.com/written as part of a series of guides on modern Java programming. To find more guides, visit the website or subscribe to the newsletter to get notified of newly published guides: https://bit.ly/2K0Ao4F.
Thanks for reading.