Chapter 2. Core Maven Concepts

As we saw in the previous chapter, each Maven project is described by an XML configuration file called Project Object Model. What we have yet to see is how Maven will use the information contained in the POM, how we can clean and build our projects, which tasks we can decide to run, and finally, how Maven plugins take part in the build process. In order to answer all these questions, we'll dive into the core concepts of Maven, which are as follows:

  • Build lifecycles
  • Lifecycle phases and plugin goals
  • Packaging types (JAR, WAR, EAR)
  • Dependencies and repositories
  • Resource filtering

Using all these features, you will learn how to set up and build a complex multimodule Java EE application. All the examples of this chapter refer to a direct usage of the Maven tool from the command line; in Appendix B, Maven Integration for Eclipse we will show you how to manage a Maven project from Eclipse IDE.

Build lifecycles

A lifecycle is a sequence of phases. In each phase, depending on the POM configuration, one or more tasks are executed. These tasks are called goals. Despite the enormous variety of work that can be accomplished by Maven, there are only three built-in Maven lifecycles: default, clean, and site.

The default lifecycle

The default lifecycle is responsible for the build process, so it's the most interesting. Among its phases, the most important phases are described in the following table:

Phase

Actions

process-resources

Filter the resource files and copy them in the output directory

compile

Compile the source code

process-test-resources

Filter the test resource files and copy them in the test output directory

test-compile

Compile the test source code

test

Run the unit tests

package

Produce the packaged artifact (JAR, WAR, EAR)

install

Install the package in the local repository so that other projects can use it as a dependency

deploy

Install the package in a remote repository

We'll speak later about local and remote Maven repositories.

When we invoke one phase from the command line, Maven executes all the phases of the lifecycle from the beginning up to the specified phase (included). In fact, one of the most common ways to run Maven is just to use the following syntax:

$ mvn <phase>

It will run all the portions of the respective lifecycle, ending with this phase.

Let's consider an example. Suppose that the POM file of our transportation-acq-ejb module is the following, and it is located in the /transportation-project/transportation-acq-ejb directory:

<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>
    <parent>
        <groupId>com.packt.examples</groupId>
        <artifactId>transportation-project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>transportation-acq-ejb</artifactId>
    <packaging>jar</packaging>
    <name>transportation-acq-ejb</name>
    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

As we can see in the preceding code, the transportation-acq-ejb module's parent is the transportation-project parent project. We can add some sample Java classes and interfaces in the transportation-acq-ejb project. First, we add an EJB local interface, MyEjb.java:

package com.packt.samples;

import javax.ejb.Local;

@Local
public interface MyEjb
{
    public int myMethod();
}

Then, we add a dummy implementation, MyEjbImpl.java:

package com.packt.samples;

import javax.ejb.Stateless;

@Stateless
public class MyEjbImpl implements MyEjb
{

    @Override
    public int myMethod()
    {         
        return 0;
    }
}

Finally, we add a unit test class, SampleTest.java:

package com.packt.samples;

import static org.junit.Assert.*;

import org.junit.Test;

public class SampleTest
{
    @Test
    public void test()
    {
        assertTrue(true);
    }
}

The directory structure of the transportation-acq-ejb module is as shown in the following screenshot:

The default lifecycle

Tip

In a Maven project, we have to put the project sources under /src/main/java and the test sources under /src/main/test. These default conventional values can be overridden, as we'll see later in this chapter, but this is not recommended; remember the convention over configuration paradigm!

Execute the following command:

$ mvn install

We'll see the following output after executing the preceding command:

[INFO] Scanning for projects...
[...]
[INFO] -----------------------------------------------------------
[INFO] Building transportation-acq-ejb 0.0.1-SNAPSHOT
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ transportation-acq-ejb ---
[…]
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ transportation-acq-ejb ---
[INFO] Compiling 2 source files to ~/transportation-project/transportation-acq-ejb/target/classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ transportation-acq-ejb ---
[…]
[INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ transportation-acq-ejb ---
[INFO] Compiling 1 source file to ~/transportation-project/transportation-acq-ejb/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.17:test (default-test) @ transportation-acq-ejb ---
[INFO] Surefire report directory: ~/transportation-project/transportation-acq-ejb/target/surefire-reports-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.packt.samples.SampleTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.032 sec - in com.packt.samples.SampleTest

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ transportation-acq-ejb ---
[INFO] Building jar: ~/transportation-project/transportation-acq-ejb/target/transportation-acq-ejb-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ transportation-acq-ejb ---
[INFO] Installing ~/transportation-project/transportation-acq-ejb-0.0.1-SNAPSHOT.jar to ~/.m2/repository/com/packt/examples/transportation-acq-ejb/0.0.1-SNAPSHOT/transportation-acq-ejb-0.0.1-SNAPSHOT.jar
[INFO] Installing ~/transportation-project/transportation-acq-ejb/pom.xml to ~/.m2/repository/com/packt/examples/transportation-acq-ejb/0.0.1-SNAPSHOT/transportation-acq-ejb-0.0.1-SNAPSHOT.pom
[INFO] -----------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -----------------------------------------------------------

Tip

If we run Maven for the first time, in addition to the preceding output shown, we'll see a lot of other output lines saying that project plugins and dependencies are being downloaded from the Maven central repository.

So, as we can see, the sequence of operations performed by Maven follows the steps specified in the default lifecycle. You will also notice that each action performed by Maven is delegated to a certain plugin. In order to compile the project, Maven will download and use the specified dependencies (in this case, Java EE API is needed to compile the EJB classes). Plugins and dependencies are downloaded on-demand, and they are saved in the local repository, which is located under the local user home in the /.m2/repository subdirectory by default.

Tip

For Linux users, the local repository is located under ~/.m2/repository, where ~ means the user home directory that usually has the /home/<username> path.

For Windows users, the local repository is (usually) located under C:Users<username>.m2 epository.

Once Maven downloads an artifact or a plugin, it will reuse its stored copy and never search the same version of this artifact or plugin in the Maven central repository or in other remote repositories that can be specified in our POM file again. The only exception to this rule regarding the snapshot versions is that if the version of a dependency or plugin is marked with the -SNAPSHOT suffix, this version is currently on development. For this reason, Maven will periodically attempt to download this artifact from all the remote repositories that have snapshots enabled in their configurations (refer the Configuring repositories section in this chapter).

If we look in the /target directory, we'll see all the work done by Maven; in this case, the compiled classes, unit test reports, and packaged artifact transportation-acq-ejb-0.0.1-SNAPSHOT.jar:

The default lifecycle

Build output of the transportation-acq-ejb module

Note that if instead of running the previous command, we run the mvn package command, the lifecycle execution will stop with the package phase and the artifact will not be installed in the local repository. This can be a problem if the artifact is needed by other projects as a dependency.

The clean lifecycle

The clean lifecycle is responsible for cleaning the build output. Its phases are as follows:

  • Preclean
  • Clean
  • Postclean

If we run the mvn clean command, the target directory will be deleted, but not the artifact installed in the local repository:

$ mvn clean

Tip

Now, if we build the project again, we'll see that no downloads will take place.

Maven can also be used to generate project documentations in various formats and reports about the project. This is achieved through the site lifecycle. We'll discuss these features in Chapter 4, Managing the Code.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset