Theme NexT works best with JavaScript enabled
0%

Apache Maven Manual


IMPORTANT:
Some of the content here is a personal summary/abbreviation of contents on the Offical Apache Maven Guide. Feel free to refer to the official site if you think some of the sections written here are not clear.


Apache Maven Introduction

  • *Q: What is Apache Maven used for? *

In a nutshell Maven is an attempt to apply patterns to a project’s build infrastructure in order to promote comprehension and productivity by providing a clear path in the use of best practices. Maven is essentially a project management and comprehension tool and as such provides a way to help with managing:

  • Builds
  • Documentation
  • Reporting
  • Dependencies
  • SCMs
  • Releases
  • Distribution

Maven can provide benefits for your build process by employing standard conventions and practices to accelerate your development cycle while at the same time helping you achieve a higher rate of success.

Installing Maven

Please follow Apache Maven Guide

Creating a Project (QuickStart)

First you might want to create a workspace folder where all your Maven project resides. Then, you could navigate to that folder’s directory and run:

1
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false

where the -DartifactId=my-app would be the new folder with name my-app under that directory you created.

Note:

  • If you have just installed Maven, it may take a while on the first run.

After it completes the setup, you can switch to that folder my-app and look at what’s created by Maven:

1
cd my-app

Under this directory you will notice the following standard project structure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
my-app
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- com
| `-- mycompany
| `-- app
| `-- App.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java

where:

  • src/main/java directory contains the project source code
  • src/test/java directory contains the test source code
  • pom.xml file is the project’s Project Object Model, or POM.

Configuring for Java 9 or Later

By default your version of Maven might use an old version of the maven-compiler-plugin that is not compatible with Java 9 or later versions. To target Java 9 or later, you should at least use version 3.6.0 of the maven-compiler-plugin and set the maven.compiler.release property to the Java release you are targetting (e.g. 9, 10, 11, 12, etc.).

In the following example, we have configured our Maven project to use version 3.8.1 of maven-compiler-plugin and target Java 11. You should be able to edit it in the pom.xml file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<properties>
<maven.compiler.release>11</maven.compiler.release>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>13</source>
<target>13</target>
</configuration>
</plugin>
</plugins>
</build>

Build the Project

Maven is based around the central concept of a build lifecycle, which consists of a number of phases. (Each of these build lifecycles is defined by a different list of build phases, wherein a build phase represents a stage in the lifecycle.)

For example, the default lifecycle comprises of the following phases (for a complete list of the lifecycle phases, refer to the Lifecycle Reference):

  • validate - validate the project is correct and all necessary information is available
  • compile - compile the source code of the project
  • test - test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
  • package - take the compiled code and package it in its distributable format, such as a JAR.
  • integration-test: process and deploy the package if necessary into an environment where integration tests can be run
  • verify - run any checks on results of integration tests to ensure quality criteria are met
  • install - install the package into the local repository, for use as a dependency in other projects locally
  • deploy - done in the build environment, copies the final package to the remote repository for sharing with other developers and projects.

At this point, since you haven’t added anthing in the folder, you could directly do

1
mvn package

which, for Maven, when a phase is given, it will execute every phase in the sequence up to and including the one defined. For example, if we execute the compile phase, the phases that actually get executed are:

  • validate
    • generate-sources
    • process-sources
    • generate-resources
    • process-resources
  • compile

In the case where we executed mvn package, the command line will print out various actions, and end with the following:

1
2
3
4
5
6
7
 ...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.953 s
[INFO] Finished at: 2019-11-24T13:05:10+01:00
[INFO] ------------------------------------------------------------------------

Note:

  • Unlike the first command executed (archetype:generate) you may notice the second is simply a single word - package. The difference is that the first one is a goal (i.e. the prefix archetype is the plugin that provides the goal archetype:generate. Maven is - at its heart - a plugin execution framework; all work is done by plugins), where as the second one is a phase.
  • After you run the mvn package, you will see that it created a new folder target, in which there will be a packaged JAR file that is the snap-shot of the project (in this case, MAVEN starts with a Hello World java file)

Now, since you see that in the standard lifecycle, package already included compile phase, it means we could test the newly compiled and packaged JAR:

1
java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App

where

  • -cp, or CLASSPATH (where the JVM will look for the .class file. In this case, the file is packaged in the my-app-1.0-SNAPSHOT.jar), is used as an option to the Java command that specifies the location of classes and packages which are defined by the user, for example, a list of directories, JAR archives and ZIP archives to search for class files.
  • com.mycompany.app.App is the java file that is created by MAVEN and packaged into target/my-app-1.0-SNAPSHOT.jar

Running Maven Tools

Although hardly a comprehensive list, these are the most common default lifecycle phases executed, also shown in the section Build the Project

  • validate
  • compile
  • test
  • package
  • integration-test
  • verify
  • install
  • deploy

There are two other Maven lifecycles of note beyond the default list above. They are:

  • clean: cleans up artifacts created by prior builds
  • site: generates site documentation for this project

Phases are actually mapped to underlying goals (A build phase is made up of a set of goals. Maven goals represent a specific task that contributes to the building and managing of a project). The specific goals executed per phase is dependent upon the packaging type of the project. For example, package executes jar:jar if the project type is a JAR, and war:war if the project type is - you guessed it - a WAR.

An interesting thing to note is that phases and goals may be executed in sequence.

1
mvn clean dependency:copy-dependencies package

This command will clean the project, copy dependencies, and package the project (executing all phases up to package, of course).

Generating a Site

This site will contain information about your project, organized by MAVEN:

1
mvn site

This phase generates a site based upon information on the project’s pom. You can look at the documentation generated under target/site.

Creating a Project

Different from the quickstart you could use, you could also create a standard project by:

1
2
3
4
mvn -B archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DgroupId=com.mycompany.app \
-DartifactId=<yourProjectName>

Then, in the directory you created, you could look at the POM file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

The POM is the basic unit of work in Maven. This is important to remember because Maven is inherently project-centric in that everything revolves around the notion of a project. In short, the POM contains every important piece of information about your project and is essentially one-stop-shopping for finding anything related to your project.

This is a very simple POM but still displays the key elements every POM contains, so let’s walk through each of them to familiarize you with the POM essentials:

  • project This is the top-level element in all Maven pom.xml files.
  • modelVersion This element indicates what version of the object model this POM is using. The version of the model itself changes very infrequently but it is mandatory in order to ensure stability of use if and when the Maven developers deem it necessary to change the model.
  • groupId This element indicates the unique identifier of the organization or group that created the project. The groupId is one of the key identifiers of a project and is typically based on the fully qualified domain name of your organization. For example org.apache.maven.plugins is the designated groupId for all Maven plugins.
  • artifactId This element indicates the unique base name of the primary artifact being generated by this project. The primary artifact for a project is typically a JAR file. Secondary artifacts like source bundles also use the artifactId as part of their final name. A typical artifact produced by Maven would have the form <artifactId>-<version>.<extension> (for example, my-app-1.0.jar).
  • packaging This element indicates the package type to be used by this artifact (e.g. JAR, WAR, EAR, etc.). This not only means if the artifact produced is JAR, WAR, or EAR but can also indicate a specific lifecycle to use as part of the build process. (The lifecycle is a topic we will deal with further on in the guide. For now, just keep in mind that the indicated packaging of a project can play a part in customizing the build lifecycle.) The default value for the packaging element is JAR so you do not have to specify this for most projects.
  • version This element indicates the version of the artifact (your end product) generated by the project. Maven goes a long way to help you with version management and you will often see the SNAPSHOT designator in a version, which indicates that a project is in a state of development. We will discuss the use of snapshots and how they work further on in this guide.
  • name This element indicates the display name used for the project (by default it will be the same name as artifactId). This is often used in Maven’s generated documentation.
  • url This element indicates where the project’s site can be found. This is often used in Maven’s generated documentation.
  • description This element provides a basic description of your project. This is often used in Maven’s generated documentation.

Note:

  • The value of the version tag in the pom.xml file shown below has the suffix: -SNAPSHOT. The SNAPSHOT value refers to the ‘latest’ code along a development branch, and provides no guarantee the code is stable or unchanging. Conversely, the code in a 'release' version (any version value without the suffix SNAPSHOT) is unchanging. In other words, a SNAPSHOT version is the ‘development’ version before the final ‘release’ version. The SNAPSHOT is “older” than its release.

For more complete understanding of a POM visit Apache Maven POM Guide

After the archetype generation of your first project you will also notice the same source tree structure you had above in the quickstart project created:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
my-app
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- com
| `-- mycompany
| `-- app
| `-- App.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java

Compiling Project Source Code

Change to the directory where pom.xml is created by archetype:generate (this will be the default directory we are using for MAVEN commands) and execute the following command to compile your application sources:

1
mvn compile

Upon executing this command you should see output like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Quick Start Archetype
[INFO] task-segment: [compile]
[INFO] ----------------------------------------------------------------------------
[INFO] artifact org.apache.maven.plugins:maven-resources-plugin: \
checking for updates from central
...
[INFO] artifact org.apache.maven.plugins:maven-compiler-plugin: \
checking for updates from central
...
[INFO] [resources:resources]
...
[INFO] [compiler:compile]
Compiling 1 source file to <dir>/my-app/target/classes
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
[INFO] Total time: 3 minutes 54 seconds
[INFO] Finished at: Fri Sep 23 15:48:34 GMT-05:00 2005
[INFO] Final Memory: 2M/6M
[INFO] ----------------------------------------------------------------------------

The first time you execute this (or any other) command, Maven will need to download all the plugins and related dependencies it needs to fulfill the command. This can take quite a while. If you execute the command again, Maven will now have what it needs, so it won’t need to download anything new and will be able to execute the command much more quickly.

Note:

  • If you ran into error running this command, it might be cause because the code is not for the default compiler used by MAVEN. You can specify it similarly in the section [Configuing for Java 9 or Later](#
    re-Java-9), by adding those before the root element ends:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <dependencies> 
    ...
    </dependencies>
    <build>
    <plugins>
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
    <source>13</source>
    <target>13</target>
    </configuration>
    </plugin>
    </plugins>
    </build>
    As you can see from the output, the compiled classes were placed in ${basedir}/target/classes, which is another standard convention employed by Maven.

Testing Project Source Code

Now you’re successfully compiling your application’s sources and now you’ve got some unit tests that you want to compile and execute (because every programmer always writes and executes their unit tests nudge nudge wink wink).

Execute the following command:

1
mvn test

Note:

  • Maven downloads more dependencies this time. These are the dependencies and plugins necessary for executing the tests (it already has the dependencies it needs for compiling and won’t download them again).
  • Before compiling and executing the tests Maven compiles the main code (in case there are some changes. In this case all these classes are up to date because we haven’t changed anything since we compiled last).

If you simply want to compile your test sources (but not execute the tests), you can execute the following:

1
2

mvn test-compile

Packaging into a Jar File

Making a JAR file is straight forward enough and can be accomplished by executing the following command:

1
mvn package

If you take a look at the POM for your project you will notice the packaging element is set to jar. This is how Maven knows to produce a JAR file from the above command.

The generated file will be in ${basedir}/target directory and you will see the generated JAR file there as well.

Installing into Local Repository

If you want to install the artifact you’ve generated (the JAR file) in your local repository (${user.home}/.m2/repository; for Windows,C:\Users\<Username>\.m2\repository is the default location). For more information on repositories you can refer to Apache Maven Introduction to Repositories but let’s move on to installing our artifact! To do so execute the following command:

1
mvn install

Upon executing this command you should see the following output:

Upon executing this command you should see the following output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Quick Start Archetype
[INFO] task-segment: [install]
[INFO] ----------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] [compiler:compile]
Compiling 1 source file to <dir>/my-app/target/classes
[INFO] [resources:testResources]
[INFO] [compiler:testCompile]
Compiling 1 source file to <dir>/my-app/target/test-classes
[INFO] [surefire:test]
[INFO] Setting reports dir: <dir>/my-app/target/surefire-reports

-------------------------------------------------------
T E S T S
-------------------------------------------------------
[surefire] Running com.mycompany.app.AppTest
[surefire] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.001 sec

Results :
[surefire] Tests run: 1, Failures: 0, Errors: 0

[INFO] [jar:jar]
[INFO] Building jar: <dir>/my-app/target/my-app-1.0-SNAPSHOT.jar
[INFO] [install:install]
[INFO] Installing <dir>/my-app/target/my-app-1.0-SNAPSHOT.jar to \
<local-repository>/com/mycompany/app/my-app/1.0-SNAPSHOT/my-app-1.0-SNAPSHOT.jar
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
[INFO] Total time: 5 seconds
[INFO] Finished at: Tue Oct 04 13:20:32 GMT-05:00 2005
[INFO] Final Memory: 3M/8M
[INFO] ----------------------------------------------------------------------------

Note that the surefire plugin (which executes the test) looks for tests contained in files with a particular naming convention. By default the tests included are:

  • **/*Test.java
  • **/Test*.java
  • **/*TestCase.java

And in the end you can find your files in C:\Users\<Username>\.m2\repository\com\mycompany\app\ (for Windows)

Other Useful Phases in Maven

One of the highly prized features of Maven is: without any work on your part this POM has enough information to generate a web site for your project! You will most likely want to customize your Maven site but if you’re pressed for time all you need to do to provide basic information about your project is execute the following command:

1
mvn site

There are plenty of other standalone goals that can be executed as well (again only with this POM file), for example:

1
mvn clean

This will remove the target directory with all the build data before starting so that it is fresh.

Using Plugins in Maven

Whenever you want to customise the build for a Maven project, this is done by adding or reconfiguring plugins.

For this example, we will configure the Java compiler to allow JDK 5.0 sources (we have in fact done this already when we configure for Java 9.0 or later). This is as simple as adding this to your POM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
...

You’ll notice that all plugins in Maven look much like a dependency - and in some ways they are. This plugin will be automatically downloaded and used - including a specific version if you request it (the default is to use the latest available).

To find out what configuration is available for a plugin, you can see the Apache Maven Plugins List and navigate to the plugin and goal you are using. For general information about how to configure the available parameters of a plugin, have a look at the Apache Maven Guide to Configuring Plugins.

Adding Files/Resources to My Jar

Another common use case that can be satisfied which requires no changes to the POM that we have above is packaging resources in the JAR file. For this common task, Maven again relies on the Standard Directory Layout.

You see below in our example we have added the directory ${basedir}/src/main/resources into which we place any resources/files we wish to package in our JAR. The simple rule employed by Maven is this: any directories or files placed within the ${basedir}/src/main/resources directory are packaged in your JAR with the exact same structure starting at the base of the JAR

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
my-app
|-- pom.xml
`-- src
|-- main
| |-- java
| | `-- com
| | `-- mycompany
| | `-- app
| | `-- App.java
| `-- resources
| `-- META-INF
| `-- application.properties
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java

Generates:

1
2
3
4
5
6
7
8
9
10
11
12
|-- META-INF
| |-- MANIFEST.MF
| |-- application.properties
| `-- maven
| `-- com.mycompany.app
| `-- my-app
| |-- pom.properties
| `-- pom.xml
`-- com
`-- mycompany
`-- app
`-- App.class

But if you had a customized:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
my-app
|-- pom.xml
`-- src
|-- main
| |-- java
| | `-- com
| | `-- mycompany
| | `-- app
| | `-- App.java
| `-- resources
| `-- testFolder
| `-- test.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java

Generates:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
|-- META-INF
| |-- MANIFEST.MF
| `-- maven
| `-- com.mycompany.app
| `-- my-app
| |-- pom.properties
| `-- pom.xml
|-- testFolder
| `-- test.class
|
`-- com
`-- mycompany
`-- app
`-- App.class

You see other files there like META-INF/MANIFEST.MF as well as a pom.xml and pom.properties file generated as well. These come standard with generation of a JAR in Maven. You can create your own manifest if you choose, but Maven will generate one by default if you don’t. The pom.xml and pom.properties files are packaged up in the JAR so that each artifact produced by Maven is self-describing and also allows you to utilize the metadata in your own application if the need arises. One simple use might be to retrieve the version of your application.

Note:

  • To add resources to the classpath for your unit tests, you follow the same pattern as you do for adding resources to the JAR except the directory you place resources in is ${basedir}/src/test/resources.

Resource Filtering in Maven

This is useful if sometimes a resource file will need to contain a value that can only be supplied at build time. Then, you can use Maven to perform variable replacement on project resources. When resource filtering is activated, Maven will scan resources for property references surrounded by ${<property name>}. When it finds these references it will replace them with the appropriate value.

To enable resource filtering, you need to set filtering to true in your pom.xml, and add the directory src/main/resources which is the default location MAVEN will look into when it compiles (since we overwrote the value to true, this has to be re-written again):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>

Now, to reference a property defined in your pom.xml, the property name uses the names of the XML elements that define the value, with “pom” being allowed as an alias for the project (root) element. So ${project.name} refers to the name of the project, ${project.version} refers to the version of the project, ${project.build.finalName} refers to the final name of the file created when the built project is packaged, etc.

Similarly, values in the user’s settings.xml can be referenced using property names beginning with “settings” (for example, {settings.localRepository} refers to the path of the user’s local repository).

For example, let’s add a couple of properties to the application.properties file (which we put in the src/main/resources directory) whose values will be supplied when the resource is filtered:

1
2
3
# application.properties
application.name=${project.name}
application.version=${project.version}

With that in place, you can execute the following command (process-resources is the build lifecycle phase where the resources are copied and filtered):

1
mvn process-resources

and the application.properties file under target/classes (and will eventually go into the jar) looks like this:

1
2
3
# application.properties
application.name=Maven Quick Start Archetype
application.version=1.0-SNAPSHOT

With that in place, you can execute the following command (process-resources is the build lifecycle phase where the resources are copied and filtered):

1
mvn process-resources

and the application.properties file under target/classes/META-INF (and will eventually go into the jar) looks like this:

1
2
3
# application.properties
application.name=my-app
application.version=1.0-SNAPSHOT

Filtering External Files

To reference a property defined in an external file, all you need to do is add a reference to this external file in your pom.xml.

First, let’s create our external properties file and call it src/main/filters/filter.properties:

1
2
# filter.properties
my.filter.value=hello!

Next, we’ll add a reference to this new file in the pom.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<filters>
<filter>src/main/filters/filter.properties</filter>
</filters>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>

Then, if we add a reference to this property in the application.properties file:

1
2
3
4
# application.properties
application.name=${project.name}
application.version=${project.version}
message=${my.filter.value}

the next execution of the mvn process-resources command will put our new property value into application.properties.

Note:

  • The file filter.property created in the src/main/filters will not get outputted by MAVEN to the target folder. This is because, it is not in the default location tree that MAVEN knows, so MAVEN will not compile it and include in your project.

Using External Dependency

You have, in fact, been using an external dependency all this time, but here we’ll talk about how this works in a bit more detail. For a more thorough introduction, please refer to our Introduction to Apache Maven Dependency Mechanism.

The dependencies section of the pom.xml lists all of the external dependencies that our project needs in order to build (whether it needs that dependency at compile time, test time, run time, or whatever). Right now, our project is depending on JUnit only (I took out all of the resource filtering stuff for clarity):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>

...

</project>

For each external dependency, you’ll need to define at least 4 things: groupId, artifactId, version, and scope.

  • The groupId, artifactId, and version are the same as those given in the pom.xml of the project that built that dependency.
  • The scope element indicates how your project uses that dependency, and can be values like compile, test, and runtime.

Note:

  • Where does Maven reference the dependency from? Maven looks in your local repository (${user.home}/.m2/repository is the default location) to find all dependencies.

This means that we could use code/projects made by others!

For example:

In a previous section, we installed the artifact from our project (my-app-1.0-SNAPSHOT.jar) into the local repository. Once it’s installed there, another project can reference that jar as a dependency simply by adding the dependency information to its pom.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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">
<groupId>com.mycompany.app</groupId>
<artifactId>my-other-app</artifactId>
...
<dependencies>
...
<dependency>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

Note:

  • If a remote repo is needed, you could use the mirror in MAVEN to setup the dependency correctly. By default, the remote repository Maven uses can be found (and browsed) at https://repo.maven.apache.org/maven2/. You can also set up your own remote repository (maybe a central repository for your company) to use instead of or in addition to the default remote repository. For more information on repositories you can refer to the Apache Maven Introduction to Repositories.

Now, when we compile the project (mvn compile), we’ll see Maven download the my-app dependency for us.

Deploying Jar into a Remote Repository

For deploying jars to an external repository, you have to configure the repository url in the pom.xml and the authentication information for connectiong to the repository in the settings.xml.

There are two locations where a settings.xml file may live:

  • The Maven install: ${maven.home}/conf/settings.xml
  • A user’s install: ${user.home}/.m2/settings.xml

The former settings.xml are also called global settings, the latter settings.xml are referred to as user settings. If both files exists, their contents gets merged, with the user-specific settings.xml being dominant.

Note:

  • settings.xml is a configuration file that should not be bundled to any specific project whereas the pom.xml can be distributed.

Now, going back to the exmple, we can use scp and username/password authentication:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>

<dependencies>
...
</dependencies>

<!--
|
|
|
-->
<distributionManagement>
<repository>
<id>mycompany-repository</id>
<name>MyCompany Repository</name>
<url>scp://repository.mycompany.com/repository/maven2</url>
</repository>
</distributionManagement>
</project>

and then in settings.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# settings.xml
<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
http://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<servers>
<server>
<id>mycompany-repository</id>
<username>jvanzyl</username>
<!-- Default value is ~/.ssh/id_dsa -->
<privateKey>/path/to/identity</privateKey> (default is ~/.ssh/id_dsa)
<passphrase>my_key_passphrase</passphrase>
</server>
</servers>
...
</settings>

Note:

  • If you are connecting to an openssh ssh server which has the parameter "PasswordAuthentication" set to "no" in the sshd_confing, you will have to type your password each time for username/password authentication (although you can log in using another ssh client by typing in the username and password). You might want to switch to public key authentication in this case.

Creating Documentation with a Site

To get you jump started with Maven’s documentation system you can use the archetype mechanism to generate a site for your existing project using the following command:

1
2
3
4
5
mvn archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-site \
-DgroupId=com.mycompany.app \
-DartifactId=my-app-site

here we used the additional line: -Darchetype ArtifactIds=maven-archetype-site, which is an archetype to generate a sample Maven site.

Now head on over to the Apache Maven Guide to creating a site to learn how to create the documentation for your project.

Creating Projects of Other Types

For example, back in the base directory we can create a simple web application:

1
2
3
4
5
mvn archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-webapp \
-DgroupId=com.mycompany.app \
-DartifactId=my-webapp

Here we used -DarchetypeArtifactId=maven-archetype-webapp to use an archetype to generate a sample Maven Webapp project. (For the available archetypes, see https://maven.apache.org/guides/introduction/introduction-to-archetypes.html)

Creating Multiple Projects at Once

The basic idea is as follows:

  • First, you could use Maven to create two (or more) projects.
  • Then, you need to create a pom.xml file that is above the two folder
  • After that, you need to configure that pom.xml file to control the two (or more) project folders
    • if you need to add dependencies between the two (or more) sub-projects, you can also add them in the manner like the section Using External Dependency
  • Finally, configure the parent for the two (or more) sub-projects

For example, if you created two projects with name my-app and my-webapp, you should have place your pom.xml above the two folders like this:

1
2
3
4
5
6
7
8
9
10
11
+- pom.xml
+- my-app
| +- pom.xml
| +- src
| +- main
| +- java
+- my-webapp
| +- pom.xml
| +- src
| +- main
| +- webapp

And in the outer pom.xml, you should have the following information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>

<modules>
<module>my-app</module>
<module>my-webapp</module>
</modules>
</project>

where

  • <artifactId>app</artifactId> will be the entire project name which includes your two subprojects.
  • the two (or more) sub-projects you included will be inside the <modules></modules> section

Note:

  • The parent POM created (called app), has a packaging of pom and a list of modules defined. This tells Maven to run all operations over the set of projects instead of just the current one

Finally, we need the following parent information to the pom.xml of the sub-projects like this:

1
2
3
4
5
6
7
8
9
10
<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>
<groupId>com.mycompany.app</groupId>
<artifactId>app</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
...

where

  • <artifactId>app</artifactId> would be same as the artifactId in the outer pom.xml file you manually created.

Note:

  • The parent definition ensures that the POM can always be located even if the project is distributed separately from its parent by looking it up in the repository.

Now, if you try to run from the top level, the outer directory where the outer pom.xml reside, the following command:

1
mvn verify

Then you will have successfully find both of your projects compiled and packed in their respective target folder.

Build Lifecycle Basics

Maven is based around the central concept of a build lifecycle. What this means is that the process for building and distributing a particular artifact (project) is clearly defined.

There are three built-in build lifecycles: default, clean and site. The default lifecycle handles your project deployment, the clean lifecycle handles project cleaning, while the site lifecycle handles the creation of your project’s site documentation.

Then, you need to understand that a build Lifecycle is made up of Phases, and a Phase is made up of Goals.

Phases in a Build Lifecycle

Each of these build lifecycles is defined by a different list of build phases, wherein a build phase represents a stage in the lifecycle.

For example, the default lifecycle comprises of the following phases (these are not all the phases, only some are picked to illustrate the general concept behind phases and lifecycles):

  • validate - validate the project is correct and all necessary information is available
  • compile - compile the source code of the project
  • test - test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
  • package - take the compiled code and package it in its distributable format, such as a JAR.
  • verify - run any checks on results of integration tests to ensure quality criteria are met
  • install - install the package into the local repository, for use as a dependency in other projects locally
  • deploy - done in the build environment, copies the final package to the remote repository for sharing with other developers and projects.

Given the default lifecycle phases above, this means that when the default lifecycle is used, Maven will first validate the project, then will try to compile the sources, run those against the tests, package the binaries (e.g. jar), run integration tests against that package, verify the integration tests, install the verified package to the local repository, then deploy the installed package to a remote repository.

Executing Those Phases

You should first decide/select the phase that matches your outcome, and then run the command. If you want your jar to be made from your project, run mvn package. If you want to run the unit tests, run mvn test.

If you are uncertain what you want, the preferred phase to call is:

1
mvn verify

This command executes each default lifecycle phase in order (validate, compile, package, etc.), up to and including, finally, executing verify.

“Special” Phases

The phases named with hyphenated-words (pre-, post-, or process-*) are not usually directly called from the command line. These phases sequence the build, producing intermediate results that are not useful outside the build. In the case of invoking integration-test, the environment may be left in a hanging state.

For example:

Failsafe and code coverage plugins bind goals to integration-test and verify phases. But if integration-test were to be called from the command line, no reports are generated. If verify is run, the net result is test and coverage reports are available after the verify phase.

In fact, the worse for executing integration-test is that the integration test container environment is left in a hanging state; the Tomcat webserver or Docker instance is left running, and Maven may not even terminate by itself.

Goals in a Phase

A build phase is responsible for a specific step in the build lifecycle, the manner in which it carries out those responsibilities may vary: it depends on the specific goals (plugins) that are attached to the phase.

A plugin/goal represents a specific task (finer than a build phase) which contributes to the building and managing of a project. It may be bound to zero or more build phases. A goal not bound to any build phase could be executed outside of the build lifecycle by direct invocation.

The order of execution depends on the order in which the goal(s) and the build phase(s) are invoked. For example, consider the command below. The clean and package arguments are build phases, while the dependency:copy-dependencies is a goal (the goal copy-dependencies of a plugin depedency/"maven-dependency-plugin").

1
mvn clean dependency:copy-dependencies package

If this were to be executed, the clean phase will be executed first (meaning it will run all preceding phases of the clean lifecycle, plus the clean phase itself), and then the dependency:copy-dependencies goal, before finally executing the package phase (and all its preceding build phases of the default lifecycle).

Note:

  • A phase can also have no goals bounded. If so, no action will be executed during that phase.

Customizing your Build Lifecycle

The first, and most common way, is to set the packaging for your project via the element <packaging> in your POM.xml file. Some of the valid packaging values are jar, war, ear and pom. If no packaging value has been specified, it will default to jar

For example, in the section where you made multiple projects and had a parent pom.xml file, it looked like:

1
2
3
4
5
6
7
8
9
10
11
12
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>
<artifactId>app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>

...

where

  • pom for a packaging value means a project that is purely metadata, and it only binds goals to the install and deploy phases, which means during all the other phases there will be no action/execution.

By default, if you have a jar as the packaging value, you will have the following goals bounded to the following phases

Phase plugin:goal
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test
package jar:jar
install install:install
deploy deploy:deploy

Customizing your Build Lifecycle by Plugins

The second way to add goals to phases is to configure plugins in your project. Plugins are artifacts that provide goals to Maven. This means that a plugin may have one or more goals wherein each goal represents a capability of that plugin.

For example, the Compiler plugin has two goals: compile and testCompile. The former compiles the source code of your main code, while the latter compiles the source code of your test code.

Note:

  • Perhaps it is clear already, but to make sure: adding the plugin on its own is not enough information - you must also specify the goals you want to run from that plugin.
  • As you will see in the later sections, plugins can contain information that indicates which lifecycle phase to bind a goal to. If more than one goal is bound to a particular phase, the order used is that those from the packaging are executed first, followed by those configured in the POM. However, you can use the <executions> element to gain more control over the order of particular goals.

For example, the Modello plugin binds by default its goal modello:java to thegenerate-sources phase (Note: The modello:java goal generates Java source codes). So to use the Modello plugin and have it generate sources from a model and incorporate that into the build, you would add the following to your POM in the <plugins> section of <build>, and it will be executed in the generate-sources phase if you do not explicitly call it by itself:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
<plugin>
<groupId>org.codehaus.modello</groupId>
<artifactId>modello-maven-plugin</artifactId>
<version>1.8.1</version>
<executions>
<execution>
<configuration>
<models>
<model>src/main/mdo/maven.mdo</model>
</models>
<version>4.0.0</version>
</configuration>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
</plugin>
...

You might be wondering why that <executions> element is there. That is so that you can run the same goal multiple times with different configuration if needed.

Now, in the case of modello:java, it only makes sense in the generate-sources phase. But some goals can be used in more than one phase, and there may not be a sensible default. For those, you can specify the phase yourself.

For example, let’s say you have a goal display:time (that echos the current time to the commandline), and you want it to run in the process-test-resources phase to indicate when the tests were started. This would be configured like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
<plugin>
<groupId>com.mycompany.example</groupId>
<artifactId>display-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>process-test-resources</phase>
<goals>
<goal>time</goal>
</goals>
</execution>
</executions>
</plugin>
...

Built-in Lifecycle and Phase Bindings

You can see the default bindings for the lifecycle clean, default, and site here

Built-in Phase and Goal Bindings

Some phases have goals bound to them by default. You can see the default bindings for each phase in the three lifecycles clean, default, site here

POM Basics

A Project Object Model or POM is the fundamental unit of work in Maven. It is an XML file that contains information about the project and configuration details used by Maven to build the project. When executing a task or goal, Maven looks for the POM in the current directory. It reads the POM, gets the needed configuration information, then executes the goal.

For example, some of the configuration that can be specified in the POM are the project dependencies, the plugins or goals that can be executed, the build profiles, project version, description, developers, mailing lists and so on.

Super POM

The Super POM is Maven’s default POM. All POMs extend the Super POM unless explicitly set, meaning the configuration specified in the Super POM is inherited by the POMs you created for your projects. The snippet below is the Super POM for Maven 3.5.4.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<project>
<modelVersion>4.0.0</modelVersion>

<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

<pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>

<build>
<directory>${project.basedir}/target</directory>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<finalName>${project.artifactId}-${project.version}</finalName>
<testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
<pluginManagement>
<!-- NOTE: These plugins will be removed from future versions of the super POM -->
<!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
</plugins>
</pluginManagement>
</build>

<reporting>
<outputDirectory>${project.build.directory}/site</outputDirectory>
</reporting>

<profiles>
<!-- NOTE: The release profile will be removed from future versions of the super POM -->
<profile>
<id>release-profile</id>

<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>

<build>
<plugins>
<plugin>
<inherited>true</inherited>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>

Here, we can see some default settings that the SUPER POM has:

  • the build target directory set to <directory>${project.basedir}/target</directory>
  • the build source directory set to <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
  • the central repository set to <url>https://repo.maven.apache.org/maven2</url>

Minimal POM

The minimum requirement for a POM are the following:

  • project root
  • modelVersion - should be set to 4.0.0
  • groupId - the id of the project’s group.
  • artifactId - the id of the artifact (project)
  • version - the version of the artifact under the specified group

For example:

1
2
3
4
5
6
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>

This is because a needs project’s fully qualified artifact name, which will be in the form of <groupId>:<artifactId>:<version>. As for the example above, its fully qualified artifact name is "com.mycompany.app:my-app:1".

Also, as mentioned in the previous section, if the configuration details are not specified, Maven will use their defaults. One of these default values is the packaging type. Every Maven project has a packaging type. If it is not specified in the POM, then the default value “jar“ would be used.

Project/POM Inheritance

Elements in the POM that are merged when you inherit another parent POM are the following:

  • dependencies
  • developers and contributors
  • plugin lists (including reports)
  • plugin executions with matching ids
  • plugin configuration
  • resources

The Super POM is one example of a parent POM that is inherited by default, however you can also introduce your own parent POMs by specifying the parent element in the POM, as demonstrated in the following examples.

  1. If we have everything ordered nicely in the following structure, where the parent POM sits right above the children:

    1
    2
    3
    |-- childProject
    | `-- pom.xml
    `-- pom.xml
    1
    For example, if the **child artifact is `com.mycompany.app:childProject:1`**,
    4.0.0 com.mycompany.app childProject 1
    1
    2

    And the **parent artifact is `com.mycompany.app:parentProject:1`**, then, we could easily **configure the child `POM`** by adding the `<parent>` element:
    com.mycompany.app parentProject 1 4.0.0 com.mycompany.app childProject 1
    1
    2. If we did not have everything in place, and had the following structure:
    . |-- childProject | `-- pom.xml `-- parentProject `-- pom.xml
    1
    2
    3
    Then we just need to **add an additional `relativePath` element** to specify where to find tha parent `POM`, since we did not have the `parent` element at the default structure.

    So we would **configure the child `POM`** by:
    com.mycompany.app parentProject 1 ../parent/pom.xml

    4.0.0
    com.mycompany.app
    childProject
    1

    1
    2

    However, in both cases, since the **child `POM` knows to inherit** from its parent `POM`, we could further **simplify the child `POM` to**:
    com.mycompany.app parentProject 1 (../parent/pom.xml)

    4.0.0
    childProject

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    So that the **child project will have the same `groupID` and `version` as the parent, as the information would be inherited**.

    > Note:
    > - [ ] This is different from the example in the section [Creating Multiple Projects at Once](#Creating-Multiple-Projects-at-Once) section, because we **did not have the `<packaging>pom</packaging>`**. The difference is that, in this case (without specifying `packaging`) the **`parentProject` is/will be used by its child projects** (like Java Inheritance), but in the other case, the **parent uses the children projects** (like Java Composition) [see below](#Project/POM-Aggregation)
    > - [ ] If you want to **compile a specific children project**, you might need to **change the parent `POM` to `<packaging>pom</packaging>`**. If you need to access the source codes in the parent directory, you should add the dependencies.

    <a name="Project/POM-Aggregatio"></a>
    ## Project/POM Aggregation
    Project Aggregation is similar to Project Inheritance, but there is an essential difference:
    - Project Inheritance would have `childrenProjects` (`modules`) using/inheriting the `parentProject`(`parent`)
    - Project Aggregation would have `parentProjects` (`parent`) using/composed of the `childProjects` (`modules`)

    So, instead of specifying the parent `POM` from the `module`, it **specifies the `modules` in the parent `POM`**. By doing so, the parent project now knows its `modules`, and **if a Maven command is invoked against the parent project**, **that Maven command will then be executed to the parent's `modules` (its `childProjects`)as well**. To do Project Aggregation, you must do the following:

    - **Configure the `parent` POMs** `packaging` to the value "`pom`".
    - **Specify in the parent POM** the directories of its modules (children POMs).

    1. If the directory structure follows that of the default structure:
    . |-- my-module | `-- pom.xml `-- pom.xml
    1
    Then we need to add the `<packaging>` element and the `<modules>` element in the **parent `POM`**:
    4.0.0 com.mycompany.app parent 1 pom my-module
    1
    2
    3
    Now, whenever a Maven command processes `com.mycompany.app:parent:1`, that same Maven command would be ran against `com.mycompany.app:my-module:1` as well. Furthermore, some commands (goals specifically) handle project aggregation differently.

    2. If we have the directory structure to the following:
    . |-- my-module | `-- pom.xml `-- parent `-- pom.xml
    1
    2

    Then we need to specify the **relative path to the module** in the parent `POM`.
    4.0.0 com.mycompany.app parent 1 pom ../my-module
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    ## Combining Project Inheritance and Project Aggregation

    To achieve this, you just edit both child and parent `POM` in the same way introduced above:
    - Specify in every child POM who their parent POM is. (Project Inheritance)
    - Change the parent POMs packaging to the value "pom" . (Project Aggregation)
    - Specify in the parent POM the directories of its modules. (Project Aggregation)

    For a simple example:
    `com.mycompany.app:paernt:1`'s POM
    4.0.0 com.mycompany.app parent 1 pom ../my-module
    1
    2

    `com.mycompany.app:my-module:1`'s POM
    com.mycompany.app parent 1 ../parent/pom.xml 4.0.0 my-module
    1
    2
    3
    4
    5
    6

    ## Variables in `POM`

    One of the practices that Maven encourages is don't repeat yourself. However, there are circumstances where you will need to use the same value in several different locations. To assist in ensuring the value is only specified once, Maven allows you to **use both your own and pre-defined variables in the `POM`**.

    For example, to access the `project.version` variable (this is pre-defined), you would reference it like so:
    ${project.version}
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    > Note:
    >
    > - [ ] If you get an error, you might need to make the variable by yourself in the parent `pom`. To do this, [see below](#own-variable)

    - Some of the **pre-defined variables** are:

    - **Project Model Variables**:
    Any field of the model that is a single value element can be referenced as a variable. For example, `${project.groupId}`, `${project.version}`, `${project.build.sourceDirectory}` and so on. Refer to the POM reference to see a full list of properties.
    - **Special Variables**
    - `project.basedir` The directory that the current project resides in.
    - `project.baseUri` The directory that the current project resides in, represented as an URI. Since Maven 2.1.0
    - `maven.build.timestamp` The timestamp that denotes the start of the build (UTC). Since Maven 2.1.0-M1

    <a name="own-variable"></a>
    - You can also use your **own variable** if you define it in the `<properties>` section:
    ... 3.0 org.apache.maven maven-artifact ${mavenVersion} org.apache.maven maven-core ${mavenVersion} ...
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    ## Profiles
    In short, Maven profiles can be used to create **customized build configurations**.

    Profiles are specified using the element `<profile>` in the `POM `itself (in the extra section `<profiles>`), and can be **triggered in many different ways**. They modify the POM at build time, and are meant to be used in complementary sets to give equivalent-but-different parameters for a set of target environments (providing, for example, the path of the appserver root in the development, testing, and production environments). As such, profiles can easily lead to differing build results from different members of your team.

    Profiles (`<profiles>`) can be **specified in any of the four file locations**:

    - Per Project
    - Defined in the POM itself (`pom.xml`).

    - Per User
    - Defined in the Maven-settings (`%USER_HOME%/.m2/settings.xml`).

    - Global
    - Defined in the global Maven-settings (`${maven.home}/conf/settings.xml`).

    - Profile descriptor (**unsupported in Maven 3.0 and above**)
    - a descriptor located in project basedir (profiles.xml)

    ## Viewing Active Profiles

    To see which profiles are already active, you can use the `help` plugin from MAVEN:
    mvn help:active-profiles
    1
    2

    and by default, nothing is actived so you will see nothing:
    Active Profiles for Project 'com.mycompany.app:my-app:pom:1.0-SNAPSHOT':

The following profiles are active:

1
If we want to **automatically show the active profiles** when we are doing, for example, the `compile` phase, we can use the similar approach shown in the section [Customizing your Build Lifecycle by Plugins](#Customizing-your-Build Lifecycle-by-Plugins) by **adding the `help` plugin and the `goal`** in our phase `compile`:
org.apache.maven.plugins maven-help-plugin 3.2.0 show-profiles compile active-profiles
1
2
3
4
5

## Making a Profile
Within each `<profile>` element, we can **configure many elements such as `dependencies`, `plugins`, `resources`, `finalName`**.

For example (configured a `plugin`):
test
  <build>
     <plugins>
        <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-antrun-plugin</artifactId>
           <version>1.1</version>
           <executions>
              <execution>
                 <phase>test</phase>
                 <goals>
                    <goal>run</goal>
                 </goals>
                 <configuration>
                 <tasks>
                    <echo>Using app.test.properties</echo>
                    <copy file="src/main/resources/app.test.properties" 
                        tofile="${project.build.outputDirectory}/env.properties"/>
                 </tasks>
                 </configuration>
              </execution>
           </executions>
        </plugin>
     </plugins>
  </build>

</profile>
1
Another simpler example could be:
no-tests true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(This will skip the `test` phase in the artifact if you activate it.)

In general, it is **recommended** to specify a profile in the **`POM` of the project**. This is because it will be **portable** since the `POM` file will be included in the final product. In contrast, profiles specified in **external files** (i.e **in `settings.xml`** or `profiles.xml`) are **not portable** in the strictest sense. Also, you can **specify much more modifications in the profile in the `POM` than in the `settings.xml`**. For more details, see the section [Profiles in `POM`s and in `Settings`](#Profiles-in-POM-and-in-Settings).



> Note:
> - [ ] In the above examples, there is an `<id>` element for that `profile`. **This will be used later to activate the profile**, so it is important to give it a sensible name,
> - [ ] We can also **configure as many profiles** as we want by **giving them unique `id`s**.

## Activate a Profile
You can activate a profile in a number of ways:

- For a **single run**
- explicitly add the `-P <profile-id>` at the end of a command
- **Automatically for a project** (per project)
- through the `POM` file
- **Automatically for all projects of a user** (per user)
- Through Maven settings
- **Triggered**
- Based on environment variables
- OS settings
- Present or missing files

## Activate Profile for a Single Run
This can be done by adding the option `-P <profile-id>` so that the profile will be **activated for that specific run**.

For example, to use the `no-test` profile (assuming that profile is added to the `pom` file of this project), we could use:
mvn package -P no-test
1
2
3
This will execute all phases up to and until `package`, except **skipping the `test` phase**, as **specified by our `no-test` profile**.

You could also activate multiple profiles by using comma as a delimiter:
mvn package -P no-test,profile2,profile3
1
2
3
4
5

## Activate Profile Automatically for a Project
This can be done by adding another section `<activation>` in the same section where you specified the `<profile>`.

For example, if we want to automatically activate the profile `no-test` for a project (again, assuming that profile is added to the `pom` file of this project), then we would have in the `pom` file:
no-test true
<properties>
  <maven.test.skip>true</maven.test.skip>
</properties>
1
2
3
4
5
6
7
8
9
10
11
This will activate the profile `no-test` everytime when the project is run.

## Deactivating a Profile
Deactivating a profile is done by adding the option `-P !<profile-id>` or `-P -<profile-id>`

However, one important thing to note is that, if you have several profiles that are **activated by default**, running the `-P !<profile-id>` or `-P -<profile-id>` would **override the configuration such that all those profiles that are activated by default would be ignored/deactivated**.

## Activate Profile Automatically for all Projects (per user)
Profiles can be activated in the **Maven settings file** (per user, `%USER_HOME%/.m2/settings.xml`; globally/all users, `${maven.home}/conf/settings.xml`), via the `<activeProfiles>` section. This section takes a list of `<activeProfile>` elements, each containing a `<profile-id>` inside.

For example, to activate the `no-test` profile for all projects of a user, add the following to the `%USER_HOME%/.m2/settings.xml`:
... no-test ...
1
2
3
4
5
6
7
So that profiles listed in the `<activeProfiles>` tag would be **activated by default every time that user runs a project**.

## Activate Profiles by Triggers

Profiles can be automatically triggered based on the detected state of the build environment. **These triggers are specified via an `<activation>` section in the profile itself**.

- Triggered by a specific JDK version:
1.4 ...
1
2
3

The above will trigger the profile when the JDK's version **starts with "1.4"** (eg. "1.4.0_08", "1.4.2_07", "1.4")
- Triggered by a specific OS setting:
Windows XP Windows x86 5.1.2600 ...
1
2

- Triggered by a specific property
debug ...
1
2
3
4

The profile above will be activated when the system property "debug" is specified with **any value**.

Or, you can specify it to be activated when the system property "debug" is **not defined**, or is defined with **a value which is not "true"**.
debug !true ...
1
2

The above can be activated by typing one of those on the command line:
mvn groupId:artifactId:goal mvn groupId:artifactId:goal -Ddebug=false
1
2
3
- Triggered by a missing/present file

This example will trigger the profile when the generated file `target/generated-sources/axistools/wsdl2java/org/apache/maven` is **missing**.
target/generated-sources/axistools/wsdl2java/org/apache/maven ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

Or you could **switch the `<missing>` to `<exists>`** if you want to trigger the profile **when that file is present**.

> Note:
>
> - [ ] As of Maven 2.0.9, the tags `<exists>` and `<missing>` could be **interpolated**. **Supported variables** are system properties like `${user.home}` and environment variables like `${env.HOME}`. Please note that **properties and values defined in the POM** itself are **not available** for interpolation here

<a name="Profiles-in-POM-and-in-Settings"></a>
## Profiles in `POM`s and in `Settings`
- Profiles in external files (`settings.xml`)

Profiles specified in external files (i.e in `settings.xml` or `profiles.xml`) are not portable in the strictest sense. Things like repository lists could simply be a proprietary repository of approved artifacts, and won't change the outcome of the build. Therefore, you will **only be able to modify**
- `<repositories>`
- `<pluginRepositories>`
- `<properties>`

- Profiles in `POM`s

If your profiles can be reasonably specified inside the `POM`, you will have a better portability **since these profiles are specified inline**. Therefore, you have many more options as well. The **trade-off**, of course, is that you can **only modify that project and it's sub-modules**.

Profiles specified in the `POM` can modify the following `POM` elements:

- `<repositories>`
- `<pluginRepositories>`
- `<dependencies>`
- `<plugins>`
- `<properties>` (not actually available in the main POM, but used behind the scenes)
- `<modules>`
- `<reporting>`
- `<dependencyManagement>`
- `<distributionManagement>`
- a subset of the `<build>` element, which consists of:
- `<defaultGoal>`
- `<resources>`
- `<testResources>`
- `<finalName>`
- `<plugin>`???

> Note:
>
> - [ ] If you have conflicting profiles in both the `pom` file and the `settings.xml` file, take note that **profiles in the `settings.xml` takes higher priority** than profiles in the `POM`.

## Standard Directory Output

Having a common directory layout would allow for users familiar with one Maven project to immediately feel at home in another Maven project. The following table documents the **directory layout expected by Maven** and the directory layout created by Maven. Please try to conform to this structure as much as possible; however, if you can't these settings **can be overridden via the project descriptor**.

Directory | Description
---|---
`src/main/java` | Application/Library sources
`src/main/resources` | Application/Library resources
`src/main/filters` | Resource filter files
`src/main/webapp` | Web application sources
`src/test/java` | Test sources
`src/test/resources` | Test resources
`src/test/filters` | Test resource filter files
`src/it` | Integration Tests (primarily for plugins)
`src/assembly` | Assembly descriptors
`src/site` | Site
`LICENSE.txt` | Project's license
`NOTICE.txt` | Notices and attributions required by libraries that the project depends on
`README.txt` | Project's readme

This means that **at the top level**, we will have **files descriptive of the project**: a `pom.xml` file, and textual documents meant for the user to be able to read immediately on receiving the source: `README.txt`, `LICENSE.txt`, etc.

So there are just **two subdirectories of this structure**: `src` and `target`. The **only other directories that would be expected** here are metadata like `CVS`, **`.git`** or `.svn`, and any subprojects in a multiproject build (each of which would be laid out as above).
- The `src` directory contains **all of the source material for building the project**, its site and so on. It contains a subdirectory for each type: main for the main build artifact, test for the unit test code and resources, site and so on.
- The `target` directory is used to house **all output of the build**.

Also, it is important to see that, within artifact producing source directories (ie. main and test), **there is one directory for the language java** (under which the normal package hierarchy exists), and one for resources (the structure which is copied to the target classpath given the default resource definition). But **if there are other contributing sources to the artifact build, they would be under other subdirectories**: for example `src/main/antlr` would contain Antlr grammar definition files.

## Transitive Dependency

Maven avoids the need to **specify the libraries that your own dependencies require** by including **transitive dependencies** automatically.

This feature is facilitated by **reading the project files of your dependencies from the remote repositories specified**. In general, **all dependencies of those projects are used in your project**, as are any that the project inherits from its parents, or from its dependencies, and so on. A problem arises only if a cyclic dependency is discovered.

However, with transitive dependency, the graph of included libraries will grow quite large. Therefore, there are **additional features that can be used to limit which dependencies are included**:
- Dependency Mediation
- Dependency Management
- Dependency Scope
- Dependency Exclusion
- Optional Dependency

## Dependency Mediation
This determines **what version of an artifact/dependency will be chosen** when multiple versions are encountered as dependencies. By default, Maven picks the "nearest definition". That is, it uses the version of the closest dependency to your project in the tree of dependencies.

However, you can always guarantee a version by declaring it **explicitly in your project's `POM`** (see section [Using External Dependency](#Using-External-Dependency)). You basically need to add the following to your `POM`:
com.mycompany.app myDependency aSpecificVersion compile
1
2
3
4
5
6
7
8
9
Or, you could use the [Dependency Management](#Dependency-Management) in the section below.

<a name="Dependency-Management"></a>
## Dependency Management
The dependency management section is a mechanism for **centralizing dependency information**. When you have a set of projects that inherit from a common parent, it's possible to put all information about the dependency in the common POM and have simpler references to the artifacts in the child POMs.

1. For example, you could use it to control the **versions of the artifacts in a set of dependencies**:

If you have a parent Project A and child Project B:
# Project A 4.0.0 maven A pom A 1.0 test a 1.2 test b 1.0 compile test c 1.0 compile test d 1.2
1
at this point, if you have the following Project B configuration:
# Project B A maven 1.0 4.0.0 maven B pom B 1.0 test a test c
1
2
3
Then version of artifact `a` and `c` would be `1.2` and `1.0`, respectively. 

However, if you have the following configuration:
# Project B A maven 1.0 4.0.0 maven B pom B 1.0 test a 1.0 runtime test c
1
2
3
Then you would have version of `1.0` for both `a` and `c`. Also, the `scope` of `a` would become `runtime`

2. Now, consider reverse case where we have two children `POM`s, Project A and Project B, with the following configurations:
# Project A: ... group-a artifact-a 1.0 group-c excluded-artifact
<dependency>
  <groupId>group-a</groupId>
  <artifactId>artifact-b</artifactId>
  <version>1.0</version>
  <type>bar</type>
  <scope>runtime</scope>
</dependency>
1
and
... group-c artifact-b 1.0 war runtime group-a artifact-b 1.0 bar runtime
1
We see that these two example `POM`s **share a common dependency (`group-a` artifact `artifact-b`)** and each has one non-trivial dependency. This **information can be put in the parent `POM`** like this:
# created a parent POM ... group-a artifact-a 1.0
    <exclusions>
      <exclusion>
        <groupId>group-c</groupId>
        <artifactId>excluded-artifact</artifactId>
      </exclusion>
    </exclusions>

  </dependency>

  <dependency>
    <groupId>group-c</groupId>
    <artifactId>artifact-b</artifactId>
    <version>1.0</version>
    <type>war</type>
    <scope>runtime</scope>
  </dependency>

  <dependency>
    <groupId>group-a</groupId>
    <artifactId>artifact-b</artifactId>
    <version>1.0</version>
    <type>bar</type>
    <scope>runtime</scope>
  </dependency>
</dependencies>
1
Now, if the two children inherits the parent, we could simplify the children `POM`s:
# Project A ... group-a artifact-a
<dependency>
  <groupId>group-a</groupId>
  <artifactId>artifact-b</artifactId>
  <!-- This is not a jar dependency, so we must specify type. -->
  <type>bar</type>
</dependency>
1
and
# Project B ... group-c artifact-b war
<dependency>
  <groupId>group-a</groupId>
  <artifactId>artifact-b</artifactId>
  <!-- This is not a jar dependency, so we must specify type. -->
  <type>bar</type>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

> Note:
>
> - [ ] In two of these dependency references, we had to specify the `<type>` element. This is because the **minimal set of information for matching a dependency reference against a `<dependencyManagement>` section is actually `{groupId, artifactId, type, classifier}`**. In many cases, these dependencies will refer to **`jar` artifacts with no classifier**. **This allows us to shorthand the identity set to `{groupId, artifactId}`**. However, in other cases, we would need to include the `<type>` element.

## Difference between using `<dependency>` and `<dependencyManagement>`

- if you use `<dependencies>` in the parent `pom` and specify all the dependencies your chlidren will need, this will
- create a shorter child poms, as technically you don't need to specify them again, unless you want to override something, like the `version`.
- it means that **those dependencies will ALWAYS be defined for ALL the child modules**.
- if you use `<dependencyManagement>` in the parent `POM`, this will
- allow you to chose **which child modules will have a dependency specified in th parent**. If nothing/no dependency is specified in the children `POM`, then no dependency will be ensued.



## Dependency Scope

Dependency scope is used to limit the transitivity of a dependency, and also to affect the classpath used for various build tasks.

There are **6 scopes available**:

- `compile`
- This is the default scope, used if none is specified. **Compile dependencies are available in all classpaths of a project**. Furthermore, those dependencies are **propagated to dependent projects**.
- `provided`
- This is much like compile, but indicates you **expect the JDK or a container to provide the dependency at runtime**. For example, when building a web application for the Java Enterprise Edition, you would **set the dependency on the Servlet API and related Java EE APIs to scope `provided`** because the **web container provides those classes**. This scope is only available on the compilation and test classpath, and is **not transitive**.
- `runtime`
- This scope indicates that the dependency is **not required for compilation**, but is **for execution**. It is in the runtime and test classpaths, but not the compile classpath.
- `test`
- This scope indicates that the dependency is not required for normal use of the application, and is **only available for the test compilation and execution phases**. This scope is **not transitive**.
- `system`
- This scope is **similar to `provided` except that you have to provide the JAR which contains it explicitly**. The artifact is **always available and is not looked up in a repository**.
- `import`
- This scope is only supported on a dependency of type `pom` in the `<dependencyManagement>` section (see [Depedency Management](#Dependency-Management)). It indicates the **dependency to be replaced with the effective list of dependencies in the specified POM's `<dependencyManagement>` section**. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.

However, each of the scopes (except for `import`) **affects transitive dependencies in different ways**, as is demonstrated in the table below.

If a **parent dependency** is set to the scope in the **left column**, **transitive dependencies of the child dependency** with the **scope across the top row** **will result in a dependency in the main project with the scope listed at the intersection**. If no scope is listed, it means the dependency will be omitted.

- | compile | provided | runtime | test
--- | --- | --- | --- | ---
**compile** | compile(*) | - | runtime | -
**provided** | provided | - | provided | -
**runtime** | runtime | - | runtime | -
**test** | test | - | test | -


## Importing Dependencies

The examples in the previous section describe how to specify managed dependencies through inheritance. However, in larger projects it may be impossible to accomplish this **since a project can only inherit from a single parent**. To accommodate this, projects can **import managed dependencies from other projects**. This is accomplished by declaring a `pom` artifact as a dependency with a scope of `import`.

Consider the case of a `POM` file:
# Project X 4.0.0 maven X pom X 1.0 test a 1.1
<dependency>
  <groupId>test</groupId>
  <artifactId>b</artifactId>
  <version>1.0</version>
  <scope>compile</scope>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

- Then if you would like another project that is not its child to have the **`<dependencyManagement>` configured the same way**, then you would do this:

```xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>project1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<dependencyManagement>
<dependencies>
<!-- Imports the bill-of-materials POM. -->
<dependency>
<groupId>maven</groupId>
<artifactId>X</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
- If you would like that project to **use the `` directly** that is specified in the configurations of Project X, then you would do this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>project1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<dependencyManagement>
<dependencies>
<!-- Imports the bill-of-materials POM. -->
<dependency>
<groupId>maven</groupId>
<artifactId>X</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- Add a dependency from the BOM POM.
Note: no version or scope is required, it's inherited from the BOM POM! -->
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
</dependency>
</dependencies>
</project>