2.3. Maven Essentials

Overview

This section provides a quick introduction to some essential Maven concepts, enabling you to understand the fundamental ideas of the Maven build system.

Build lifecycle phases

Maven defines a standard set of phases in the build lifecycle, where the precise sequence of phases depends on what type of package you are building. For example, a JAR package includes the phases (amongst others): compile, test, package, and install.
When running Maven, you normally specify the phase as an argument to the mvn command, in order to indicate how far you want the build to proceed. To get started, the following are the most commonly used Maven commands:
  • Build the project, run the unit tests, and install the resulting package in the local Maven repository:
    mvn install
  • Clean the project (deleting temporary and intermediate files):
    mvn clean
  • Build the project and run the unit tests:
    mvn test
  • Build and install the project, skipping the unit tests:
    mvn install -Dmaven.test.skip=true
  • Build the project in offline mode:
    mvn -o install
    Offline mode (selected by the -o option) is useful in cases where you know that you already have all of the required dependencies in your local repository. It prevents Maven from (unnecessarily) checking for updates to SNAPSHOT dependencies, enabling the build to proceed more quickly.

Maven directory structure

Example 2.1, “Standard Maven Directory Layout” shows the standard Maven directory layout. Most important is the Maven POM file, pom.xml, which configures the build for this Maven project.

Example 2.1. Standard Maven Directory Layout

ProjectDir/
    pom.xml
    src/
        main/
            java/
                ...
            resources/
                META-INF/
                    spring/
                        *.xml
                OSGI-INF/
                    blueprint/
                        *.xml
        test/
            java/
            resources/
    target/
        ...
The project's Java source files must be stored under ProjectDir/src/main/java/ and any resource files should be stored under ProjectDir/src/main/resources/. In particular, Spring XML files (matching the pattern *.xml) should be stored under the following directory:
ProjectDir/src/main/resources/META-INF/spring/
Blueprint XML files (matching the pattern *.xml) should be stored under the following directory:
ProjectDir/src/main/resources/OSGI-INF/blueprint/

Convention over configuration

An important principle of Maven is that of convention over configuration. What this means is that Maven's features and plug-ins are initialized with sensible default conventions, so that the basic functionality of Maven requires little or no configuration.
In particular, the location of the files within Maven's standard directory layout effectively determines how they are processed. For example, if you have a Maven project for building a JAR, all of the Java files under the src/main/java directory are automatically compiled and added to the JAR. All of the resource files under the src/main/resources directory are also added to the JAR.
Note
Although it is possible to alter the default Maven conventions, this practice is strongly discouraged. Using non-standard Maven conventions makes your projects more difficult to configure and more difficult to understand.

Maven packaging type

Maven defines a variety of packaging types, which determine the basic build behavior. The most common packaging types are as follows:
jar
(Default) This packaging type is used for JAR files and is the default packaging type in Maven.
bundle
This packaging type is used for OSGi bundles. To use this packaging type, you must also configure the maven-bundle-plugin in the POM file.
war
This packaging type is used for WAR files. To use this packaging type, you must also configure the maven-war-plugin in the POM file.
pom
When you build with this packaging type, the POM file itself gets installed into the local Maven repository. This packaging type is typically used for parent POM files.

Maven artifacts

The end product of a Maven build is a Maven artifact (for example, a JAR file). Maven artifacts are normally installed into a Maven repository, from where they can be accessed and used as building blocks for other Maven projects (by declaring them as dependencies).

Maven coordinates

Artifacts are uniquely identified by a tuple of Maven coordinates, usually consisting of groupId:artifactId:version. For example, when deploying a Maven artifact into the Red Hat JBoss Fuse container, you can reference it using a Maven URI of the form, mvn:groupId/artifactId/version.
For more details about Maven coordinates, see chapter "Building with Maven" in "Deploying into Apache Karaf".

Maven dependencies

The most common modification you will need to make to your project's POM file is adding or removing Maven dependencies. A dependency is simply a reference to a Maven artifact (typically a JAR file) that is needed to build and run your project. In fact, in the context of a Maven build, managing the collection of dependencies in the POM effectively takes the place of managing the collection of JAR files in a Classpath.
The following snippet from a POM file shows how to specify a dependency on the camel-blueprint artifact:
<project ...>
    ...
    <dependencies>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-blueprint</artifactId>
            <version>2.17.0.redhat-630xxx</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    ...
</project>

dependency element

The dependency element declares a dependency on the Maven artifact with coordinates org.apache.camel:camel-blueprint:6.3.0.redhat-xxx. You can add as many dependency elements as you like inside the dependencies element.

dependency/scope element

The scope element is optional and provides some additional information about when this dependency is needed. By default (with the scope element omitted), it is assumed that the dependency is needed at build time, at unit test time, and at run time. With scope set to the value, provided, the effect depends on what kind of artifact you are building:
  • OSGi bundle—(when the POM's packaging element is specified as bundle) the provided scope setting has no effect.

Transitive dependencies

To simplify the list of dependencies in your POM and to avoid having to list every single dependency explicitly, Maven employs a recursive algorithm to figure out the dependencies needed for your project.
For example, if your project, A, depends on B1 and B2; B1 depends on C1, C2, and C3; and B2 depends on D1 and D2; Maven will automatically pull in all of the explicitly and implicitly required dependencies at build time, constructing a classpath that includes the dependencies, B1, B2, C1, C2, C3, D1, and D2. Of these dependencies, only B1 and B2 appear explicitly in A's POM file. The rest of the dependencies—which are figured out by Maven—are known as transitive dependencies.

Maven repositories

A Maven repository is a place where Maven can go to search for artifacts. Because Maven repositories can be anywhere—and that includes anywhere on the Internet—the Maven build system is inherently distributed. The following are the main categories of Maven repository:
  • Local repository—the local repository (by default, located at ~/.m2/repository on *NIX or C:\Documents and Settings\UserName\.m2\repository on Windows) is used by Maven as follows:
    • First search location—the local repository is the first place that Maven looks when searching for a dependency.
    • Cache of downloaded dependencies—any artifacts that have ever been downloaded from a remote repository are stored permanently in the local repository, so that they can be retrieved quickly next time they are needed.
    • Store of locally-built artifacts—any time that you build a local project (using mvn install), the resulting artifact gets stored in your local repository.
  • Remote repository—Maven can also search for and download artifacts from remote repositories. By default, Maven automatically tries to download an artifact from remote repositories, if it cannot find the artifact in the local repository (you can suppress this behavior by specifying the -o flag—for example, mvn -o install).
  • System repository—(Red Hat JBoss Fuse container only; not used by the mvn command-line tool) at run time, the Red Hat JBoss Fuse container can access artifacts from the JBoss Fuse system repository, which is located at InstallDir/system/.
For more details about Maven repositories, see chapter "Building with Maven" in "Deploying into Apache Karaf".

Specifying remote repositories

If you need to customise the remote repositories accessible to Maven, you must separately configure the build-time and runtime repository locations, as follows:
  • Build time—to customize the remote repositories accessible at build time (when running the mvn command), edit the Maven settings.xml file, at the following location:
    • *Nix: default location is ~/.m2/settings.xml.
    • Windows: default location is C:\Documents and Settings\UserName\.m2\settings.xml.
  • Run time—to customize the remote repositories accessible at run time (from within Red Hat JBoss Fuse container), edit the relevant property settings in the InstallDir/etc/org.ops4j.pax.url.mvn.cfg.