Mastering Series
Mastering series aims to make you the best developer, out there.
Mastering series aims to make you the best developer, out there.
Welcome to the series - Mastering Maven.
With this series, we will dive into the world of Apache Maven β a powerful tool that simplifies your project management like magic!
Whether you’re just starting on your coding journey or you are a seasoned professional, looking to streamline your workflow, these videos have something for everyone.
We will break down the basics, showcase advanced features, and explore best practices, to elevate your development game.
We will start with absolute basics - What is Maven, Why is it so Popular, How it Works, and How can you use it, to build your applications, in the most efficient way.
Getting Started with Apache Maven
A beginners introduction to Apache Maven
Installing Apache Maven on Linux
Installing Apache Maven on Mac
Installing Apache Maven on Windows
A beginners introduction to Apache Maven
Standard Project Directory Structure of a typical Apache Maven Project
This article gives you a beginners Introduction to Apache Maven.
You can watch the Introduction in this video.
Apache Maven or in short just Maven, is popular for its build capabilities. That is why, most people refer to Maven, as a Build Automation tool, or in short - just a Build Tool.
Yet, Maven is not just a build tool; but it is more than that. The project team responsible for the development and maintenance of Maven, describes Maven as a software project management and comprehension tool.
Based on the concept of a Project Object Model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.
Do remember this term, Project Object Model or in short POM, because you will hear and use it all the time when talking about Maven. We will discuss POM in detail in our later videos.
So, as you can see, Maven aims to be, more than, just a Build Automation Tool.
But, you might ask, what do we mean by “More than a Build Tool”?
Well, apart from providing the build capabilities, which comprise of:
But apart from all of this (the build tooling), Maven can do things like generating reports. These reports could be a Unit Test report, or you have a tool that does some Performance testing of your application. Maven can take the performance test data and generate a report and publish them.
You can also generate a documentation website from Maven. People who are familiar with Javadoc, Maven provides support to generate Javadoc, which is a very common documentation format for Java source code.
What else - you can also use it to communicate within your team. Maven can act as a team member and can send you notification on your Slack or Hangouts or any other messenger.
And it can do a lot - a lot more things.
All applications built today have dependencies.
The below XKCD diagram depicts the nature of modern day applications and their interdependence.
As much as using dependencies allows us to quickly build the applications, dependency management becomes important. One of the biggest benefits or features that Maven brings with it, is Dependency Management. If you have ever worked with Apache ANT, you will know how much things got better, when you started using Maven.
A typical Java application these days has multiple dependencies. For example, here I have an application which has 2 dependencies. A Web Server that is going to handle requests(Tomcat or Jetty), and I have a database driver that allows me to connect to the database.
Without Maven, I will need to download the jars from the internet, copy them to the library folder, and then add these in the application classpath. Now, when I run the application, after compilation and building, the application works.
Now, thatβs a lot of manual work.
Instead of manually managing these dependencies, I can configure these dependencies in Maven and let Maven do the hard work. Maven will download the jar files from the internet, use them for compiling, testing and then package it along with the final packaged artifact.
You might think, these are just two files and I can manage that. But these days, a typical java application has easily more than 10 dependencies/jar files. If you start managing these dependencies manually, trust me, it is going to be a nightmare.
In fact, let me give you an example how managing dependency manually can easily go out of control. So taking the previous example, we have WebServer version 1.0 and DB Driver version 1.0 in the application. The application is running fine and there are no issues.
Consider, there is a critical security bug reported in Web Server 1.0 (and this happens all the time). Developers managing Web Server, fix the security bug and release a new version. This new version is Web Server 2.0. Since we do not want the security bug to affect our application, we will need to update the Web Server dependency from 1.0 to 2.0. So, we will download the latest Web Server 2.0 jar, and add it to the application.
But, when we try to run the application, it fails. Why?
Because, in a hurry to fix the security bug, WebServer 2.0 became incompatible with DB Driver 1.0. Developers of DB Driver, on realizing this, fixes the compatibility issue and releases their version DB Driver version 2.0.
So, what will we have to do now?
Again the same process, update DB Driver to version 2.0. We download the jar file, add it to our application and then now, the application starts to run again.
This is a very simple example with just 2 dependencies. Manual dependency management gets really, really complicated once you start to deal with dependency over 10.
Worse, you update a single dependency, and you see multiple other dependencies becoming incompatible with each other. There is a cascading update of the dependencies required, until all incompatibilities are resolved, to eventually have the application work fine.
This is where Dependency Management comes into picture and the power of Maven.
We will configure both Web Server and DB Driver dependency in the Maven configuration file. Whenever we update any of the dependencies, all related compatible dependencies are also fetched by Maven.
In our example, when we update Web Server 2.0 in the Maven configuration file, Maven automatically fetches the compatible DB Driver 2.0.
And all this happens magically, under the hood. All you do is update the Maven configuration file, and Maven does the magic for you.
But, you might wonder - how does Maven do all this Magic? The answer to that question is - Plugins.
Maven makes use of Plugins. Whatever activity you can think of, there is a plugin for that activity.
You want to compile your source code, there is a plugin to compile.
You want to run tests that you wrote in the application, there is a plugin for testing.
You want to create a Docker image so that you can deploy your application, there is a plugin to build a docker image.
In fact, there is even a plugin to create the Maven project structure called archetype. It allows you to create your starting project structure - your folders for source code, folder for test classes, and then create the Maven configuration file, so that you can adjust settings as per your need.
Whatever Maven does, it does it with the help of plugins. These plugins contain the code to perform the activity. Maven just triggers the plugin code as per userβs needs, via the Maven configuration file.
Maven works on all three platforms, Windows, Mac and Linux. All, you need is Java installed on your system to run Maven on your system.
And that is a very brief introduction to Apache Maven.
This article gives you a step by step walkthrough for installing Apache Maven on Linux.
You can watch the entire installation demo in this video.
Apache Maven is the most popular build and project management tool for Java projects. Maven is built on top of Java, so if you plan to install Maven on your system, you need to have Java installed on your system.
Installation of Maven on any system consists of following 3 steps.
Let me walk you through these steps in detail for a Linux system.
The latest Apache Maven version at the time of writing this is 3.9.9
. All screenshots and commands in this article refer to this version. But they are equally applicable to other versions, as well.
The first step is to download the Apache Maven from the official website. The downloads page for Apache Maven is this - https://maven.apache.org/download.cgi. On this page, you have two binary options to download - either a zip file or a tar.gz file(marked in blue boxes). Here is the screenshot below.
You can choose either of these. If you are not sure, choose the zip file. Also, download the corresponding checksum file(marked in orange boxes) so that you can validate the zip file download.
You can use your browser to download these, or you can use the wget
or curl
on the command prompt to download the files.
Here is the command using the wget
that download the zip file and the corresponding checksum file.
-> wget -q --show-progress https://dlcdn.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip
apache-maven-3.9.9-bin.zip 100%[======================================================>] 8.78M 17.8MB/s in 0.5s
-> wget -q --show-progress https://downloads.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip.sha512
apache-maven-3.9.9-bin.zip.sha5 100%[======================================================>] 128 --.-KB/s in 0s
-> ls -l
-rw-rw-r-- 1 thedevjournal thedevjournal 9202456 Jan 27 15:24 apache-maven-3.9.9-bin.zip
-rw-rw-r-- 1 thedevjournal thedevjournal 128 Jan 27 15:26 apache-maven-3.9.9-bin.zip.sha512
Before you extract the zip or tar.gz file, perform a quick checksum validation of the downloaded file to ensure that there were no issues with the download.
The checksum files mentions which kind of hash is used for zip file. Its sha512, and hence we need sha512sum
command to calculate the checksum of the zip file. This command is part of coreutils
package and if you don’t have install, you can install it with your package manager. Here is a list of installation commands for installing coreutils
on your Linux distribution.
-> sha512sum apache-maven-3.9.9-bin.zip
8beac8d11ef208f1e2a8... (removed in favour of brevity) ...82ee8a2ff4c4418ba apache-maven-3.9.9-bin.zip
-> cat apache-maven-3.9.9-bin.zip.sha512
8beac8d11ef208f1e2a8... (removed in favour of brevity) ...82ee8a2ff4c4418ba
A quick glance, you would see that both the checksums are same and that ensures that the download was completed without any errors.
Before we extract the binary archive file, we need a directory. It is a good practice to keep all of your installations together, so you can place them in a directory called installed
in your home directory(~
).
You can create this directory if it does not exist using the mkdir
command. Inside this installed
directory, we need to create our maven3
directory where we will extract our binary archive file. You can create these directories like this.
-> mkdir -p ~/installed/maven3
Afterwards, we need to move our binary archive file in this maven3
directory, and then we cd
into this directory so that we can extract the archive file here.
-> mv apache-maven-3.9.9-bin.zip ~/installed/maven3/
-> cd ~/installed/maven3
If you have downloaded the zip file, you will need unzip
command to extract the zip file. After extracting the zip file, you won’t need it, so you can delete that.
-> unzip -q apache-maven-3.9.9-bin.zip
-> rm apache-maven-3.9.9-bin.zip -f
And if you have downloaded the tar.gz file, you will need tar
command.
-> tar -xf apache-maven-3.9.9-bin.tar.gz
-> rm apache-maven-3.9.9-bin.tar.gz -f
You don’t need to create a symbolic link to the newly extracted folder, but it will make your life easier if a symbolic link always pointed to latest Maven installation.
So, if next time, you upgrade the Maven installation from 3.9.9
to 3.9.10
, you can just update the symbolic link and everything should continue to work as it is. You won’t have to update any environment variables(discussed in the next section)
Here is how you will create a symbolic link.
-> ln -s apache-maven-3.9.9 latest
With the extraction of binary archive file in the installed/maven3
directory, Maven is pretty much installed in your system. The only gotcha is that every-time you need to run the mvn
command, you will have to traverse the entire path - ~/installed/maven3/latest/bin/mvn
. It will be much better, if we could just run the mvn
command from any directory without specifying the entire path to the mvn
executable.
A lot of Java tools look for M2_HOME
environment variable to locate the Maven installation directory in the system. This environment variable can be configured in any of your .bash_profile, .bashrc, .profile
file. This is the entry that you will need to put.
export M2_HOME="~/installed/maven3/latest"
Once, this is configured, we need to configure the PATH
variable, that will enable running of the mvn
command from any directory. Here is how, it will be configured in your .bashrc or .bash_profile
file.
export PATH="$PATH:$M2_HOME/bin"
Once this is configured, you need to re-import the configurations. Simple close the current terminal window and open a new one.
And now if you run mvn -version
, you should see the Maven installation details confirming that you have Apache Maven installed successfully.
-> mvn -version
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /home/thedevjournal/installed/maven3/latest
Java version: 17.0.13, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "6.8.0-52-generic", arch: "amd64", family: "unix"
Now, you can start to run your builds locally with Maven on your Linux system.
This article gives you a step by step walkthrough for installing Apache Maven on Mac.
You can watch the entire installation demo in this video.
Apache Maven is the most popular build and project management tool for Java projects. Maven is built on top of Java, so if you plan to install Maven on your system, you need to have Java installed on your system.
Installation of Maven on any system consists of following 3 steps.
Let me walk you through these steps in detail for a Mac system.
The latest Apache Maven version at the time of writing this is 3.9.9
. All screenshots and commands in this article refer to this version. But they are equally applicable to other versions, as well.
The first step is to download the Apache Maven from the official website. The downloads page for Apache Maven is this - https://maven.apache.org/download.cgi. On this page, you have two binary options to download - either a zip file or a tar.gz file(marked in blue boxes). Here is the screenshot below.
You can choose either of these. If you are not sure, choose the zip file. Also, download the corresponding checksum file(marked in orange boxes) so that you can validate the zip file download.
You can use your browser to download these, or you can use the wget
or curl
on the command prompt to download the files.
Here is the command using the wget
that download the zip file and the corresponding checksum file.
-> wget -q --show-progress https://dlcdn.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip
apache-maven-3.9.9-bin.zip 100%[======================================================>] 8.78M 17.8MB/s in 0.5s
-> wget -q --show-progress https://downloads.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip.sha512
apache-maven-3.9.9-bin.zip.sha5 100%[======================================================>] 128 --.-KB/s in 0s
-> ls -l
-rw-rw-r-- 1 thedevjournal thedevjournal 9202456 Jan 27 15:24 apache-maven-3.9.9-bin.zip
-rw-rw-r-- 1 thedevjournal thedevjournal 128 Jan 27 15:26 apache-maven-3.9.9-bin.zip.sha512
If you don’t have wget
and/or curl
installed, you can install these through homebrew via brew install wget
and/or brew install curl
.
Before you extract the zip or tar.gz file, perform a quick checksum validation of the downloaded file to ensure that there were no issues with the download.
The checksum files mentions which kind of hash is used for zip file. Its sha512, and hence we need shasum
command to calculate the checksum of the zip file.
-> shasum -a 512 apache-maven-3.9.9-bin.zip
8beac8d11ef208f1e2a8... (removed in favour of brevity) ...82ee8a2ff4c4418ba apache-maven-3.9.9-bin.zip
-> cat apache-maven-3.9.9-bin.zip.sha512
8beac8d11ef208f1e2a8... (removed in favour of brevity) ...82ee8a2ff4c4418ba
A quick glance, you would see that both the checksums are same and that ensures that the download was completed without any errors.
Before we extract the binary archive file, we need a directory. It is a good practice to keep all of your installations together, so you can place them in a directory called installed
in your home directory(~
).
You can create this directory if it does not exist using the mkdir
command. Inside this installed
directory, we need to create our maven3
directory where we will extract our binary archive file. You can create these directories like this.
-> mkdir ~/installed
-> mkdir ~/installed/maven3
Afterwards, we need to move our binary archive file in this maven3
directory, and then we cd
into this directory so that we can extract the archive file here.
-> mv apache-maven-3.9.9-bin.zip ~/installed/maven3/
-> cd ~/installed/maven3
If you have downloaded the zip file, you will need unzip
command to extract the zip file. After extracting the zip file, you won’t need it, so you can delete that.
-> unzip -q apache-maven-3.9.9-bin.zip
-> rm apache-maven-3.9.9-bin.zip
And if you have downloaded the tar.gz file, you will need tar
command.
-> tar -xf apache-maven-3.9.9-bin.tar.gz
-> rm apache-maven-3.9.9-bin.tar.gz
You don’t need to create a symbolic link to the newly extracted folder, but it will make your life easier if a symbolic link always pointed to latest Maven installation.
So, if next time, you upgrade the Maven installation from 3.9.9
to 3.9.10
, you can just update the symbolic link and everything should continue to work as it is. You won’t have to update any environment variables(discussed in the next section)
Here is how you will create a symbolic link.
-> ln -s apache-maven-3.9.9 latest
With the extraction of binary archive file in the installed/maven3
directory, Maven is pretty much installed in your system. The only gotcha is that every-time you need to run the mvn
command, you will have to traverse the entire path - ~/installed/maven3/latest/bin/mvn
. It will be much better, if we could just run the mvn
command from any directory without specifying the entire path to the mvn
executable.
A lot of Java tools look for M2_HOME
environment variable to locate the Maven installation directory in the system. This environment variable can be configured in your .zshrc
file. This is the entry that you will need to put.
export M2_HOME="/Users/devjournal/installed/maven3/latest"
Change devjournal
to your username in the above path
Once, this is configured, we need to configure the PATH
variable, that will enable running of the mvn
command from any directory. Here is how, it will be configured in your .zshrc
file.
export PATH="$PATH:$M2_HOME/bin"
Once this is configured, you need to re-import the configurations. Simple close the current terminal window and open a new one.
And now if you run mvn -version
, you should see the Maven installation details confirming that you have Apache Maven installed successfully.
-> mvn -version
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /Users/thedevjournal/installed/maven3/latest
Java version: 17.0.13, vendor: Private Build, runtime: /Library/Java/JavaVirtualMachines/java-17.jdk/Contents/Home
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "11.7.10", arch: "x86_64", family: "mac"
Now, you can start to run your builds locally with Maven on your Mac system.
This article gives you a step by step walkthrough for installing Apache Maven on Mac.
You can watch the entire installation demo in this video.
Apache Maven is the most popular build and project management tool for Java projects. Maven is built on top of Java, so if you plan to install Maven on your system, you need to have Java installed on your system.
Installation of Maven on any system consists of following 3 steps.
Let me walk you through these steps in detail for a Mac system.
The latest Apache Maven version at the time of writing this is 3.9.9
. All screenshots and commands in this article refer to this version. But they are equally applicable to other versions, as well.
The first step is to download the Apache Maven from the official website. The downloads page for Apache Maven is this - https://maven.apache.org/download.cgi. On this page, you have two binary options to download - either a zip file or a tar.gz file(marked in blue boxes). Here is the screenshot below.
You can choose either of these. If you are not sure, choose the zip file. Also, download the corresponding checksum file (marked in orange boxes) so that you can validate the zip file download.
You can use your browser to download these, or you can use the curl
on the command prompt to download the files.
Here is the command using the curl
that download the zip file and the corresponding checksum file.
PS C:\Users\thedevjournal\Downloads> curl -o apache-maven-3.9.9-bin.zip https://dlcdn.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip
PS C:\Users\thedevjournal\Downloads> curl -o apache-maven-3.9.9-bin.zip.sha512 https://downloads.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.zip.sha512
PS C:\Users\thedevjournal\Downloads> dir
Directory: C:\Users\thedevjournal\Downloads
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 02-02-2025 05:18 9202456 apache-maven-3.9.9-bin.zip
-a---- 02-02-2025 05:22 128 apache-maven-3.9.9-bin.zip.sha512
Before you extract the zip file, perform a quick checksum validation of the downloaded file to ensure that there were no issues with the download.
The checksum files mentions which kind of hash is used for zip file. Windows provides CertUtil
which allows to generate checksum of files using -hashfile
operation. Since the Maven checksum file uses SHA-512 format, we also need to generate the hash in the same format.
PS C:\Users\thedevjournal\Downloads> CertUtil -hashfile .\apache-maven-3.9.9-bin.zip SHA512
SHA512 hash of .\apache-maven-3.9.9-bin.zip:
8beac8d11ef208f1e2a8... (removed in favour of brevity) ...82ee8a2ff4c4418ba
CertUtil: -hashfile command completed successfully.
PS C:\Users\thedevjournal\Downloads> cat .\apache-maven-3.9.9-bin.zip.sha512
8beac8d11ef208f1e2a8... (removed in favour of brevity) ...82ee8a2ff4c4418ba
A quick glance, you would see that both the checksums are same and that ensures that the download was completed without any errors.
Before we extract the binary archive file, we need a directory. It is a good practice to keep all of your installations together, so you can place them in a directory called installed
in your C drive(C:\
).
You can create this directory if it does not exist using the mkdir
command.
PS C:\Users\thedevjournal\Downloads> mkdir C:\installed
Afterwards, we need to move our binary archive file inside C:\installed
directory, and then we cd
into this directory so that we can extract the archive file here.
PS C:\Users\thedevjournal\Downloads> mv apache-maven-3.9.9-bin.zip C:\installed
PS C:\Users\thedevjournal\Downloads> cd C:\installed
You will use Expand-Archive
command to extract the contents of the zip file.
PS C:\installed> Expand-Archive .\apache-maven-3.9.9-bin.zip
PS C:\installed> dir
Directory: C:\installed
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 02-02-2025 05:35 apache-maven-3.9.9-bin
-a---- 02-02-2025 05:18 9202456 apache-maven-3.9.9-bin.zip
PS C:\installed> dir .\apache-maven-3.9.9-bin\
Directory: C:\installed\apache-maven-3.9.9-bin
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 02-02-2025 05:35 apache-maven-3.9.9
Expand-Archive
extracts the file contents inside the apache-maven-3.9.9-bin
directory, hence we also need to move the new extracted folder 1 level above. And then, we can delete the zip file and the empty extraction folder.
PS C:\installed> mv .\apache-maven-3.9.9-bin\apache-maven-3.9.9 .\
PS C:\installed> rmdir .\apache-maven-3.9.9-bin
PS C:\installed> rmdir .\apache-maven-3.9.9-bin.zip
PS C:\installed> dir
Directory: C:\installed
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 02-02-2025 06:24 apache-maven-3.9.9
You can also simply extract from UI as well.
With the extraction of binary archive file in the installed
directory, Maven is pretty much installed in your system. The only gotcha is that every-time you need to run the mvn
command, you will have to traverse the entire path - C:\installed\apache-maven-3.9.9\bin\mvn
. It will be much better, if we could just run the mvn
command from any directory without specifying the entire path to the mvn
executable.
A lot of Java tools look for M2_HOME
environment variable to locate the Maven installation directory in the system. This environment variable can be configured using [System.Environment]::SetEnvironmentVariable
. This is the command:
[System.Environment]::SetEnvironmentVariable('M2_HOME','C:\installed\apache-maven-3.9.9', 'User')
The 3rd parameter, User
indicates that you intend to store this variable across multiple sessions, and only available to the user who is logged in. If you want to set this variable system-wide, use Machine
as the parameter.
Once, this is configured, we need to configure the PATH
variable, that will enable running of the mvn
command from any directory. Here is how, it will be configured:
$OLD_PATH = [Environment]::GetEnvironmentVariable("PATH", "User")
[Environment]::SetEnvironmentVariable("PATH", "$OLD_PATH;%M2_HOME%\bin", "User")
Once this is configured, you need to re-import the configurations. Simple close the current terminal window and open a new one.
And now if you run mvn -version
, you should see the Maven installation details confirming that you have Apache Maven installed successfully.
PS C:\installed> mvn --version
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: C:\installed\apache-maven-3.9.9
Java version: 17.0.14, vendor: Oracle Corporation, runtime: C:\Program Files\Java\jdk-17
Default locale: en_IN, platform encoding: Cp1252
OS name: "windows 11", version: "10.0", arch: "amd64", family: "windows"
Now, you can start to run your builds locally with Maven on your Mac system.
This article demonstrates the very first build with Apache Maven. In this article, we will use command prompt to create our simple Maven project and then use mvn
command to build it.
You can watch the entire demo in this video.
You need to have Apache Maven already installed on your system. If you don’t have Maven installed, you can install it by following steps from our previous articles:
You can also watch the videos here.
In this article, we will create the Maven project from the command prompt using the mvn
command. This basic project scaffolding is done using the maven-archetype-plugin. This plugin the one that is used by the IDEs under the hood to create the Project.
The archetype plugin has a numerous template projects to chose from and also from various sources. If you type simple mvn archetype:generate
, you will be presented with 3500+ various project templates. You can use the filter option to limit the search and chose, but in most cases, it is preferable to use an IDE.
The Archetype plugin works in interactive and non-interactive mode. In the interactive mode, you need to select the project template from which the project should be created and then you need to provide the maven coordinates.
If you already know the archetype, it is advisable to use the non-interactive mode. This is the approach which we will use in this article.
So, fire up a new Terminal window, and run the following command:
mvn archetype:generate \
-DinteractiveMode=false \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-simple \
-DarchetypeVersion=1.5
-DgroupId=io.thedevjournal.maven \
-DartifactId=first-maven-build \
-Dversion=1.0
If you are running this for the very first time, then Maven will download the plugin jars from the Maven central, and you will see those in your console. Don’t worry, these will be just downloaded just once and occasionally when there is a new update to the plugin that is being executed.
The command is a long one, so let us dissect it one at a time.
archetype:generate
This is a goal of archetype plugin that is responsible for generating for the project. Maven’s plugin execution follows this convention plugin:goal
to execute the various executions goals provided by the plugin. A full list of archetype plugin’s goals are listed here.
Because, we need to create a project from a template, we use the generate
goal.
Maven Lifecycle Goals are discussed in this article.
-DinteractiveMode=false
Property arguments to Maven are provided using -D
prefix. In our case, we are providing a property interactiveMode
which is used by archetype plugin. This tells the archetype plugin that it should not prompt the user for any mandatory value that is not provided. It will instead error out mentioning which value was missing.
In the interactive mode, Maven will use the values that you have provided and if any value is missing, it will ask you to provide them on the prompt.
Since, we are providing all the mandatory values as property arguments, we are disabling the interactive mode by interactiveMode=false
.
-DarchetypeGroupId=org.apache.maven.archetypes
This property tells the Archetype plugin to select the groupId
of the archetype that need to be used to create the project. There can be multiple organizations or teams that are creating their own archetypes, and they could clash. The archetypeGroupId
provides the ability to avoid such collisions.
For example, if you type mvn archetype:generate
, and when the plugin is asking you to provide the archetype id or filter option, type maven-archetype-simple
. You will see that there are three archetypes that define the same artifact id. Here is the output.
-> mvn archetype:generate
...
...
3523: remote -> za.co.absa.hyperdrive:component-archetype_2.12 (-)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 2216: maven-archetype-simple
Choose archetype:
1: remote -> com.haoxuer.maven.archetype:maven-archetype-simple (a simple maven archetype)
2: remote -> fr.ebruno.maven.archetypes:maven-archetype-simple (An archetype which contains a simple Maven project.)
3: remote -> org.apache.maven.archetypes:maven-archetype-simple (An archetype which contains a simple Maven project.)
As you can see, the first archetype has archetypeGroupId=com.haoxuer.maven.archetype
, second one has archetypeGroupId=fr.ebruno.maven.archetypes
, and third archetypeGroupId=org.apache.maven.archetypes
. To allow archetype plugin to chose precisely which of this needs to be used, you should specify archetypeGroupId
.
If you don’t specify archetypeGroupId
and there are multiple archetypes, the archetype plugin will use the first one from the list.
-DarchetypeArtifactId=maven-archetype-simple
archetypeArtifactId
tells which project template to be used to create the project. In our case, we will be using maven-archetype-simple
to create our project from.
-DarchetypeVersion=1.5
Even if you have provided archetypeGroupId
and archetypeArtifactId
, it is possible that there are multiple versions. If that is the case, you need to specify the version of the artifact id, which should be used to generate the project. In our case, we will be using Version 1.5
of maven-archetype-simple
to generate our project.
If you don’t specify archetypeVersion
and there are multiple versions, the archetype plugin will use the oldest available version.
-DgroupId=io.thedevjournal.maven.firstbuild
, -DartifactId=first-build
and -Dversion=1.0
groupId, artifactId
and version
together combine to indicate your project’s co-ordinate. Maven co-ordinates is the backbone of the Dependency Management. Just like a GPS Co-ordinate allow you to locate a specific place on a Globe, similarly, a project co-ordinate allows Maven to locate the project in the dependency tree of the root project.
Maven co-ordinates are discussed in great details in this article.
Now that the project is created, let us see the files that have been created. A quick run of tree
command shows the following output.
-> tree .
.
βββ pom.xml
βββ src
βββ main
βΒ Β βββ java
βΒ Β βββ io
βΒ Β βββ devjournal
βΒ Β βββ maven
βΒ Β βββ firstbuild
βΒ Β βββ App.java
βββ test
βββ java
βββ io
βββ devjournal
βββ maven
βββ firstbuild
βββ AppTest.java
App.java
is a very simple java program printing Hello World!
, and AppTest.java
is a JUnit test class file.
Below are the contents of these files.
package io.devjournal.maven.firstbuild;
/**
* Hello world!
*/
public class App {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
package io.devjournal.maven.firstbuild;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
* Unit test for simple App.
*/
public class AppTest {
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue() {
assertTrue(true);
}
}
pom.xml
The project object model file, pom.xml
contains the project, its dependencies and details of how to build the project. A detailed explanation of different sections of the POM is covered in this article, but high-level sections are discussed in individual tabs.
<!-- Project's Co-ordinates as provided in the mvn archetype:generate command -->
<groupId>io.devjournal.maven</groupId>
<artifactId>first-maven-build</artifactId>
<version>1.0</version>
<!-- Name of the Project and URL(you should adjust this as indicated) -->
<name>first-maven-build</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<!-- Encoding of Files in the Project -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Java Compiler Version -->
<maven.compiler.release>17</maven.compiler.release>
</properties>
<!-- Manages dependency versions -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Dependency 1 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- Dependency 2 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- How to Build the Project -->
<build>
<!-- Which Build Plugins to Use -->
<pluginManagement>
<plugins>
<!-- Build Plugin 1 - maven-clean-plugin-->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<!-- Build Plugin 2 - maven-resources-plugin-->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<!-- More plugins here -->
</plugins>
</pluginManagement>
</build>
<?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>io.devjournal.maven</groupId>
<artifactId>first-maven-build</artifactId>
<version>1.0</version>
<name>first-maven-build</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- Optionally: parameterized tests support -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.12.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.6.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
It has been too much theory. Let us build this project.
Maven build contains of different lifecycle phases, and depending on your requirements, you specify the goals to execute. A typical Maven build consists of two goals - clean package
.
clean
tells Maven to delete the files created from previous builds, while package
tells Maven to compile, test, and package the project.
Maven Lifecycle Phases are discussed in detail in this article.
Here is the output when you run mvn clean package
.
-> mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< io.devjournal.maven:first-maven-build >----------------
[INFO] Building first-maven-build 1.0
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.4.0:clean (default-clean) @ first-maven-build ---
[INFO] Deleting /home/thedevjournal/git/mastering-maven/first-maven-build/target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ first-maven-build ---
[INFO] skip non existing resourceDirectory /home/thedevjournal/git/mastering-maven/first-maven-build/src/main/resources
[INFO]
[INFO] --- compiler:3.13.0:compile (default-compile) @ first-maven-build ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 17] to target/classes
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ first-maven-build ---
[INFO] skip non existing resourceDirectory /home/thedevjournal/git/mastering-maven/first-maven-build/src/test/resources
[INFO]
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ first-maven-build ---
[INFO] Recompiling the module because of changed dependency.
[INFO] Compiling 1 source file with javac [debug release 17] to target/test-classes
[INFO]
[INFO] --- surefire:3.3.0:test (default-test) @ first-maven-build ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running io.devjournal.maven.firstbuild.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.033 s -- in io.devjournal.maven.firstbuild.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jar:3.4.2:jar (default-jar) @ first-maven-build ---
[INFO] Building jar: /home/thedevjournal/git/mastering-maven/first-maven-build/target/first-maven-build-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.511 s
[INFO] Finished at: 2025-02-02T20:10:27+05:30
[INFO] ------------------------------------------------------------------------
If you are running mvn clean package
for the very first time, you will see Maven download a lot of plugin jar files, just like the archetype plugin execution earlier. Every time, there is a new plugin that Maven executes, or an existing plugin for which there is a new updated, Maven will download the new jar files for the first time.
And with that, your first Maven build is complete.
Maven uses convention based approach, and hence, it defines a standard directory structure for the project to organize the files.
Familiarity with this structure is important for understanding how the project files are used by Maven to build and assemble the project.
Here is the video explaining these.
But, why limit ourselves to one project structure?
Because, this discipline allows you to be more productive. It might take a bit of time for you to get used to this structure, but the effort is worth it.
Prior to Maven, projects had very varied directory structure and if you worked on multiple projects, keeping track of files across these projects, would have been really difficult.
Maven made all of this simpler, by having a consistent project structure across projects. So, even if you moved to a different organization or worked on an open source project, you will feel completely at home and navigating the project files would be a walk in the park.
With this consistent project structure, Maven plugins can easily assume the location of certain files that they need for execution. That means you can just include the plugin and they will just work, out of the box. You donβt need to configure anything specific for most cases. It really, really reduces the time to get your builds running.
Letβs now look at a standard directory structure for a Maven Project.
The first and foremost, maven configuration file - pom.xml
. This should be located in your projectβs root directory or project’s home directory.
In this directory, you also will have src
folder that will contain all the files that, Maven plugins will use.
Below, is the example of the project’s home directory.
-> tree . -L 1
.
βββ pom.xml
βββ src
Letβs see how src
folder is laid out, to store the files.
src
For all of your Application code files, they need to be placed inside the main
directory of src
. Within the main
directory, you need to put the files inside the language specific folder.
So, your java files will be stored in src/main/java
and your scala
or kotlin
files will be stored at src/main/scala
or src/main/kotlin
respectively.
Within each of these directories, you have your regular package structure, that is unique to your application.
Here is an example.
-> tree .
.
βββ pom.xml
βββ src
| +-----------------------------------+
βββ|ββ main |
|Β βββ java |
|Β βΒ Β βββ io |
|Β βΒ Β βββ devjournal |
|Β βΒ Β βββ maven |
|Β βΒ Β βββ App.java |
|Β βββ kotlin |
|Β βββ scala |
+-----------------------------------+
For storing the application configuration files, like property configs, yaml configs, xml configs, or any other file that your application needs to use from classpath when its run, you need to store those in resources
folder inside main
directory.
So, full path is src/main/resources
.
-> tree .
.
βββ pom.xml
βββ src
ββββββ main
Β βββ java
Β βββ kotlin
Β βββ scala
+--|--------------------------------+
| βββ resources |
Β Β | Β Β βββ application.properties |
+-----------------------------------+
If you working on a web application, you need to store your html, css, javascript, jsp, etc. They are stored in src/main/webapp
. The directory structure inside webapp
should confirm to Java Servlet Specification so that these can be packaged correctly and gets deployed correctly on Application servers.
-> tree .
.
βββ pom.xml
βββ src
ββββββ main
Β βββ java
Β βββ kotlin
Β βββ scala
βββ resources
+--|--------------------------------+
|Β βββ webapp |
|Β βββ META-INF |
|Β βββ resources |
|Β βΒ Β βββ css |
|Β βΒ Β βββ images |
|Β βΒ Β βββ js |
|Β βββ WEB-INF |
|Β βββ jsp |
|Β βββ web.xml |
+-----------------------------------+
When we talk about files for testing, Maven expects these to be stored in a separate directory - test
inside src
folder.
And for Test class files for your source classes, the structure is similar to files under src/main
. So, if you have application Java class files under src/main/java
, then you need to place your test classes for these at src/test/java
.
Similarly, for other language class files for scala, kotlin and groovy.
-> tree .
.
βββ pom.xml
βββ src
ββββββ main
| Β βββ java
| Β βββ kotlin
| Β βββ scala
| βββ resources
| Β βββ webapp
| +--------------------------------------+
βββ|β test |
| βββ java |
| | βββ io |
| | βββ devjournal |
| | βββ maven |
| | βββ AppTest.java |
| βββ kotlin |
| βββ scala |
+--------------------------------------+
And if you require any test specific configuration files, then you need to store those in resources
folder in your src/test
folder. Again, similar to what the structure is for src/main
.
-> tree .
.
βββ pom.xml
βββ src
ββββββ main
| Β βββ java
| Β βββ kotlin
| Β βββ scala
| βββ resources
| Β βββ webapp
|
βββββ test
βββ java
βββ kotlin
βββ scala
+--|-------------------------------------+
| βββ resources |
Β Β | Β Β βββ application-test.properties |
+----------------------------------------+
If you have some integration tests that maven needs to run, Maven expects you to store these in a separate directory inside src
. It is src/it
, short form for integration test.
The directory structure of integration test folder is exactly similar to that of src/main
or src/test
. You get language specific folders to store your integration test class files and an additional resources folder to store any configuration files that you might need during the integration tests.
-> tree .
.
βββ pom.xml
βββ src
ββββββ main
ββββββ test
| +-----------------------+
βββ|β it |
| βββ java |
| βββ kotlin |
| βββ scala |
| | |
| βββ resources |
+-----------------------+
As you know, Maven can generate a project site for your application. To facilitate this, maven expects you to store these files in a separate folder called site
inside the src
folder.
The site
directory contains a site.xml
that defines how Maven should build the site. To store the site pages, maven provides different folders for each supported markup language.
-> tree .
.
βββ pom.xml
βββ src
ββββββ main
ββββββ test
ββββββ it
| +----------------------+
βββ|β site |
| βββ apt |
| βββ fml |
| βββ markdown |
| βββ xdoc |
| | |
| βββ site.xml |
+----------------------+
And finally, assembly
directory that tells Maven how to assemble your project. Without specifying any assembly configuration, maven assembles the project based on the default packaging from pom.xml
.
But if you want to assemble your project differently, you can define the configuration in the assembly
directory, and provide the configuration file to the maven-assembly plugin.
-> tree .
.
βββ pom.xml
βββ src
ββββββ main
ββββββ test
ββββββ it
ββββββ site
| +-------------------------+
βββ|β assembly |
| βββ distribution.xml |
+-------------------------+
And that is pretty much it. Again, adhering to Maven’s standard project structure streamlines project management and enhances productivity. By following these conventions, you can ensure consistency and ease of collaboration across different projects and teams.