JavaData & JavaWhat is Maven? | An Important Tool for Java Developers

What is Maven? | An Important Tool for Java Developers

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

The goal of this article is to provide a good overview of Apache Maven. To answer to the question, “What is Maven?,” we need to cover several topics, but for starters, let’s say that Maven is a great tool that can sustain, support, and assist all stages involved in software development. Apache Maven is ready to serve you for creating a project from scratch, building, testing, reporting, documenting, guiding, ensuring code quality, transparent migration, project modularization, deployment, centralized remote repositories, and so forth, as a complex and comprehensive tool dedicated to software project management. Maven is an important “player” in Agile team collaboration.

Downloading and Installing Maven on Linux/Windows/Mac

Downloading Apache Maven is a very simple task that can be accomplished via the download page. Independently of your operating system, just pick up the desired archive (ZIP or TAR.GZ):

Maven01
Figure 1: Download Apache Maven

For testing the examples from this article, we have downloaded Apache Maven 3.3.9.

The next step is also very simple. Extract the archive content in a convenient location on your computer and try to obtain a path without white-space characters (for example, in Windows, D:Maven (used in this article) or D:toolsMaven-3.3.9).

Ensure JDK Presence

To work properly, Apache Maven needs the Java Development Kit (JDK). For example, Apache Maven 3.3.9 requires JDK 1.7 or above to execute. In case that you don’t know if you have JDK installed, open a command prompt and type java-version. In Figure 2, you can see this command under Windows, but you can use it under Linux or Mac also:

Maven02
Figure 2: Check JDK presence

If JDK is not installed, please follow these instructions. It is mandatory to successfully accomplish this step before going further. So, take your time and pay attention to this step.

Configure Environment Variables

To start using Maven, you need to set a few environment variables as follows: PATH, M2_HOME, and MAVEN_HOME. M2_HOME and MAVEN_HOME must point to the Maven installation folder (for example, D:Maven) and the PATH must point to the /binD:Mavenbin). This is pretty simple to achieve and depends on your OS, but here are some hints.

Configure PATH, MAVEN_HOME, and M2_HOME on Windows

On Windows, you can accomplish this via the Environment Variables wizard available in Control Panel |System and Security |System | Environment Variables.

Maven03
Figure 3: Setting PATH, M2_HOME, and MAVEN_HOME in Windows

Configure PATH, MAVEN_HOME, and M2_HOME on Linux

On Linux, you need to export the PATH, MAVEN_HOME, and M2_HOME environment variables in the .bashrc file. This file can be found in the user’s home folder, which for me is /home/leonard/.bashrc:

export MAVEN_HOME=/home/leonard/Maven
export M2_HOME=/home/leonard/Maven
export PATH=${PATH}:${M2_HOME}/bin

Configure PATH, MAVEN_HOME, and M2_HOME on Mac

On a Mac, you need to export the PATH, MAVEN_HOME, and M2_HOME environment variables in the .bash_login:

export MAVEN_HOME=/usr/local/Maven
export M2_HOME=/usr/local/Maven
export PATH=${PATH}:${M2_HOME}/bin

Verify Maven Installation

After you download and install Maven, it is a good practice to ensure that Maven is ready to go. For this, independent of the OS, you can execute mvn -version in a command-line terminal window. In Figure 4, you can see this under Windows:

Maven04
Figure 4: Verify Maven installation

So, if you see output like in Figure 4, Maven is working as expected. From this point forward, the presented examples will consider Windows as the OS.

Create/Generate a Maven Project

Maven is basically a suite of plug-ins that work together or separately (plug-in centric) to accomplish different kind of tasks. For example, Maven allows us to create a Java project from Maven archetypes (templates) or from a pom.xml file. Among Maven archetypes we have:

An archetype to generate a sample Maven project: maven-archetype-quickstart

An archetype to generate a simplified sample J2EE application: maven-archetype-j2ee-simple

An archetype to generate a sample Maven Web application project: maven-archetype-webapp

...

To create a new Maven project from an archetype, we can use the following command (replace archetype_artifactId with the artifactId of the desired archetype):

mvn archetype:generate -DarchetypeArtifactId=archetype_artifactId>

Or, if you also need to specify the groupId, use this:

mvn archetype:generate -DarchetypeGroupId=archetype_groupId
                       -DarchetypeArtifactId=archetype_artifactId

We also can choose the desired archetype during project creation via the following command:

mvn archetype:generate

Create a Quickstart Java SE Project

Okay, so let’s try the mvn archetype:generate for creating (generating) a quickstart Java SE project. Navigate from the command line to a convenient location (where you want to store the project) and type the preceding command. At the beginning, you see something like in Figure 5:

Maven05
Figure 5: Create first Maven project

The first thing you must specify is the archetype that you intend to use for this project. Before Maven prompts you to do that, you will see a very long list with the available archetypes (1500+). Each archetype is listed with a number (identifier), a name, and a short description meant to provide a hint about its purpose. By default, Maven will suggest that you choose the maven-archetype-quickstart archetype which is identified by the number 784. We have cropped the relevant part in Figure 6:

Maven06
Figure 6: Choose the desired archetype

Because we want to go for maven-archetype-quickstart, simply press Enter. Furthermore, Maven will list the available versions for the selected archetype and suggest you to use the latest version. Again, you can just press Enter to go with the latest version:

Maven07
Figure 7: Choose the archetype version

After several downloads, you will be prompted to provide the project “landmarks” (known as Maven coordinates) such as groupId, artifactId, version, and package:

  • groupId: The unique hierarchical location of a project within a Maven repository. We use the local Maven repository that resides on your computer. Here, you can put something composed from your organization (domain) name and the project name (for example, org.mycompany.myproj). Further sub-modules can be derived from this name (for example, org.mycompany.myproj.subproj1). Following this naming convention, you can easily “navigate” through the project structure.
  • artifactId: Represents the name of the project without version (for example, myproj). Typically, this is the name of the project as it is known by its users (for example, OmniFaces, PrimeFaces, and so on).
  • version: Represents the version of the project. This can follow any version convention (for example, 1.0, 1.1, 1.2, and the like). Maven suggests using the 1.0-SNAPSHOT style.
  • package: Indicates the package name where the sources will be stored.

So, for groupId, we have specified org.quickstart; for artifactId, we have specified quickstart; for version, we have specified 1.0; and for package, we have specified the same as for groupId:

Maven08
Figure 8: Finalization of project creation

After we provide the Maven coordinates, the project is successfully created and is ready to go. In Figure 9, you can see what Maven has generated for us:

Maven09
Figure 9: Maven-generated Java SE project

Create a Java EE 7 Starter Project for JBoss WildFly

Another common type of projects generated via Maven archetypes are Java Web/enterprise projects. This time, let’s create a Java EE 7 starter project for JBoss Wildfly by indicating the archetype groupId and artifactId right from command line (the code of this project is 1543):

Maven10
Figure 10: Generate a Java Web project

Take your time to check the generated project. As you will see, it has a significant number of folders and files.

Compile and Test a Project

Compiling and testing the project are two of the main objectives that must be successfully accomplished to deliver a working software package. So, let’s see how we can do that via Maven.

Compile the Project

To compile a Maven project, we need to execute from a command-line terminal window the following command: mvn compile (by default, Maven supports several goals and compile is one of them; among the most popular we have: clean, package, deploy, test, and install). So, let’s compile our Java SE and web project; notice that we execute this command from the project folder:

Maven11
Figure 11: Compile the Java SE project

The result of compilation (Java classes) can be seen in the /quickstart/target/classes folder. Now, let’s compile the Java EE 7 application:

Maven12
Figure 12: Compile the Java Web project

The result of compilation (Java classes) can be seen in the /javaee7.quickstart/target/classes folder.

Test the Project

Another part of the default build lifecycle is represented by the capability of testing the project. To sustain a TDD (Test Driven Development) pattern, Maven provide the test feature via the mvn test command. Via this command, we will execute the tests located in the src/test folder. For our Java SE application, we have a single test named AppTest:

Maven13
Figure 13: Testing the Java SE application

We should do the same for our Java EE 7 application. In this case, the test is also located in the src/test folder and it is named MemberRegistrationTest. But, this test is not as easy as for the Java SE app, so you must have some patience and read further. Later on, you will see this test also.

What Is POM (Project Object Model)?

Basically, the presence of a pom.xml file in a project is a clear indicator that this is a Maven project. Maven knows this file as the XML representation of the project. This file may contain a lot of information, such as metadata, dependencies, configurations, project organization, paths, profiles, and so forth. If you check, there are two projects; you can notice that both of them contain a pom.xml file in the root. Although the pom.xml file for the Java SE application is pretty short and simple, the pom.xml file for the Java EE 7 application is quite big and complex. So, let’s see the structure of a POM file:

<project ... >

   <modelVersion>4.0.0</modelVersion>

   <!-- The Basics -->

   <groupId>...</groupId>
   <artifactId>...</artifactId>
   <version>...</version>
   <packaging>...</packaging>
   <dependencies>...</dependencies>
   <parent>...</parent>
   <dependencyManagement>...</dependencyManagement>
   <modules>...</modules>
   <properties>...</properties>

   <!-- Build Settings -->
   <build>...</build>
   <reporting>...</reporting>

   <!-- More Project Information -->
   <name>...</name>
   <description>...</description>
   <url>...</url>
   <inceptionYear>...</inceptionYear>
   <licenses>...</licenses>
   <organization>...</organization>
   <developers>...</developers>
   <contributors>...</contributors>

   <!-- Environment Settings -->
   <issueManagement>...</issueManagement>
   <ciManagement>...</ciManagement>
   <mailingLists>...</mailingLists>
   <scm>...</scm>
   <prerequisites>...</prerequisites>
   <repositories>...</repositories>
   <pluginRepositories>...</pluginRepositories>
   <distributionManagement>...</distributionManagement>
   <profiles>...</profiles>
</project>

Let’s have a few words about each section and let’s try to identify some of them in the pom.xml of the Java EE 7 application:

<!-- The Basics -->

In this part, we have the project coordinates, dependencies, dependency management, and inheritance details. Moreover, it may contain modules and some project-level properties. Take your time and try to dissect this part extracted from the Java EE 7 application pom.xml file; don’t hesitate to carefully read the comments because is a good way of learning by example:

...
<groupId>org.javaee7.quickstart</groupId>
<artifactId>javaee7.quickstart</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<name>WildFly Quickstarts: javaee7.quickstart</name>
<description>A starter Java EE 7 webapp project for use on
    JBoss WildFly / WildFly, generated from the
    jboss-javaee6-webapp archetype</description>

   <properties>
      <!-- Explicitly declaring the source encoding
           eliminates the following message: -->
      <!-- [WARNING] Using platform encoding (UTF-8 actually)
           to copy filtered resources, i.e. build is platform
           dependent! -->
      <project.build.sourceEncoding>
         UTF-8
      </project.build.sourceEncoding>

      <!-- JBoss dependency versions -->
      <version.wildfly.maven.plugin>
         1.0.2.Final
      </version.wildfly.maven.plugin>

      <!-- Define the version of the JBoss BOMs we want
           to import to specify tested stacks. -->
      <version.jboss.bom>8.2.1.Final</version.jboss.bom>

      <!-- other plugin versions -->
      <version.compiler.plugin>3.1</version.compiler.plugin>
      <version.surefire.plugin>2.16</version.surefire.plugin>
      <version.war.plugin>2.5</version.war.plugin>

      <!-- maven-compiler-plugin -->
      <maven.compiler.target>1.7</maven.compiler.target>
      <maven.compiler.source>1.7</maven.compiler.source>
   </properties>

   <dependencyManagement>
      <dependencies>
      <!-- JBoss distributes a complete set of Java EE 7 APIs
           including a Bill of Materials (BOM). A BOM specifies the
           versions of a "stack" (or a collection) of
           artifacts. We use this here so that we always get the
           correct versions of artifacts. Here we use the
           jboss-javaee-7.0-with-tools stack (you can read this as
           the JBoss stack of the Java EE 7 APIs, with some extras
           tools for your project, such as Arquillian for testing)
           and the jboss-javaee-7.0-with-hibernate stack you can
           read this as the JBoss stack of the Java EE 7 APIs, with
           extras from the Hibernate family of projects) -->
         <dependency>
            <groupId>org.wildfly.bom</groupId>
            <artifactId>jboss-javaee-7.0-with-tools</artifactId>
            <version>${version.jboss.bom}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
         <dependency>
            <groupId>org.wildfly.bom</groupId>
            <artifactId>jboss-javaee-7.0-with-hibernate</artifactId>
            <version>${version.jboss.bom}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>

   <dependencies>
      <!-- First declare the APIs we depend on and need for compilation.
           All of them are provided by JBoss WildFly -->

      <!-- Import the CDI API, we use provided scope as the API is
           included in JBoss WildFly -->
      <dependency>
         <groupId>javax.enterprise</groupId>
         <artifactId>cdi-api</artifactId>
         <scope>provided</scope>
      </dependency>

      <!-- Import the Common Annotations API (JSR-250), we use
           provided scope as the API is included in JBoss WildFly -->
      <dependency>
         <groupId>org.jboss.spec.javax.annotation</groupId>
         <artifactId>jboss-annotations-api_1.2_spec</artifactId>
         <scope>provided</scope>
      </dependency>

      <!-- Import the JAX-RS API, we use provided scope as the API is
           included in JBoss WildFly -->
      <dependency>
         <groupId>org.jboss.resteasy</groupId>
         <artifactId>jaxrs-api</artifactId>
         <scope>provided</scope>
      </dependency>

      <!-- Import the JPA API, we use provided scope as the API is
           included in JBoss WildFly -->
      <dependency>
         <groupId>org.hibernate.javax.persistence</groupId>
         <artifactId>hibernate-jpa-2.1-api</artifactId>
         <scope>provided</scope>
      </dependency>

      <!-- Import the EJB API, we use provided scope as the API is
           included in JBoss WildFly -->
      <dependency>
         <groupId>org.jboss.spec.javax.ejb</groupId>
         <artifactId>jboss-ejb-api_3.2_spec</artifactId>
         <scope>provided</scope>
      </dependency>

      <!-- JSR-303 (Bean Validation) Implementation -->
      <!-- Provides portable constraints such as @Email -->
      <!-- Hibernate Validator is shipped in JBoss WildFly -->
      <dependency>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-validator</artifactId>
         <scope>provided</scope>
         <exclusions>
            <exclusion>
               <groupId>org.slf4j</groupId>
               <artifactId>slf4j-api</artifactId>
            </exclusion>
         </exclusions>
      </dependency>

      <!-- Import the JSF API, we use provided scope as the API is
           included in JBoss WildFly -->
      <dependency>
         <groupId>org.jboss.spec.javax.faces</groupId>
         <artifactId>jboss-jsf-api_2.2_spec</artifactId>
         <scope>provided</scope>
      </dependency>

      <!-- Now we declare any tools needed -->

      <!-- Annotation processor to generate the JPA 2.0 metamodel
           classes for typesafe criteria queries -->
      <dependency>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-jpamodelgen</artifactId>
         <scope>provided</scope>
      </dependency>

      <!-- Annotation processor that raising compilation errors
           whenever constraint annotations are incorrectly used. -->
      <dependency>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-validator-annotation-processor</artifactId>
         <scope>provided</scope>
      </dependency>

      <!-- Needed for running tests (you may also use TestNG) -->
      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <scope>test</scope>
      </dependency>

      <!-- Optional, but highly recommended -->
      <!-- Arquillian allows you to test enterprise code such as
           EJBs and Transactional(JTA) JPA from JUnit/TestNG -->
      <dependency>
         <groupId>org.jboss.arquillian.junit</groupId>
         <artifactId>arquillian-junit-container</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>org.jboss.arquillian.protocol</groupId>
         <artifactId>arquillian-protocol-servlet</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
...

<!-- Build Settings -->

This section is reserved for build details as your project’s directory structure and managing plug-ins. For example, our pom.xml study case declares here the WildFly plug-in for deploying the application WAR to a local WildFly container:

...
<build>
   <!-- Maven will append the version to the finalName
        (which is the name given to the generated war,
        and hence the context root) -->
   <finalName>${project.artifactId}</finalName>
   <plugins>
      <plugin>
         <artifactId>maven-war-plugin</artifactId>
         <version>${version.war.plugin}</version>
         <configuration>
            <!-- Java EE 7 doesn't require web.xml,
                 Maven needs to catch up! -->
            <failOnMissingWebXml>false</failOnMissingWebXml>
         </configuration>
      </plugin>
      <!-- The WildFly plugin deploys your war to a local
           WildFly container -->
      <!-- To use, run: mvn package wildfly:deploy -->
      <plugin>
         <groupId>org.wildfly.plugins</groupId>
         <artifactId>wildfly-maven-plugin</artifactId>
         <version>${version.wildfly.maven.plugin}</version>
      </plugin>
   </plugins>
</build>
...

<!-- More Project Information -->

This section is useful for providing in-depth details about licenses, organization, developers, and contributors. In our case study, this section is like this:

...
<url>http://wildfly.org</url>
<licenses>
   <license>
      <name>Apache License, Version 2.0</name>
      <distribution>repo</distribution>
      <url>
         http://www.apache.org/licenses/LICENSE-2.0.html
      </url>
   </license>
</licenses>
...

<!– Environment Settings –>

In this section, we have all information regarding the environment including issue management (defect tracking system), continuous integration management, mailing lists, SCM (Software Configuration Management), prerequisites, repositories, profiles, and so on. In our case study, we have several profiles:

...
<profiles>
   <profile>
      <!-- The default profile skips all tests, though you can tune
           it to run just unit tests based on a custom pattern -->
      <!-- Seperate profiles are provided for running all tests,
           including Arquillian tests that execute in the specified
           container -->
      <id>default</id>
      <activation>
         <activeByDefault>true</activeByDefault>
      </activation>
      <build>
         <plugins>
            <plugin>
               <artifactId>maven-surefire-plugin</artifactId>
               <version>${version.surefire.plugin}</version>
               <configuration>
                  <skip>true</skip>
               </configuration>
            </plugin>
         </plugins>
      </build>
   </profile>

   <profile>
      <!-- An optional Arquillian testing profile that executes
           tests in your WildFly instance -->
      <!-- This profile will start a new WildFly instance, and
           execute the test, shutting it down when done -->
      <!-- Run with: mvn clean test -Parq-wildfly-managed -->
      <id>arq-wildfly-managed</id>
      <dependencies>
         <dependency>
            <groupId>org.wildfly</groupId>
            <artifactId>
               wildfly-arquillian-container-managed
            </artifactId>
            <scope>test</scope>
         </dependency>
      </dependencies>
   </profile>

   <profile>
      <!-- An optional Arquillian testing profile that executes
           tests in a remote WildFly instance -->
      <!-- Run with: mvn clean test -Parq-wildfly-remote -->
      <id>arq-wildfly-remote</id>
      <dependencies>
         <dependency>
            <groupId>org.wildfly</groupId>
            <artifactId>
               wildfly-arquillian-container-remote
            </artifactId>
           <scope>test</scope>
        </dependency>
   </profile>

   <profile>
      <!-- When built in OpenShift the 'openshift' profile will
           be used when invoking mvn. -->
      <!-- Use this profile for any OpenShift specific
           customization your app will need. -->
      <!-- By default, that is to put the resulting archive into
           the 'deployments' folder. -->
      <!-- http://maven.apache.org/guides/mini/
           guide-building-for-different-environments.html -->
      <id>openshift</id>
      <build>
         <plugins>
            <plugin>
               <artifactId>maven-war-plugin</artifactId>
               <version>${version.war.plugin}</version>
               <configuration>
                  <outputDirectory>
                     deployments
                  </outputDirectory>
                  <warName>ROOT</warName>
               </configuration>
            </plugin>
         </plugins>
      </build>
   </profile>
</profiles>
...

A detailed POM explanation can be found here.

Build Lifecycles

There are three built-in build lifecycles: default, clean, and site.

Default Lifecycle

When we refer to a Maven build lifecycle, we refer to a suite of phases that Maven is taking into account to build a project. Even though phases such as compile, test, or deploy are pretty well-known, you have to know that Maven actually has eight “major” phases, as shown in Figure 14 (there is also a set of “minor” phases not listed here):

Maven14
Figure 14: Maven build lifecycle

  • validate: Validates that all project information is available and is correct
  • compile: Compiles the project’s source code
  • test: Runs unit tests inside the proper framework
  • package: Packages the compiled code in its distribution format (for example, JAR, WAR, and the like)
  • integration-test: Takes the package in the integration-test environment
  • verify: Checks the package validity
  • install: To re-use the package locally in other projects, Maven installs the package in the local repository
  • deploy: The final package is installed in the remote repository (for example, Nexus, Artifactory, or even Maven Central) and is ready to be shared by other projects/developers.

Clean Lifecycle

The clean process is responsible for cleaning the project for files generated at compilation, additional files, and so forth. This is accomplished in three “minor” phases:

  • pre-clean: Executes before project cleaning
  • clean: Deletes all files from previous builds
  • post-clean: Finalizes project cleaning

Site Lifecycle

The site process is able to generate and deploy the project’s site documentation. It has four “minor” phases:

  • pre-site: Executes before generation of the site
  • site: Generates the project’s site documentation
  • post-site: Finalizes the site generation and gets ready for site deployment
  • site-deploy: Deploys the site documentation to the specified server

Command Commands

Let’s see several common commands that involve the build lifecycle phases. In the section Compile and test a project, you already saw mvn compile and mvn test at work, so let’s see some more:

Clean

  • mvn clean: Cleans the project

Maven15
Figure 15: Cleaning the Java EE 7 project

Package

  • mvn package: Packages the application

Maven16
Figure 16: Packaging the Java EE 7 project into a WAR

Deploy

  • mvn deploy: Deploys the application

Here, we must have a little discussion because this command is more tricky. If you try this command for the Java EE 7 application, you will receive an error like in Figure 17:

Maven17
Figure 17: Trying to deploy the Java EE 7 application

To understand this idea, you must know a few additional things. First, we must distinguish between repository deployment and application server deployment. The default deploy phase of Maven is considering repository deployment, which means that you try to deploy your artifact (application) on a remote repository (release or snapshot) location as Nexus, Artifactory, or even Maven Central. Basically, we try to use the Maven Deploy Plugin, which has two goals (known as Mojos). The first one is deploy:deploy (the deploy phase of the build lifecycle is implemented via this Mojo), and the second one is deploy:deploy-file (not discussed here). Now, we will focus on the first Mojo, deploy:deploy. To work, this Mojo needs a <distributionManagement/> section in pom.xml. This section should supply at least a <repository/> defining the remote repository location for your artifact. When your repository also needs authentication, you need a <server/> entry in your settings.xml file (this file can be found in MAVEN_HOME/conf folder). So, our error message means that we never specified a remote repository.

Now, in terms of Java EE, by deploy, we understand application server deployment. This means that some application server (for example, WildFly, GlassFish, Tomcat, and so on) will be aware of our application and it will expose it for usage in a browser. So, asking Maven to deploy an application will not result in its application server deployment. To accomplish application server deployment, you need a special plugin, such as the WildFly Maven Plugin. This plugin comes with several goals, as: wildfly:deploy, wildfly:run, and the like.

Let’s suppose that we want to deploy our Java EE 7 application on a WildFly application server. We can accomplish this very easily because our pom.xml comes with this plugin configured. This is normal, because we have generated the project from a WildFly dedicated Maven archetype. Here is the plugin:

<!-- The WildFly plugin deploys your war to a local WildFly
     container -->
<!-- To use, run: mvn package wildfly:deploy -->
<plugin>
   <groupId>org.wildfly.plugins</groupId>
   <artifactId>wildfly-maven-plugin</artifactId>
   <version>${version.wildfly.maven.plugin}</version>
</plugin>

This means that we can use the goals of WildFly Maven Plugin out-of-the-box. For example, if you want Maven to download WildFly, start it and deploy our Java EE 7 application; then, you can simply execute the mvn wildfly:run command. Just ensure that the default WildFly ports are free (8080 and 9990). When Maven finishes the job, you will be able to see the application at http://localhost:8080/javaee7.quickstart:

Maven18
Figure 18: Deploying our Java EE 7 application on WildFly application server via Maven

If you already have WildFly installed, you can start it easily and execute the mvn wildfly:deploy command. This will deploy the application on your WildFly. Check out the rest of goals here.

Working with Profiles

Among the advantages provided by Maven, we have project portability. Maven tries to keep the projects independent (portable) across filesystem references via local repository and pom.xml configurations.

When portability is affected (which means that the independency of the filesystem cannot be achieved), Maven provides a solution materialized in profiles. Profiles are defined in pom.xml and they are demarcated by the <profile/> tag. Profiles can be triggered: through the command line using the -P option, via Maven settings, or environment specific triggers.

If we take a closer look to the pom.xml of our Java EE 7 application, we notice several profiles, as follows (please, read the comments because they help you to understand what each profile does):

...
<profiles>
   <profile>
      <!-- The default profile skips all tests, though you
           can tune it to run just unit tests based on a
           custom pattern -->
      <!-- Seperate profiles are provided for running all
           tests, including Arquillian tests that execute in the
           specified container -->
      <id>default</id>
      <activation>
         <activeByDefault>true</activeByDefault>
      </activation>
      <build>
         <plugins>
            <plugin>
               <artifactId>maven-surefire-plugin</artifactId>
               <version>${version.surefire.plugin}</version>
               <configuration>
                  <skip>true</skip>
               </configuration>
            </plugin>
         </plugins>
      </build>
   </profile>

   <profile>
      <!-- An optional Arquillian testing profile that executes tests in
           your WildFly instance -->
      <!-- This profile will start a new WildFly instance, and execute
           the test, shutting it down when done -->
      <!-- Run with: mvn clean test -Parq-wildfly-managed -->
      <id>arq-wildfly-managed</id>
      <dependencies>
         <dependency>
            <groupId>org.wildfly</groupId>
            <artifactId>
               wildfly-arquillian-container-managed
             </artifactId>
            <scope>test</scope>
         </dependency>
      </dependencies>
   </profile>

   <profile>
      <!-- An optional Arquillian testing profile that executes tests
           in a remote WildFly instance -->
      <!-- Run with: mvn clean test -Parq-wildfly-remote -->
      <id>arq-wildfly-remote</id>
      <dependencies>
         <dependency>
            <groupId>org.wildfly</groupId>
            <artifactId>
               wildfly-arquillian-container-remote
            </artifactId>
            <scope>test</scope>
         </dependency>
      </dependencies>
   </profile>

   <profile>
      <!-- When built in OpenShift the 'openshift' profile will be
           used when invoking mvn. -->
      <!-- Use this profile for any OpenShift specific customization
           your app will need. -->
      <!-- By default that is to put the resulting archive into the
           'deployments' folder. -->
      <!-- http://maven.apache.org/guides/mini/guide-building-for-
           different-environments.html -->
      <id>openshift</id>
      <build>
         <plugins>
            <plugin>
               <artifactId>maven-war-plugin</artifactId>
               <version>${version.war.plugin}</version>
               <configuration>
                  <outputDirectory>deployments</outputDirectory>
                  <warName>ROOT</warName>
               </configuration>
            </plugin>
         </plugins>
      </build>
   </profile>
</profiles>
...

As you can see, all the above profiles are dedicated to testing the application. For example, let’s try to test our Java EE 7 application via mvn clean test -Parq-wildfly-remote. First, download, install, and start JBoss WildFly 10.0.0 with default settings (ports 8080 and 9990) on your computer. You can easily start it from the command line by executing the standalone batch file:

Maven19
Figure 19: Running standalone WildFly from the command line

Furthermore, open a new command prompt and execute mvn clean test -Parq-wildfly-remote. You may notice that Maven will deploy the application on WildFly, execute the tests, and un-deploy the application:

Maven20
Figure 20: Execute tests

You can read more about Maven profiles here.

Build Automation

As you saw in the previous sections, Maven builds a project by executing several phases of the build lifecycle. You know that, to test an application, you can sequentially execute the following commands:

// 1. Execute validate and wait to finish
mvn validate
...
// 2. Execute compile and wait to finish
mvn compile
...
// 3. Execute package and wait to finish
mvn package
...
// 4. Execute test and wait to finish
mvn test

Although these are individual commands executed one by one, Maven allows us to automate the process by executing the last of the phases (we choose which one to be the last). When you specify a certain phase, Maven will execute every build phase that is before the called build phase. For example, if you execute the test phase, Maven will execute all build phases before it. This means that instead of executing four different commands, we can simply execute only the last one as mvn test. Maven will execute validate, compile, and package as a result of automation skills. Or, if we execute mvn deploy, Maven will execute all build phases.

Project Modularization

Maven project modularization, or multi-modular projects, consist of a Parent Project that contains Child Projects known as Modules. Practically, this is a technique of organizing large projects that can be divided in sub-modules. The Parent Project contains a POM file that defines the containing sub-modules. Each sub-module has its own POM, also. Check Figure 21:

Maven21
Figure 21: Maven modularization

To provide an example, we start by creating a new pom.xml file in the main application folder. We name this folder MyBigApp and the pom.xml looks like the following; it’s important to notice the <packaging>pom</packaging> part:

<?xml version="1.0" encoding="UTF-8"?>
<project 
         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>my.big.apps</groupId>
   <artifactId>BigApp</artifactId>
   <version>1.0</version>
   <packaging>pom</packaging>
   <name>MyBigApp</name>
</project>

Further, navigate from the command line in the MyBigApp folder and generate the exact same projects as we did earlier in this article. First, the Java SE quickstart:

Maven22
Figure 22: Generate the Java SE quickstart application

Next, create the Java EE 7 quickstart application:

Maven23
Figure 23: Generate the Java EE 7 quickstart application

After the job is done, take a look into the main pom.xml file and notice the <modules/> section:

...
<modules>
   <module>quickstart</module>
   <module>javaee7.quickstart</module>
</modules>
...

Now, you can compile the entire project from the MyBigApp folder via mvn compile:

Maven24
Figure 24: Compile a project based on multiple modules

Dependency Management

Probably the most known feature of Maven is represented by the dependency management (managing the dependency of the current project of other libraries, projects, and tools). Since version 2, Maven provides transient dependency, which means that Maven will automatically discover artifacts that your dependencies require. In POM, the dependencies section is demarcated by the <dependencies/> tag and each dependency is demarcated by the <dependency/> tag. Essentially, the code skeleton looks like this:

<dependencies>
   <dependency>
      <groupId>...</groupId>
      <artifactId>...</artifactId>
      <version>...</version>
      <scope>...</scope>
   </dependency>
   <dependency>
      ...
   </dependency>
   ...
</dependencies>

Dependencies Scopes

There are six dependencies scopes as follows (the scope is specified in the <scope/> tag):

  • compile (default): Dependencies are available in the classpaths.
  • provided: JDK or the environment provides dependencies at runtime.
  • runtime: Dependencies are required at runtime and are indicated in the runtime classpaths.
  • test: Dependencies required for test compilation and execution.
  • system: Dependency is always available, but the JAR is provided anyway.
  • import: Imports dependencies specified in POM included via the <dependencyManagement/> element.

Dependencies Plug-in

The dependency plug-in is a very useful tool. As you can see here, this plug-in comes with a significant number of goals. Among these, the most used are listed below:

dependency:analyze: Performs dependencies analysis and reports the dependencies that are: used and declared; used and undeclared; unused and declared. For our Java EE 7 application, you can see the output in Figure 25:

Maven25
Figure 25: Executing dependency:analyze

dependency:analyze-duplicate: Performs an analysis of the <dependencies/> and <dependencyManagement/> tags and determines the duplicate declared dependencies:

Maven26
Figure 26: Executing dependency:analyze-duplicate

dependency:resolve: Instructs Maven to resolve all dependencies and displays the version.

dependency:resolve-plugin: Resolves all plug-ins.

dependency:tree: Displays dependency trees.

Generating Javadoc

To generate Javadoc (API documentation in HTML), we can use the Maven Javadoc plug-in. Among its 10+ goals, we have the one that generates the documentation for the project. This is javadoc:javadoc and you can see it at work in Figure 27:

Maven27
Figure 27: Executing javadoc:javadoc

For the Java EE 7 project, the documentation will be located in the javaee7.quickstart/target/site/apidocs folder. Simply open the index.xhtml file in your browser.

Generating Unit Tests Reports

The Maven Surefire plug-in is fully capable to run the unit tests, generate plain text, and XML reports of the tests. The only goal of this plug-in is surefire:test. Normally, you will have this plug-in already available in your pom.xml or you should add it manually, as shown below:

<version.surefire.plugin>2.16</version.surefire.plugin>
...
<build>
   <plugins>
      <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <version>${version.surefire.plugin}</version>
         <configuration>
            <skip>false</skip>
         </configuration>
      </plugin>
   </plugins>
</build>

To execute the Sunfire plug-in, simply execute the command mvn test. To see the output to the console, use mvn test -Dsurefire.useFile=false.

Summary

In this article, we have covered some of the main aspects of Maven. You have to know that Maven can do more than this, and it is a very important tool in any developer arsenal. In addition to what was discussed here, you may also be interested in generating code coverage reports, creating centralized remote repositories, Java/Google/Scala/Groovy/Flex … and Maven, IDE integration, and so on.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories