Maven Complete Tutorial for Beginners
Tags: java, maven, beginners, programming
Published: 2020-12-19 21:58:11

---
title: Maven Complete Tutorial for Beginners
published: true
description: 
tags: #java #maven #beginners #programming
cover_image: https://i1.wp.com/programmingtechie.com/wp-content/uploads/2020/12/MAVEN-COMPLETE-TUTORIAL-1.png?resize=1024%2C576&ssl=1
---

**This post was originally published in [programmingtechie.com](https://programmingtechie.com/)**

If you are a Java Developer, your day to day activities while working on Java Projects includes writing code, compiling code, testing, packaging code in the form of an artifact like JAR, WAR or EAR and then deploying this artifact to an Application Server.

**Apache Maven** automates all the tasks which are mentioned above by minimizing the manual overhead.

In this tutorial, we will understand **What is Apache Maven?** and will cover all the concepts required for you to start using Maven in your Java Projects

If you are a visual learner like me, check out the below video tutorial:
{% youtube JhSBS2OpGdU %}

##Table of Contents
  * [What is Apache Maven](#chapter-1)
  * [Installing Maven](#chapter-2)
  * [Configure Maven Installation in IDE](#chapter-3)
  * [Create your First Maven Project](#chapter-4)
  * [Exploring Maven Folder Structure](#chapter-5)
  * [Maven Core Concepts](#chapter-6)
     * [Project Object Model](#chapter-7)
        * [Simple POM File](#chapter-8)
        * [Super POM File](#chapter-9)
        * [Effective POM File](#chapter-10)
     * [Dependencies](#chapter-11)
        * [Transitive Dependencies](#chapter-12)
        * [Excluding Dependencies](#chapter-13)
        * [SNAPSHOT and RELEASE dependencies](#chapter-14)
        * [Dependency Scopes](#chapter-15)
     * [Repositories](#chapter-16)
        * [Snapshot and Release Version Handling](#chapter-17)
  * [Maven Build Lifecycle](#chapter-18)
  * [Plugins and Goals](#chapter-19)
     * [Maven Compile Plugin](#chapter-20)
     * [Maven Surefire Plugin](#chapter-21)
     * [Maven Install Plugin](#chapter-22)
     * [Maven Deploy Plugin](#chapter-23)
     * [Other Maven Plugins](#chapter-24)
  * [Maven Multi Module Projects](#chapter-25)
     * [Creating Multi Module Project using IntelliJ](#chapter-26)
     * [Managing Dependencies inside Maven Multi Module Project](#chapter-27)
     * [Managing Plugins inside Maven Multi Module Project](#chapter-28)
  * [Using Profiles](#chapter-29)
  * [Conclusion](#chapter-30)

#What is Apache Maven ?<a name="chapter-1"></a>
**Apache Maven** is a Project Management Tool used to manage projects which are developed using JVM languages like Java, Scala, Groovy etc.

The major tasks of a Project Management Tool include:

* Building the Source Code
* Testing Source Code
* Packaging the Source Code into an Artifact (ZIP, JAR, WAR or EAR)
* Handles Versioning and Releases of the Artifacts
* Generating JavaDocs from the Source Code
* Managing Project Dependencies

Maven is also called as a **Build Tool** or a **Dependency Management Tool**

# Installing Maven<a name="chapter-1"></a>

You can download Maven from the website [here](https://maven.apache.org/download.cgi?Preferred=ftp://ftp.osuosl.org/pub/apache/). At the time of writing this tutorial, the latest version of Maven is 3.6.3.

Under the Files section, you can download Maven by clicking on the link which looks something like [apache-maven-3.6.3-bin.zip](https://mirrors.supportex.net/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zip)

Once you have downloaded and unzipped the folder, make sure to add the M2_HOME environment variable and to set the value of this variable to location of the unzipped folder.

After that make sure to set another environment variable called M2 which contains the value M2_HOME/bin

![M2 Environment Variable] (https://i1.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven_Env_Variables.png?w=626&ssl=1)

After that, make sure to update the Path variable also with the M2 environment variable.

![M2 Environment Variable inside Path] (https://i2.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven_Env_Variable_Path.png?w=527&ssl=1)

Once you completed the above steps, open a new terminal window and type `mvn –version` and you should see the output like below:

![Maven Version Check](https://i2.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven-Version-Check.png?w=1245&ssl=1)

# Configure Maven Installation in IDE<a name="chapter-2"></a>

The next step is to configure the maven installation inside your favorite IDE, in this tutorial we are going to use IntelliJ IDEA as the primary IDE.

You can download the community edition of this IDE [here](https://www.jetbrains.com/idea/download/#section=windows)

Once you have installed the IDE, on the Welcome Window click on the **Configure** button and select Settings and inside the Settings Window search for Maven and under the **Maven home directory** choose the Maven directory.

![IntelliJ](https://i0.wp.com/programmingtechie.com/wp-content/uploads/2020/12/configure-maven-1.png?w=802&ssl=1)

![Configure Maven](https://i2.wp.com/programmingtechie.com/wp-content/uploads/2020/12/configure-maven-2.png?w=982&ssl=1)

Click on **Apply** and then **OK**

You configured Maven successfully in your IDE. Now it’s time to create our first Maven Project.

# Create your First Maven Project<a name="chapter-3"></a>

In IntelliJ, click on **New Project** and in the window, select **Maven** to the left side and click on **Next**.

Then enter your project name and if you expand the section **Artifact Coordinates**.

You will see the fields **GroupId**, **ArtifactId** and **Version**.

* A GroupId is like a identifier for your project which usually follows the Java Package naming convention, so in our example IntelliJ has by default added the value org.example but you can add any value you like.
* An ArtifactId is the name of the project you are creating
* A Version is a unique number which identifies the version of our project.

![Artifact Coordinates](https://i2.wp.com/programmingtechie.com/wp-content/uploads/2020/12/New-Project.png?w=1204&ssl=1)

Once you click on **Finish**, IntelliJ should open the project and the folder structure of the project will look something like the picture you see below.

![Maven Project Structure](https://i0.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven-Project-Structure.png?w=922&ssl=1)

# Exploring Maven Folder Structure<a name="chapter-4"></a>

Let’s have a look at the Folder Structure of the Maven Project we just created.

The **src** folder is the root for our application source code and tests. Then we have the following subfolders:

* The folder **src/main/java** contains the java source code, all the production code for our application resides here
* In the **src/main/resources** we will store all the files we are going to use in our project (example: Property Files, any files where we need to read in our application like XML, CSV etc.). If you are developing a web-application we will usually place all the static resources inside this folder.
* In the **src/test/java** folder we will store all the test classes in our project.
* There is another folder called **target** (currently not visible), which stores the compiled java class files. We will discuss about this in the coming sections
* And lastly, we have the **pom.xml** file which contains the metadata of the project dependencies.

#Maven Core Concepts<a name="chapter-5"></a>

## Project Object Model<a name="chapter-6"></a>

The **Project Object Model** File(also called as **pom.xml**) contains the meta-data of the project and is also responsible to manage dependencies and to configure plugins which helps us in automating many repetitive tasks.

Here is how a basic **pom.xml** file looks like:

```
<?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>org.example</groupId>
    <artifactId>maven-project</artifactId>
    <version>1.0-SNAPSHOT</version>  
</project>
```

* **project** is the top level tag of our **pom.xml** file, which encapsulates all the information related to our Maven Project.
* **modelVersion** represents what version of POM you are using. The modelVersion for Maven 3 is always 4.0. This will never change unless you are using another major version of Maven.

Now as we know what is a POM file, let’s have a look at different type’s of POM files. We have basically 3 types of POM files:

* Simple POM file
* Super POM file
* Effective POM file

### Simple POM File<a name="chapter-7"></a>
This is the same file(**pom.xml**) which was generated in the previous section. It only contains information which is relevant to our current project.

### Super POM File<a name="chapter-8"></a>
A **Super POM File** is a parent for all the **Simple POM files**, it contains a set of default configuration which is shared by all the **Simple POM** files.

You can find the **Super POM** file inside the Maven installation directory under the path **M2_HOME/lib** and inside the JAR file **maven-model-builder-XXX.jar** where XXX represents the version of the maven version you are using.

We can find it under the package name **org.apache.maven.model** under the file name **pom-4.0.0.xml**.

> **CAUTION**: You should never try to edit the Super POM as it contains sensible defaults from Maven.

### Effective POM File<a name="chapter-9"></a>
An **Effective POM File** is nothing but a combination of **Simple POM** and **Super POM** File’s.

It’s just a way of checking all the information of the pom.xml files in one place.

We will have a look at how this will be helpful in the upcoming sections.

You can have a look at the **Effective POM** of our **pom.xml** file by typing the following command

`mvn help:effective-pom`

In IntelliJ, you can simply right click on the **pom.xml** file, select **Maven** -> **Show Effective POM**

## Dependencies<a name="chapter-10"></a>
If you are working on any non-trivial Java Project chances are that you are using many third party JAR files in your project to develop the application. These JAR files can be anything like a Framework or a Library. Examples include **Junit**, **Spring Framework**, **Selenium** etc.

These external libraries are called as **dependencies**. Maven provides an excellent way to specify and manage dependencies in our **pom.xml** file.

Without using Maven, you have to manually download the required JAR files from internet and add them one-by-one to the classpath of our project.

Maven provides a **dependencies** section inside the pom.xml where you can specify the information of the JAR you require in your project (**groupId**, **artifactId** and **version**). Once you have specified the required libraries, maven will automatically download these dependencies into our project and adds them to the classpath of our project.

Inside the **dependencies** section you can define each individual dependency like below inside the **pom.xml** file.

```
<?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>org.example</groupId>
    <artifactId>maven-project</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.5.2</version>
        </dependency>
    </dependencies>
</project>
```

We have defined **Junit5** as a **dependency** in our **pom.xml** file.

Notice that I have mentioned the tags **groupId**, **artifactId** and **version** to uniquely identify a dependency and by providing these values, Maven can automatically download these dependencies to our project.

In IntelliJ, make sure to click on the Refresh button under the Maven Tab in the right side, to force IntelliJ to initiate the download of the dependencies. Check the below image:

![Intellij Maven Dependencies](https://i0.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven-Dependencies-1.png?resize=1536%2C725&ssl=1)

In this way, you can provide all the dependencies needed in your project inside the pom.xml and Maven will automatically download them.

###Transitive Dependencies<a name="chapter-11"></a>
In the above example, you can observe that the **junit-jupiter-engine** indeed depends on other JAR files like **apiguardian-api**, **junit-platform-engine** and **junit-jupiter-api**

These JAR files are called **Transitive Dependencies**

![Maven Transitive Dependencies](https://i2.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Mavne-Dependencies-1.png?w=1229&ssl=1)

###Excluding Dependencies<a name="chapter-12"></a>
There are some instances where we will have some conflicts between the project dependencies and the transitive dependencies, at that time we can manually exclude the transitive dependency we don’t need.

For example, if you are developing your application using Spring Boot, there is a dependency called **spring-boot-starter-test** which will provide all the dependencies needed to test the Spring Boot applications.

This **spring-boot-starter-test** dependency contains **Junit 4** as the transitive dependency, as we are already using **Junit 5** we can exclude the transitive dependency like below:

```
<?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>org.example</groupId>
    <artifactId>maven-project</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.1.6.RELEASE</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>
```
> **NOTE**: The newer Spring Boot versions comes with JUnit 5 dependency, I purposely used the old version **2.1.6.RELEASE** as an example.

###SNAPSHOT and RELEASE dependencies<a name="chapter-13"></a>
A dependency can be categorized into two ways:
* SNAPSHOT
* RELEASE
A Snapshot Dependency resembles that the project version is under development.

If you are working on a Java project in a team, chances are that you are following some kind of iterative process where you go through the phases of development and then release the software at the end of the phase.

When the project is under development we generally use the **SNAPSHOT** dependencies, which looks something like **1.0-SNAPSHOT**

```
<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>org.example</groupId>
    <artifactId>maven-project</artifactId>
    <version>1.0-SNAPSHOT</version>
</project>
```
When the software is ready for release, we generally create a RELEASE version which looks like **1.0.RELEASE** (ex: **Spring Boot Starter Test dependency**)

```
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.1.6.RELEASE</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </exclusion>
    </exclusions>
</dependency>
```
###Dependency Scopes<a name="chapter-14"></a>
Each Maven Dependency can be categorized 6 different scopes.

Here are the list of scopes available:

* **compile**: This is the default scope if none is specified. Compile time dependencies are available in classpath of the project.
* **provided**: Similar to **compile** scope, but indicates that the JDK or the underlying container will provide the dependency at run-time. The dependency will be available at compile time, but not packaged into the artifact.
An example of the usage is the **javax.servlet-api** dependency
* **runtime**: The dependencies defined with this scope will be only available at runtime but not at compile time.
An example of the usage:
Imagine if you are using MySQL Driver inside your project, you can add the dependency with scope as runtime, to ensure that the JDBC API abstraction is used instead of MySQL Driver API during implementation.
If the source code includes any classes which is part of the MySQL JDBC API, then the code wont compile as the dependency is unavailable at compile time.
* **test**: Dependencies are only available at the time of running the tests, typical examples include Junit and TestNG
* **system**: It’s similar to the provided scope, but only difference is we need to explicitly mention where can the dependency be found in the system, using the **systemPath** tag:

`<systemPath>${basedir}/lib/some-dependency.jar</systemPath>`

##Repositories<a name="chapter-15"></a>
In the previous section, we saw how Maven manages and automatically downloads the dependencies.

These dependencies, are stored inside a special directory called **Repository**. There are basically 2 kinds of repositories:

* **Local Repository**
A Local Repository is a directory on the machine where the Maven is running.

The default location for the Local Repository is <User-Home>/.m2

In Windows, it looks like:
**C:\Users\<user-name>\.m2\repository**

* **Remote Repository**
A Remote Repository is a web-site where we can download Maven Dependencies. This can be a repository provided by Maven (repo.maven.org) or a custom repository setup inside an organization using software like [Artifactory](https://jfrog.com/artifactory/) or [Nexus](https://www.sonatype.com/nexus/repository-pro).
Now that we saw different types of repositories, let’s see how Maven Resolves the dependencies.

Now let’s see how Maven Resolves the dependencies.

![Maven Dependency Resolution](https://i1.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Repositories.png?w=631&ssl=1)

* When you define a dependency defined inside the **pom.xml** file, Maven first checks whether the dependency is already present in the **Local Repository** or not.
* If it is not, then it tries to connect to the **Remote Repository**, (Ex: **https://repo.maven.org**) and tries to download the dependencies, and store them inside the **Local Repository**.
We can define the **Remote Repository** in our pom.xml like below:
```
<repositories>
  <repository>
    <id>my-internal-site</id>
    <url>http://myserver/repo</url>
  </repository>
</repositories>
```
###Snapshot and Release Version Handling<a name="chapter-16"></a>
In the previous section, we learned that Maven first checks the **Local Repository** before downloading a dependency from **Remote Repository**.

When dealing with **SNAPSHOT** dependencies Maven **periodically** downloads the dependency from **Remote Repository** even though the dependency exists in **Local Repository**.

This is because **SNAPSHOT** dependencies are under heavy development, and are subjected to change frequently.

You can change this behavior by adding a **<snapshots>** section inside the **repositories** tag.

```
<repositories>
  <repository>
    <id>my-internal-site</id>
    <url>http://myserver/repo</url>
    <snapshots>
        <enabled>true</enabled>
        <updatePolicy>XXX</updatePolicy>
    </snapshots>
  </repository>
</repositories>
```
The value XXX inside the **updatePolicy** can be:

* **always**: Maven always checks for a latest version
* **daily**: This is the default value, as the name suggests it downloads the version once every day on the first run.
* **interval:XXX**: Checks every XXX minutes
* **never**: Never checks for the updates.

**RELEASE** versions on the other hand are more stable, and follow the usual dependency resolution.

# Maven Build Lifecycle<a name="chapter-17"></a>
Till now we learned about the Core Concepts of Maven, now it’s time to dive deep and understand how Maven builds our Java Project.

Maven follows a **Build Lifecycle** to well… build our project. 

This Lifecycle is divided into 3 parts:
* default
* clean
* site

Each Lifecycle is independent of each other and they can be executed together.

The default life cycle is divided into different phases like below:

* **validate** – verifies whether the pom.xml file is valid or not
* **compile** – compiles the source code inside the project
* **test** – runs unit-tests inside the project
* **package** – packages the source code into an artifact (ZIP, JAR, WAR or EAR)
* **integration-test**– executes tests marked as Integration Tests
* **verify** – checks whether the created package is valid or not.
* **install** – installs the created package into our Local Repository
* **deploy** – deploys the created package to the Remote Repository

The **clean** lifecycle is mainly responsible to clean the .class and meta-data generated by the above build phases.

The **site** lifecycle phase is responsible to generate Java Documentation.

All 3 lifecycles also contains some additional phases, which I am not going to cover in this tutorial, if you are interested you can refer to the [Maven Documentation](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#lifecycle-reference)

# Plugins and Goals<a name="chapter-18"></a>
To be able to execute these Lifecycle Phases, Maven provides us with **Plugins** to perform each task.

Each plugin is associated with a particular **Goal**

Let’s have a look at different Plugins and the associated Goals:

##Maven Compile Plugin<a name="chapter-19"></a>
The Maven Compile Plugin is responsible to compile our Java files into the .class files. It’s equivalent of running **javac <java-class-name>**

This plugin enables the **compile** phase of the default lifecycle.

You can add this plugin to your project by adding the below section to your **pom.xml** file under the **dependencies** 
section.

```
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
        </plugin>
    </plugins>
</build>
```
At the time of writing this tutorial, **Maven Compiler Plugin** is at version **3.8.1**

After adding the plugin to the project, you can activate the **compile** phase, by typing the below command:

```
$ mvn compiler:compile
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< org.example:maven-project >----------------------
[INFO] Building maven-project 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-cli) @ maven-project ---
[INFO] Nothing to compile - all classes are up to date
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.729 s
[INFO] Finished at: 2020-12-04T20:16:23+01:00
[INFO] ------------------------------------------------------------------------
```
In the above command the **compiler** is the name of the plugin and **compile** is the goal which triggers the lifecycle phase – compile

You can already see the message – **“Nothing to compile – all classes are up to date”**

As there are no Java Files in our project, there is nothing to compile, so let’s create a simple **HelloWorld.java** file

```
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}
```
If you try to compile again, you can see the following output:

```
$ mvn compiler:compile
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< org.example:maven-project >----------------------
[INFO] Building maven-project 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-cli) @ maven-project ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.123 s
[INFO] Finished at: 2020-12-04T20:14:55+01:00
[INFO] ------------------------------------------------------------------------
```
We can see the generated class files under the target folder which resides just under the project root folder.

![Maven Compile Folder Structure](https://i2.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Target-Folder.png?w=464&ssl=1)

If you have some Test files, those are also compiled using the **Compiler Plugin**.

To demonstrate that let’s create the below Test class under the src/test/java folder

```
public class HelloWorldTest {
    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld();
        System.out.println(helloWorld.say("Hi"));
    }
}
```
And here is how you can compile the test classes:
```
$ mvn compiler:testCompile
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< org.example:maven-project >----------------------
[INFO] Building maven-project 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-cli) @ maven-project ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\target\test-classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.319 s
[INFO] Finished at: 2020-12-04T20:23:59+01:00
[INFO] ------------------------------------------------------------------------
```
As you can see that a change has been detected by the **Maven Compiler Plugin** and it has compiled our Test classes to the **target/test-classes** folder

![Maven Test Compile](https://i0.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Target-Folder-with-Test-Classes.png?w=454&ssl=1)

As we are using IntelliJ, we can also use it to run the compilation, by clicking on the **compile** button under the **LifeCycle** dropdown as you see in the below image:

![Maven Intellij Lifecycle phases](https://i0.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Intellij-Compile-Plugin.png?w=616&ssl=1)

If you run the **compile** option you may see the below error:

```
[INFO] Compiling 1 source file to F:\maven-project\target\classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] Source option 6 is no longer supported. Use 7 or later.
[ERROR] Target option 6 is no longer supported. Use 7 or later.
```
This is because, by default the **Source** and **Target** Compiler Version is set to 1.5 in IntelliJ Configuration. You can add the below **configuration** to the compiler plugin to override this settings:

```
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>15</source>
                <target>15</target>
            </configuration>
        </plugin>
    </plugins>
</build>
```
You can pass many customized option to the Maven Compiler Plugin based on your needs, you can find the examples of the configuration in the [Apache Maven Compiler Plugin](https://maven.apache.org/plugins/maven-compiler-plugin/index.html) website

##Maven Surefire Plugin<a name="chapter-20"></a>
Using **Surefire Plugin**, we can run the tests inside our project by using the following command:

```
$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< org.example:maven-project >----------------------
[INFO] Building maven-project 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-project ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ maven-project ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-project ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory F:\maven-project\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ maven-project ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ maven-project ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running HelloWorldTest
Hi
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.014 s - in HelloWorldTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.797 s
[INFO] Finished at: 2020-12-04T20:54:49+01:00
[INFO] ------------------------------------------------------------------------
```
You can see that the HelloWorldTest.java file was executed successfully, and the you can also see how many Tests are executed successfully.

The Surefire Plugin generates Text and XML reports under the **target/surefire-reports** folder.

![Maven Tests](https://i1.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven-SureFire-Reports.png?w=830&ssl=1)

Similar to **Compiler Plugin**, you can also configure Surefire Plugin based on your needs.

Surefire Plugin by default includes all tests, if you have a bunch of tests, you can manually exclude some tests to be executed using below configuration:

```
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <excludes>HelloWorldTest.java</excludes>
    </configuration>
</plugin>
```
And if you run the **mvn test** command now, you can see that no tests are executed.

```
$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< org.example:maven-project >----------------------
[INFO] Building maven-project 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-project ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ maven-project ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-project ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory F:\maven-project\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ maven-project ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ maven-project ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.043 s
[INFO] Finished at: 2020-12-04T21:00:09+01:00
[INFO] ------------------------------------------------------------------------
```
##Maven Install Plugin<a name="chapter-21"></a>
This is used to package our source code into an artifact of our choice like a JAR and install it to our **Local Repository** which is **<USER_HOME>/.m2/repository** folder.

You can configure Maven Install Plugin by adding the below code:

```
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-install-plugin</artifactId>
    <version>2.5.2</version>
</plugin>
```
You can run the **install** phase of the lifecycle by typing the below command:

```
$ mvn install
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< org.example:maven-project >----------------------
[INFO] Building maven-project 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-project ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ maven-project ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-project ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory F:\maven-project\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ maven-project ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ maven-project ---
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ maven-project ---
[INFO] Building jar: F:\maven-project\target\maven-project-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ maven-project ---
[INFO] Installing F:\maven-project\target\maven-project-1.0-SNAPSHOT.jar to C:\Users\sai\.m2\repository\org\example\maven-project\1.0-SNAPSHOT\maven-project-1.0-SNAPSHOT.jar
[INFO] Installing F:\maven-project\pom.xml to C:\Users\sai\.m2\repository\org\example\maven-project\1.0-SNAPSHOT\maven-project-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.236 s
[INFO] Finished at: 2020-12-04T21:10:49+01:00
[INFO] ------------------------------------------------------------------------
```
By checking the above output, you can see that the install phase includes also the previous phases in the lifecycle, so as part of this phase maven:

* validates our pom.xml (**validate**)
* compiles our source code (**compile**)
* executes our tests (**test**)
* packages our source code into JAR (**package**)
* installs the JAR into our local repository (**install**)

You can see the JAR file in the below screenshot under the **target** folder.

![Maven Install Folder Structure](https://i0.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Intellij-Install-Plugin.png?w=759&ssl=1)

##Maven Deploy Plugin<a name="chapter-22"></a>
The Maven Deploy Plugin will deploy the artifact into a remote repository. The deploy goal of the plugin is associated with the **deploy** phase of the build lifecycle.

The plugin can be configured like below:
```
<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-deploy-plugin</artifactId>
   <version>2.8.2</version>
</plugin>
```
Before running the **deploy** phase of the lifecycle, we have to make sure that the remote repository details are configured inside our project.

We can configure this details inside the **distributionManagement** section:
```
<distributionManagement>
    <repository>
        <id>test-distribution</id>
        <name>distro name</name>
        <url>http://distrourl.com</url>
    </repository>
</distributionManagement>
```
To be able to connect to the remote repository, maven needs access to the credentials, which can be configured inside a special file called as **settings.xml** file.

This file is usually configured inside the **<USER_HOME>/.m2/** folder, which looks like something below:

```
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <id>test-distribution</id>
            <username>my_username</username>
            <password>my_password</password>
        </server>
    </servers>
</settings>
```
Maven also provides us a way to encrypt the credentials inside the **settings.xml** file, you can read about this here

You can run the **deploy** goal using the following command:
`$ mvn deploy`

Once you run this command, you will notice that it will run all the lifecycle phases up until deploy.

Although if you run this command in the example project, it will fail because the Remote Repository Details are invalid.

##Maven Clean Plugin<a name="chapter-23"></a>
Another important plugin in Maven is the **Maven Clean Plugin**, you saw that when running the above lifecycle phases, the generated files are stored under a folder called **target**.

Usually when building our source code we need to start of as a clean slate so that there are no inconsistencies in the generated class files or JAR.

For this reason we have the **clean** phase where we will delete all the contents inside the **target** folder. You can execute this phase by typing the below commands:

```
$ mvn clean
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< org.example:maven-project >----------------------
[INFO] Building maven-project 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven-project ---
[INFO] Deleting F:\maven-project\target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.204 s
[INFO] Finished at: 2020-12-04T21:19:12+01:00
[INFO] ------------------------------------------------------------------------
```
You can see that the target folder under our project is deleted successfully.

## Other Maven Plugins<a name="chapter-24"></a>
There are many other plugins in Maven world, to execute other phases in the Maven Build Lifecycle, you can check them out [here](https://maven.apache.org/plugins/index.html)

#Maven Multi Module Projects<a name="chapter-25"></a>
Till now we saw the Core Concepts of Maven, now it’s time to dive deep into some advanced concepts.

In the real world where we are building some non-trivial projects, the source code is going to be modularized (hopefully) and is divided into different sub projects.

To manage this effectively, Maven provides us Multi Module Projects where you can have nest different projects inside each other. We are basically creating a parent-child relationship between different Maven projects.

Basically, we have a **Parent Project** (Parent POM) which contains different **sub-projects** (**sub-modules**), each of which is again a normal Maven Project.

![Multi Module Project](https://i1.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven-Multi-Module-Project.png?w=506&ssl=1)

The **Parent POM** usually encapsulates other child’s and that’s why its packaged as a **POM** instead of usual packaing format’s like **JAR**.

If you recall the section **Project Object Model** , we discussed about **Super POM** which is basically a kind of **Parent POM** which encapsulates default settings configured by Maven for us.

##Creating Multi Module Project using IntelliJ<a name="chapter-26"></a>
We will see how to generate Multi Module Projects using our IntelliJ IDE.

To create the project, first right click on the project root folder and select **New** -> **Module** and click on **Next**.

![Maven Module Coordinates](https://i2.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven-Child-Project-1.png?w=1061&ssl=1)

Give a name to the child project and click on **Finish**.

![Maven Module Structure](https://i1.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven-Multi-Module-Project-Structure.png?w=730&ssl=1)

You can see the new project structure in the above picture after we created the **child project**.

Now if you open the **pom.xml** under the root folder, you can observe the following tags which are added by creating the maven module.

```
    <modules>
        <module>child-project-1</module>
    </modules>
```
We can create multiple projects in the same way and you can see all the modules will be listed one-by-one under the **modules** tag.

```
    <modules>
        <module>child-project-1</module>
        <module>child-project-2</module>
        <module>child-project-3</module>
    </modules>
```
As we create these 3 modules, having the **src** folder under the root project folder doesn’t make much sense, so let’s copy and paste this folder onto other child-projects, so that we have some code configured inside these modules.

This is how our project structure now looks like:
![Maven Multi Module Project Structure](https://i2.wp.com/programmingtechie.com/wp-content/uploads/2020/12/Maven-Multi-Module-Project-Structure-with-Code.png?w=944&ssl=1)

And if you check the **pom.xml** of **child-project-1**,**child-project-2** and **child-project-3**. You can see that the root project is configured as a parent project.

```
<?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">
    <parent>
        <artifactId>maven-project</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>child-project-1</artifactId>
 
 
</project>
```
Now you can build all the projects at once by running the **mvn install** under the Parent Project, and Maven scans through all the POMS and builds all of them one-by-one

```
$ mvn install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] maven-project                                                      [pom]
[INFO] child-project-1                                                    [jar]
[INFO] child-project-2                                                    [jar]
[INFO] child-project-3                                                    [jar]
[INFO]
[INFO] ---------------------< org.example:maven-project >----------------------
[INFO] Building maven-project 1.0-SNAPSHOT                                [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ maven-project ---
[INFO] Installing F:\maven-project\pom.xml to C:\Users\subra\.m2\repository\org\example\maven-project\1.0-SNAPSHOT\maven-project-1.0-SNAPSHOT.pom
[INFO]
[INFO] --------------------< org.example:child-project-1 >---------------------
[INFO] Building child-project-1 1.0-SNAPSHOT                              [2/4]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ child-project-1 ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ child-project-1 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\child-project-1\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ child-project-1 ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory F:\maven-project\child-project-1\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ child-project-1 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\child-project-1\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ child-project-1 ---
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ child-project-1 ---
[INFO] Building jar: F:\maven-project\child-project-1\target\child-project-1-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ child-project-1 ---
[INFO] Installing F:\maven-project\child-project-1\target\child-project-1-1.0-SNAPSHOT.jar to C:\Users\subra\.m2\repository\org\example\child-project-1\1.0-SNAPSHOT\child-project-1-1.0-SNAPSHOT.jar
[INFO] Installing F:\maven-project\child-project-1\pom.xml to C:\Users\subra\.m2\repository\org\example\child-project-1\1.0-SNAPSHOT\child-project-1-1.0-SNAPSHOT.pom
[INFO]
[INFO] --------------------< org.example:child-project-2 >---------------------
[INFO] Building child-project-2 1.0-SNAPSHOT                              [3/4]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ child-project-2 ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ child-project-2 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\child-project-2\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ child-project-2 ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory F:\maven-project\child-project-2\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ child-project-2 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\child-project-2\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ child-project-2 ---
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ child-project-2 ---
[INFO] Building jar: F:\maven-project\child-project-2\target\child-project-2-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ child-project-2 ---
[INFO] Installing F:\maven-project\child-project-2\target\child-project-2-1.0-SNAPSHOT.jar to C:\Users\subra\.m2\repository\org\example\child-project-2\1.0-SNAPSHOT\child-project-2-1.0-SNAPSHOT.jar
[INFO] Installing F:\maven-project\child-project-2\pom.xml to C:\Users\subra\.m2\repository\org\example\child-project-2\1.0-SNAPSHOT\child-project-2-1.0-SNAPSHOT.pom
[INFO]
[INFO] --------------------< org.example:child-project-3 >---------------------
[INFO] Building child-project-3 1.0-SNAPSHOT                              [4/4]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ child-project-3 ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ child-project-3 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\child-project-3\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ child-project-3 ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory F:\maven-project\child-project-3\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ child-project-3 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\child-project-3\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ child-project-3 ---
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ child-project-3 ---
[INFO] Building jar: F:\maven-project\child-project-3\target\child-project-3-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ child-project-3 ---
[INFO] Installing F:\maven-project\child-project-3\target\child-project-3-1.0-SNAPSHOT.jar to C:\Users\subra\.m2\repository\org\example\child-project-3\1.0-SNAPSHOT\child-project-3-1.0-SNAPSHOT.jar
[INFO] Installing F:\maven-project\child-project-3\pom.xml to C:\Users\subra\.m2\repository\org\example\child-project-3\1.0-SNAPSHOT\child-project-3-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for maven-project 1.0-SNAPSHOT:
[INFO]
[INFO] maven-project ...................................... SUCCESS [  0.252 s]
[INFO] child-project-1 .................................... SUCCESS [  1.534 s]
[INFO] child-project-2 .................................... SUCCESS [  0.430 s]
[INFO] child-project-3 .................................... SUCCESS [  0.351 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.699 s
[INFO] Finished at: 2020-12-04T21:58:10+01:00
[INFO] ------------------------------------------------------------------------
```
You can see that Maven built all the projects and provided us a nice report of the **Build Status** of each project.

Maven uses something called as a **Reactor** which is responsible to scan the whole project and identify the parent and child maven projects. If there are any dependencies, then Reactor makes sure to execute the projects in the required order.

For example, if **child-project-2** is dependent on **child-project-3** , then Maven Reactor makes sure to first build **child-project-3** and then **child-project-2**.

##Managing Dependencies inside Maven Multi Module Project<a name="chapter-27"></a>
When you are working with Multiple Maven Modules, you may be working with different dependencies in different modules, and chances are that you may be using similar dependencies in multiple modules.

Maven provides us a way to effectively manage the dependencies in your project by allowing us to define the dependencies in centralized location (**parent project**) and use those dependencies across the different child projects.

This minimizes the dependency version mismatch across multiple projects, as we have a single place we can manage all the dependencies and its versions.

Let’s see how to do that in our example project.

I am going to move all the dependencies which are defined inside the parent project into the **dependencyManagement** section, like below:
```
<?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>org.example</groupId>
    <artifactId>maven-project</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>child-project-1</module>
        <module>child-project-2</module>
        <module>child-project-3</module>
    </modules>
 
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-engine</artifactId>
                <version>5.5.2</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <version>2.1.6.RELEASE</version>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <configuration>
                    <excludes>HelloWorldTest.java</excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>
        </plugins>
    </build>
</project>
```
The change in the pom.xml is minor, we just moved the dependencies under the **dependencyManagement** tag.

Now if you analyze the dependencies under the **child-project-1** you can see that it’s empty.

```
mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------< org.example:child-project-1 >---------------------
[INFO] Building child-project-1 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ child-project-1 ---
[INFO] org.example:child-project-1:jar:1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.871 s
[INFO] Finished at: 2020-12-05T20:23:59+01:00
[INFO] ------------------------------------------------------------------------
```
This is because we moved all the dependencies inside the Parent POM into **dependencyManagement** section, now to access any dependencies the **Child Projects** should define them manually inside their **pom.xml**.

In this way, the child projects can have only the dependencies they need inside the **pom.xml**.

Now, let’s go ahead and add the **junit-jupiter** dependencies inside the **child-project-1** and see what happens.
```
<?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">
    <parent>
        <artifactId>maven-project</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>child-project-1</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
        </dependency>
    </dependencies>
</project>
```

```
$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------< org.example:child-project-1 >---------------------
[INFO] Building child-project-1 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ child-project-1 ---
[INFO] org.example:child-project-1:jar:1.0-SNAPSHOT
[INFO] \- org.junit.jupiter:junit-jupiter-engine:jar:5.5.2:compile
[INFO]    +- org.apiguardian:apiguardian-api:jar:1.1.0:compile
[INFO]    +- org.junit.platform:junit-platform-engine:jar:1.5.2:compile
[INFO]    |  +- org.opentest4j:opentest4j:jar:1.2.0:compile
[INFO]    |  \- org.junit.platform:junit-platform-commons:jar:1.5.2:compile
[INFO]    \- org.junit.jupiter:junit-jupiter-api:jar:5.5.2:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.930 s
[INFO] Finished at: 2020-12-05T20:27:26+01:00
[INFO] ------------------------------------------------------------------------
```
You can now see that the **junit-jupiter** dependency is available inside the **child-project-1**.

##Managing Plugins inside Maven Multi Module Project<a name="chapter-28"></a>
We can also manage Plugins inside our Maven Multi Module project, similar to the dependencies.

To Manage Plugins, we have the **pluginManagement** section inside the **pom.xml** and each child project can chose the plugin it needs.

This is how our parent **pom.xml** looks like after introducing the **pluginManagement**.
```
<?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>org.example</groupId>
    <artifactId>maven-project</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>child-project-1</module>
        <module>child-project-2</module>
        <module>child-project-3</module>
    </modules>
 
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-engine</artifactId>
                <version>5.5.2</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <version>2.1.6.RELEASE</version>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <source>11</source>
                        <target>11</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.2</version>
                    <configuration>
                        <excludes>HelloWorldTest.java</excludes>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
```
#Using Profiles<a name="chapter-29"></a>
Profiles can be used in Maven to created customized build configurations. This means customizing the behavior of our builds based on specific conditions.

For example: Sometimes we need to test whether the source code packaging is working correctly or not, in that case we can skip the test execution by activating the **skip.tests** property like below:

```
<profile>
    <id>skip-tests</id>
    <properties>
        <maven.test.skip>true</maven.test.skip>
    </properties>
</profile>
```
Now we can try to run the build by specifying which profile to activate using the **-P** flag.
```
$ mvn -Pskip-tests clean install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] maven-project                                                      [pom]
[INFO] child-project-1                                                    [jar]
[INFO] child-project-2                                                    [jar]
[INFO] child-project-3                                                    [jar]
[INFO]
[INFO] ---------------------< org.example:maven-project >----------------------
[INFO] Building maven-project 1.0-SNAPSHOT                                [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven-project ---
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ maven-project ---
[INFO] Installing F:\maven-project\pom.xml to C:\Users\subra\.m2\repository\org\example\maven-project\1.0-SNAPSHOT\maven-project-1.0-SNAPSHOT.pom
[INFO]
[INFO] --------------------< org.example:child-project-1 >---------------------
[INFO] Building child-project-1 1.0-SNAPSHOT                              [2/4]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ child-project-1 ---
[INFO] Deleting F:\maven-project\child-project-1\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ child-project-1 ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ child-project-1 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\child-project-1\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ child-project-1 ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ child-project-1 ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ child-project-1 ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ child-project-1 ---
[INFO] Building jar: F:\maven-project\child-project-1\target\child-project-1-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ child-project-1 ---
[INFO] Installing F:\maven-project\child-project-1\target\child-project-1-1.0-SNAPSHOT.jar to C:\Users\subra\.m2\repository\org\example\child-project-1\1.0-SNAPSHOT\child-project-1-1.0-SNAPSHOT.jar
[INFO] Installing F:\maven-project\child-project-1\pom.xml to C:\Users\subra\.m2\repository\org\example\child-project-1\1.0-SNAPSHOT\child-project-1-1.0-SNAPSHOT.pom
[INFO]
[INFO] --------------------< org.example:child-project-2 >---------------------
[INFO] Building child-project-2 1.0-SNAPSHOT                              [3/4]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ child-project-2 ---
[INFO] Deleting F:\maven-project\child-project-2\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ child-project-2 ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ child-project-2 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\child-project-2\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ child-project-2 ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ child-project-2 ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ child-project-2 ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ child-project-2 ---
[INFO] Building jar: F:\maven-project\child-project-2\target\child-project-2-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ child-project-2 ---
[INFO] Installing F:\maven-project\child-project-2\target\child-project-2-1.0-SNAPSHOT.jar to C:\Users\subra\.m2\repository\org\example\child-project-2\1.0-SNAPSHOT\child-project-2-1.0-SNAPSHOT.jar
[INFO] Installing F:\maven-project\child-project-2\pom.xml to C:\Users\subra\.m2\repository\org\example\child-project-2\1.0-SNAPSHOT\child-project-2-1.0-SNAPSHOT.pom
[INFO]
[INFO] --------------------< org.example:child-project-3 >---------------------
[INFO] Building child-project-3 1.0-SNAPSHOT                              [4/4]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ child-project-3 ---
[INFO] Deleting F:\maven-project\child-project-3\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ child-project-3 ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ child-project-3 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to F:\maven-project\child-project-3\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ child-project-3 ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ child-project-3 ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ child-project-3 ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ child-project-3 ---
[INFO] Building jar: F:\maven-project\child-project-3\target\child-project-3-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ child-project-3 ---
[INFO] Installing F:\maven-project\child-project-3\target\child-project-3-1.0-SNAPSHOT.jar to C:\Users\subra\.m2\repository\org\example\child-project-3\1.0-SNAPSHOT\child-project-3-1.0-SNAPSHOT.jar
[INFO] Installing F:\maven-project\child-project-3\pom.xml to C:\Users\subra\.m2\repository\org\example\child-project-3\1.0-SNAPSHOT\child-project-3-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for maven-project 1.0-SNAPSHOT:
[INFO]
[INFO] maven-project ...................................... SUCCESS [  0.327 s]
[INFO] child-project-1 .................................... SUCCESS [  1.208 s]
[INFO] child-project-2 .................................... SUCCESS [  0.205 s]
[INFO] child-project-3 .................................... SUCCESS [  0.167 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.055 s
[INFO] Finished at: 2020-12-05T23:00:13+01:00
[INFO] ------------------------------------------------------------------------
```
If you observe the logs carefully, you can see that the test-execution is skipped:

```
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ child-project-3 ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ child-project-3 ---
[INFO] Building jar: F:\maven-project\child-project-3\target\child-project-3-1.0-SNAPSHOT.jar
```
This is just a simple usage of the profiles, you can configure multiple profiles in our project to customize the build behavior.

# Conclusion<a name="chapter-30"></a>

So we came to the end of this tutorial, I hope this tutorial improved your understanding of Maven.

#### If you like this article please make sure to share it with your friends and colleagues who wants to learn about Apache Maven. You can follow me through my [blog](https://https://programmingtechie.com/), [Youtube Channel](https://www.youtube.com/channel/UCD20RZV_WHQImisCW2QZwDw) and [Twitter](https://twitter.com/sai90_u)