Apache Maven Basic Tutorial

I created this brief introduction to Maven because I wasn’t able to find any documentation that would help me understand the fundamental concepts and basic operation of Maven quickly enough. As much as the official documentation encompasses most of the necessary information, that information is somewhat scattered across a relatively large number of documents. On the other hand, tutorials written by users often lack clarity and accuracy when addressing the fundamental concepts. My goal was to gather the minimum amount of information so that the reader would:

Project Object Model (POM)

Maven is a tool that aims to provide a standard way to build Java-based projects. It can be used for building and managing any Java-based project (e. g. an Eclipse project, although Eclipse integration is not as trivial as one might expect).

The definition and configuration of a Maven project is done via the Project Object Model (POM), which is represented by a pom.xml file. It is an XML file that contains information about the project and configuration details used by Maven to build the project. Generally, pom.xml is the only file Maven needs to be created in order to be able to build your project.

POM identifies any project by means of its groupId, artifactId, and version.

These three values form the project's fully qualified artifact name (also known as GAV, or the coordinates). Maven uses a colon to delimit the POM coordinates:

<groupId>:<artifactId>:<version>

Minimal POM

Let’s see what the simplest possible pom.xml may look like. The minimum requirement for a pom.xml is the following:

Here's an example:

    <project>
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.mycompany.app</groupId>
      <artifactId>my-application</artifactId>
      <version>0.0.1</version>
    </project>

The corresponding fully qualified artifact name is com.mycompany.app:my-application:0.0.1.

Maven Invocation

So far, we have learnt what a basic Maven project definition may look like. Let us now concentrate on the actions Maven can perform on a project.

Any action Maven can do with a project is called a goal. Goals may (or may not) be combined into so-called build lifecycle phases, which in turn form series known as build lifecycles.

The syntax for running Maven from the command line now follows naturally:

mvn [options] [goal(s)] [phase(s)]

Each of the terms following mvn can be omitted or repeated and their order may be altered. The order of execution depends on the order in which the goal(s) and the build phase(s) are invoked.

All available options can be listed with the command mvn -h, or you can find them online.

Goals & Plugins

Goals are the building blocks that almost all actions Maven can perform on a projects are made of. Goals can be implemented in Java (as annotated classes) or in a scripting language such as BeanShell. A goal implementation is called a Mojo, a word play on POJO (Plain-old-Java-object), substituting "Maven" for "Plain". Mojos always need to be a part of a "library" known as a Maven plugin.

How to create a new Maven project

To get a taste of basic Maven usage, we're going to learn how to automatically create an empty Maven project. This can be done by using a plugin called archetype, specifically its generate goal. We need to specify what kind of project should be created, in other words, what are we going to develop. Maven provides a number of templates (called archetypes) for different types of project. We choose the maven-archetype-quickstart archetype, which will generate a sample Maven project. As we already know, the POM requires that groupId, artifactId, and version be configured. Since we haven't got a pom.xml yet, we need to pass these coordinates as parameters. More precisely, we need to specify at least groupId and artifactId; version is not required. The following command is now self-explanatory:

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

Let us note that the Archetype mechanism is additive, which means that pieces or aspects of a project can be added to existing projects. If, for example, you have used the quick start archetype to generate a working project, you can then quickly create a site for that project by using the site archetype within that existing project.

Plugin naming conventions

We saw in the last paragraph that in order to execute a certain goal, one can use the syntax <plugin>:<goal>. This syntax is actually a shortcut. Each plugin has its own POM coordinates, so you can use a full plugin qualification when invoking any of its goals:

mvn groupId:artifactId:version:goal

Moreover, archetype is not a full artifactId of the plugin, which is, actually, maven-archetype-plugin. The "official" Apache Maven plugins maintained by the Apache Maven team follow the naming convention of maven-<pluginname>-plugin, and their groupId is org.apache.maven.plugins. User-defined plugins should follow the naming convention of <pluginname>-maven-plugin. In both cases, Maven automatically assigns the plugin a shortened alias <pluginname>.

For more information see the official plugin development guide.

Build Lifecycles

So far, we have been exploring the low-level principles of Maven, which are centered around (plugin) goals. Maven, however, aims to provide more than just a collection of plugins and goals, namely means to clearly define the process for building and distributing a project. For this purpose, Maven defines a build lifecycle, which is a sequence of phases. Each phase consists of zero or more plugin goals. Unlike a plugin, which is merely a collection of goals relating to a particular topic or area, a lifecycle phase is a meaningful "unit of work" one can perform on a project.

The relationship between build phases and plugin goals can be summarized as follows:

Maven has three built-in build lifecycles: default, clean and site. The default lifecycle handles your project deployment, the clean lifecycle handles cleaning up artifacts created by prior builds, while the site lifecycle handles the creation of your project's site documentation. Each of these build lifecycles is defined by a different list of build phases.

For example, the default lifecycle comprises phases such as:

The clean lifecycle phases include:

For a complete list of the default, clean, and site lifecycle phases, refer to the Lifecycle Reference.

When you recall the mvn command syntax, you may notice that it allows to pass a list of phases rather than a list of lifecycles. That is because if you call a build phase, it will execute not only that build phase, but also all phases preceding the called build phase in a lifecycle.

Building a project

The vast majority of Maven projects can be built with the following command:

mvn clean install

This command tells Maven to execute the clean phase of the eponymous lifecycle following all of its prior phases, and the install phase of the default lifecycle following all of its prior phases. Maven builds all the project modules, and installs them in the local repository. The local repository is created in your home directory (or alternative location that you created it), and is the location that all your project’s dependencies (downloaded JARs) and the projects you built are stored. If you look in the target subdirectory, you should find the build output and the final library or application that was being built.

Let us note that the above command can also be used in a multi-module scenario (i.e. a project with one or more subprojects) - Maven will traverse into all of the subprojects and run clean and install (including all of the prior phases).

But how does Maven ‘know’ where to look for your source code and where to install the built modules? The answer is that, whenever configuration details are not specified in your project’s POM, Maven will use their defaults. This concept is known as “convention over configuration”, since you only need to configure what was not defined as, or is different from, the defaults. Let’s have a brief look at this concept from a more technical viewpoint.

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. In other words, if the configuration details are not specified in your project’s POM, Maven will use their defaults.

The Super POM contains default values for most projects. Examples for this include the build directory, which is target; the source directory, which is src/main/java; the test source directory, which is src/test/java; and so on. Another example is the packaging type. Every Maven project has a packaging type. This could be e.g. jar, war or ear. If it is not specified in the POM, then the default value jar would be used.

Parameter override

You can specify properties in your build files and override them on the command line. For example you can specify in your POM file that the test should be skipped during the build:

    <properties>
      <skipTests>true</skipTests>
    </properties>

On the command line you can override such parameters as demonstrated in the following command:

mvn clean install -DskipTests=false

Dependency Management

Maven has an ability to download your project's dependency libraries automatically from a central repository of JARs and other dependencies. All you need to do is list these dependencies' POM coordinates in your pom.xml.

For example, say your project makes use of the class javax.servlet.http.HttpServlet. Now you need to find out, what the corresponding POM coordinates for this class are. This information can be found at http://search.maven.org/ by means of Advanced Search. Once you've found the appropriate groupId and arcifactId (which, in our case, are javax.servlet and javax.servlet-api, respectively), you can click either of them to see a list of available versions. To include this dependency, you create a <dependency> section and add it to the <dependencies> section of your pom.xml:

    <dependencies>
      ...
      <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.0-b01</version>
      </dependency>
    </dependencies>

References

Most information in this tutorial comes from the following documents: