Learn Apache Maven to create, manage and automate Java projects

Neeraj Kushwaha
11 min readSep 25, 2022

--

This article is originally published at https://www.learncsdesign.com

As with other craftsmen, software developers rely on their tools to build applications. In the day-to-day development and maintenance of quality software, tools such as IDEs, bug tracking tools, build tools, frameworks, containers, and debug tools, such as memory analyzers, play a vital role.

Apache Maven is an open-source, standards-based project management framework designed to simplify the building, testing, reporting, and packaging of the software.

Maven is one of the most widely used open-source software programs in enterprises around the world because:

1. Standardized Directory Structure

Whenever we start a new project, we spend considerable time deciding on the project layout and folder structure needed to store code and configuration files. Maven standardizes the folder structure and organization of a project, including source code, test code, and configuration files.

2. Declarative Dependency Management

Java projects depend heavily on other projects and open source frameworks to function. It can be tedious to manually download dependencies and keep track of their versions. Maven provides an easy way to declare these dependencies in a separate file pom.xml. Then, it automatically downloads those dependencies and allows you to use them in your project.

3. Plugins

The plugin-based architecture of Maven makes it easy to add and customize its functionality. Maven plugins provide reusable build and task logic.

4. Uniform Build Abstraction

For building projects, Maven provides a uniform interface. Using a few commands, you can build a Maven project.

5. Tools Support

Maven provides a powerful command-line interface for performing different operations. Maven is supported by all major IDEs and continuous integration products, such as Jenkins.

6. Archetypes

Maven provides a standard directory structure for its projects. Maven archetypes are predefined project templates that can be used to create new projects. You will find all the folders and files needed to get started in an archetype-based project.

7. Convention Over Configuration

Maven is based on the principle of convention over configuration (CoC). It emphasizes sensible defaults, thereby reducing the number of decisions to be made. This saves time as well as simplifies the end product since the amount of configuration is drastically reduced.

Maven Components

Maven utilizes several components in order to accomplish its tasks:

  • Maven SCM — Maven can interact with several source code management systems to perform functions such as checking out code or creating a branch. The Maven SCM project provides a common API for performing such operations.
  • Maven Wagon — Maven automatically downloads project dependencies like JAR files from FTP servers, file systems, and websites. Maven Wagon provides a transport abstraction that enables Maven to interact with different transport protocols and retrieve dependencies.
  • Maven Doxia — It is a framework for generating static and dynamic content, such as PDF files and web pages. Doxia is used heavily by Maven to generate project documentation and reports.

Setting Up Maven

Apache Maven is installed by extracting the archive and adding the bin folder to the PATH variable with the mvn command. Follow the instructions in the Maven installation guide.

Maven Dependency Management

Maven manages dependencies declaratively. You declare your project’s dependencies in an external file called pom.xml. Maven will automatically download those dependencies and pass them on to your project for building, testing, and packaging.

Maven connects to the network and downloads artifacts and metadata from remote repositories the first time it is run. Maven Central is the default remote repository and can be found at https://repo.maven.apache.org/maven2. Maven stores a copy of these downloaded artifacts in its local repository. Maven will look for an artifact in its local repository and if it is not found, it will attempt to download it from a remote repository.

As part of an enterprise environment, the company maintains a repository manager that acts as a proxy to remote repositories. Enterprises have full control over their internal repository, so they can decide which types of artifacts are allowed. Furthermore, teams can also push internal artifacts to the repository manager, enabling collaboration. The most popular open-source repository managers are Sonatype Nexus and Apache Archiva.

Configuration specific to a user/enterprise is stored in a settings.xml file. Maven looks for the settings.xml file in two locations: the Maven installation’s conf folder and the .m2 folder in the user’s home directory. In the conf folder, settings.xml is referred to as global settings, and in the .m2 folder, user settings. Maven will merge the contents of both files if both exist, and the user setting will prevail.

Dependency Identification

Maven dependency coordinates are used to uniquely identify each dependency:

  • groupId — Identifies the organization responsible for this project. For example, org.springframework.
  • artifactId — Artifact identifier generated by the project. It must be unique among all projects using the same groupId. For example, spring-orm.
  • version — This indicates the project’s version number. For example, 1.0.0 or 1.0.0-SNAPSHOT. Those artifacts in development are labeled with a SNAPSHOT in their version. This tells Maven to check remote repositories for the latest version of the artifact.

The dependencies tag is used in pom.xml to declare dependencies.

Transitive Dependencies

Often, dependencies declared in your project’s pom.xml file have their own dependencies. These dependencies are called transitive dependencies. A key benefit of Maven is that it automatically deals with transitive dependencies and includes them in your project.

In order to resolve version conflicts, Maven uses a technique known as dependency mediation. Maven uses dependency mediation to pull the dependency that is closest to the project in the dependency tree. Maven provides a dependency plugin that lets you visualize a project’s dependency tree.

When you do not want to include certain transitive dependency JARs in the archive, you can use the exclusion element which takes the groupId and artifactId coordinates of the dependency to exclude them.

Maven Project Organization

Let’s talk about how Maven provides archetypes to bootstrap projects quickly that lay out the project directories.

.
├── pom.xml
├── src
│ ├── main
│ │ └── java
│ │ └── com
│ │ └── learncsdesign
│ │ └── App.java
│ └── test
│ └── java
│ └── com
│ └── learncsdesign
│ └── AppTest.java
└── target
  • pom.xml — At the root of every Maven project is a pom.xml. It contains project and configuration information, such as dependencies and plugins.
  • src — The files in this folder are project-related artifacts such as source code or property files.
  • src/main/java — The Java source code is contained in this folder.
  • src/test/java — The Java unit test code is located in this folder.
  • target — It holds generated artifacts such as .class files.

Demystifying POM

POM stands for Project Object Model. The file pom.xml contains the XML representation of the Maven project. A POM contains information about a project, as well as configurations for plugins to be used during the build process.

We will take a quick look at some of the elements directly under POM’s project element.

Maven Coordinates

The POM defined below is the bare minimum supported by Maven.

GroupId:ArtifactId:version serves as a coordinate in the Maven repository to locate them. These 3 elements were already discussed earlier.

Packaging

The packaging element explains what the project’s packaging is. Maven assumes the default packaging is jar when no packaging is declared.

Pom, jar, maven-plugin, ejb, war, ear, rar are the current core packaging values.

Dependencies

The majority of projects depend on others to build and run correctly. Maven adds the dependencies of those dependencies (transitive dependencies).

Dependency Scope

As an example, consider a Java project that uses JUnit for its unit testing. You do not need to bundle the JUnit JAR file in the final production archive since the JUnit JAR file you included in your project is only needed during testing.

Maven has the concept of scope, which lets you specify when and where a dependency is needed.

Maven provides the following six scopes:

  1. compile — Dependencies with the compile scope are available in the classpath in all phases of a project build, test, and run. This is the default scope.
  2. provided — Dependencies with the provided scope are available in the classpath during the build and test phases. They don’t get bundled within the generated artifact.
  3. runtime — Dependencies with the runtime scope are not available in the classpath during the build phase. Instead, they get bundled in the generated artifact and are available during runtime.
  4. test — Dependencies with the test scope are available during the test phase.
  5. system — Dependencies with the system scope are similar to dependencies with the provided scope, except that these dependencies are not retrieved from the repository. Instead, a hard-coded path to the file system is specified from where the dependencies are used.
  6. import — The import scope is applicable for .pom file dependencies only. It allows you to include dependency management information from a remote .pom file.

Properties

Maven provides properties, also known as placeholders, that are used in pom.xml file. Maven properties are referenced with the ${property_name} notation. There are two types of properties: implicit and user-defined.

Implicit Properties — The implicit properties are available to any Maven project by default. For example, Maven exposes its POM properties using the project prefix, so to access an artifact inside the pom.xml, simply use ${project.artifactId}.

User-Defined Properties — Maven allows you to declare custom properties in pom.xml file using the properties element. In this case, we define the property junit.version which will be referenced in the dependency for JUnit.

Maven Lifecycle

Maven provides a uniform interface for creating and distributing projects through its lifecycle.

Goals and Plugins

In order to build artifacts such as JAR or WAR successfully, a set of steps and tasks must be followed in a well-defined order. Maven uses the concept of goals to represent granular tasks like compiling source code, running unit tests, and packaging the artifact.

Maven packages goals into plugins, which are essentially collections of one or more goals. Here the compiler is the plugin that provides the goal compile.

Lifecycle and Phases

Maven goals are granular and typically perform a single task. For complex operations such as generating artifacts or documentation, it is necessary to execute multiple goals in an orderly manner.

Through lifecycle and phase abstractions, Maven simplifies these complex operations so that build-related operations can be completed with a few commands.

Maven’s build lifecycle constitutes a series of stages that get executed, these stages are referred to as phases.

Every Maven project has the following three built-in lifecycles:

  • default — A Maven project is compiled, packaged, and deployed with this lifecycle.
  • clean — In this lifecycle, temporary files and generated artifacts are removed from the target directory.
  • site — Documentation and website generation are handled by this lifecycle.

Let’s look at some of the phases associated with the default life cycle.

  • validate — Verify that the project is correct and all needed information is available.
  • compile — Compile the source code.
  • test — Test the compiled source code using a suitable unit testing framework. These tests should not require the code to 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.

Maven lifecycle is an abstract concept that cannot be directly executed. One or more phases are executed instead. The command mvn package, for example, will execute the package phase of the default lifecycle. In addition to clearly defining the order of phases in a lifecycle, Maven also executes all phases prior to a requested phase. When the mvn package command is run, Maven will run all prior phases such as validate, compile, and test.

Each phase involves a number of tasks. Each phase is associated with zero or more goals. A phase simply delegated those tasks to its associated goals.

A portion of the internal lifecycle associated with JAR project

Maven Archetype

Using Maven archetypes, users can easily create new projects. Maven provides developers with hundreds of out-of-the-box archetypes. Maven provides the maven-archetype-webapp archetype to generate web applications.

By using the archetype plugin with generate goal, we can bootstrap a project.

$ mvn archetype:generate -DgroupId={project-packaging} -DartifactId={project-name} -DarchetypeArtifactId={maven-template} -DinteractiveMode=false

Let’s generate a simplest Maven project

$ mvn archetype:generate -DgroupId=com.learncsdesign -DartifactId=java-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Documentation and Reporting

Documentation and reporting are key aspects of any project.

Using the Site Lifecycle

Maven provides the site lifecycle that can be used to generate a project’s documentation.

$ mvn site

The site lifecycle generates the project’s site by using Maven’s site plug-in. After this command completes, a site folder is created under the project’s target folder. You can view the generated site by opening the index.html file in a browser. It shows details about project-like dependencies, plugins, etc.

Generating Javadoc Reports

Javadoc is the de facto standard for describing Java code. Developers can use it to understand what a class or method does. Maven provides a Javadoc plug-in that uses the Javadoc tool to generate Javadocs. Declaring it in the reporting element of the pom.xml file is all that is needed to integrate the Javadoc plug-in.

After you have configured the Javadoc plug-in, run mvn site to generate the Javadoc. The apidocs folder will appear under target/site after the command runs successfully.

Generating Unit Test Reports

Maven runs all tests for each build. Failed tests cause the build to fail. Surefire is a Maven plug-in that provides a uniform interface for running tests created by frameworks such as JUnit or TestNG. It can also generate execution results in various formats, such as XML and HTML.

Now that Surefire is configured, let’s create a Maven site using the mvn site command. Following successful execution of the command, you will see a Surefire Reports folder under target.

Generating Code Coverage Reports

The code coverage metric measures how much source code is exercised by automated tests. It serves as a measure of the quality of your tests. There are two popular code coverage tools for Java: JaCoCo and Clover from Atlassian.

Maven Release Process

Release plugins automate the process of releasing projects and publishing artifacts to the Maven repository.

Enterprise Maven deployments require repository managers. They serve as proxies for public repositories and facilitate the sharing and collaboration of artifacts as well as the governance of artifacts used in the enterprise.

Sonatype Nexus repository manager is open-source software that allows you to maintain internal repositories and access external repositories.

Nexus comes with repositories for Releases and snapshots out of the box. All SNAPSHOT artifacts will be stored in the Snapshots repository, and all release artifacts will be stored in the Releases repository.

A deployment to Nexus is a protected operation, as is the case with most repository managers. Maven needs the right access roles in settings.xml in order to interact with Nexus and deploy artifacts.

The release of a project is a complex process that typically involves the following steps:

  • Check that there are no uncommitted changes on the local machine.
  • In the pom.xml file, remove SNAPSHOT from the version.
  • Make sure the project does not use any SNAPSHOT dependencies.
  • Incorporate the modified pom.xml file into your source control system.
  • Create a source control tag.
  • Create a new version of the artifact and deploy it to the repository manager.
  • The pom.xml file should be updated to reflect the new version.

There is a Maven plug-in that provides a standard mechanism for executing the preceding steps and releasing project artifacts.

Two important steps are required to release an artifact through Maven’s release process: prepare and perform.

Maven Prepare Goal

As its name suggests, the prepare goal prepares a project for release.

$ mvn release:prepare

Upon completion of the prepare goal, an SCM tag will be created.

Maven Perform Goal

The perform goal is responsible for checking out code from the newly created tag and building and deploying it into the remote repository.

$ mvn release:perform

If you like the post, don’t forget to clap. If you’d like to connect, you can find me on LinkedIn.

References

https://maven.apache.org/index.html

--

--

Neeraj Kushwaha

https://www.learncsdesign.com “Walking on water and developing software from a specification are easy if both are frozen”