Maven in Depth: Understanding the pom.xml File
- pranaypourkar
- Jun 30, 2023
- 12 min read
Apache Maven is an project management and build automation tool used primarily in Java projects. It provides a way to build, test, and manage software projects, handling various aspects of the software development lifecycle. It is based on the Project Object Model (POM) which is a declarative model that describes the project's dependencies, build process, and other information. Maven uses POM to automate the build process and ensures that all of the project dependencies are downloaded and installed and the project is built in a consistent manner.
Syntax of Maven Command:
mvn [options] [<phase-name>[:<goal-name>]] [-D<property>=<value>] [-P<profile-id>]For Example:
mvn clean executes the clean phase of the default lifecycle.
mvn compile executes the compile phase of the default lifecycle.
mvn test-compile executes the test-compile goal within the compile phase.
mvn package -DskipTests=true executes the package phase and skips running tests by setting the skipTests property to true.
mvn install -Pproduction executes the install phase and activates the production profile defined in the POM file.
Use Case of colon ":" in the mvn command
1. Lifecycle and Phase:
<lifecycle>:<phase> -> This specifies a specific phase within a particular lifecycle. For example, clean:clean refers to the clean lifecycle and the clean phase. compile:compile refers to the compile phase of the default lifecycle.
2. Plugin and Goal:
<plugin>:<goal> -> This specifies a specific goal within a plugin. Plugins are typically configured in the project's pom.xml file. For example, compiler:compile refers to the compile goal of the compiler plugin.
3. Plugin Execution:
<plugin>:<goal>@<execution> -> This specifies a specific execution of a plugin's goal. An execution is a way to configure and customize the behavior of a plugin. For example, surefire:test@integration-tests refers to the execution with the ID "integration-tests" of the Surefire plugin's test goal.
For more details on the Maven, visit the official site - https://maven.apache.org/
The pom.xml serves as the configuration file and is an important part of a project built using Apache Maven. It is written in XML (eXtensible Markup Language) format and is located in the root directory of the Maven project. It defines various aspects of the project, including its dependencies, build settings, plugins, repositories, and other project-related information.
pom.xml file consists of several sections. Below is the list of some of the important sections and their corresponding tags.
Root Element:
The <project> tag is the root element of the pom.xml file and represents the entire Maven project. It encapsulates all the project-related information and configuration settings. The <project> tag acts as the container for various sections and tags within the pom.xml file.
The xmlns, xmlns:xsi, and xsi:schemaLocation attributes are used to specify the XML namespace and schema location for validation purposes. They help ensure that the POM file adheres to the XML schema defined by Maven. These attributes are not mandatory in a Maven POM file. However, if these attributes are not present, Maven will still be able to parse and process the POM file without any issues. It is considered good practice to include these attributes for clarity and standard.
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
...
...
</project>Project Information:
It includes details such as the project's name, version, description, organization etc.
<modelVersion>: It specifies the version of the POM schema. It is a required element and indicates the POM version being used. For most projects, the value is set to "4.0.0", indicating that the POM follows the Maven POM version 4.0.0.
<modelVersion>4.0.0</modelVersion><groupId>: It identifies the group or organization to which the project belongs.
<groupId>com.company.project</groupId><artifactId>: It specifies the project's unique identifier or name.
<artifactId>sample-maven-service</artifactId><version>: It help specify the version of the project.
<version>0.0.1-SNAPSHOT-1</version><name>: It is used to provide a descriptive name for the project.
<name>Company :: sample-maven-service</name><description>: It helps describes the project in detail.
<description>This is a Sample Maven Service</description><url>: It is used to specify the URL of the project's homepage or documentation.
<url>http://www.example.com/sample-maven-service</url> <packaging>: We can specify the type of packaging used for the project with the help of this tag.
Some of the values supported are listed below.
JAR (Java Archive): Used for packaging Java classes and resources into a standalone JAR file.
WAR (Web Application Archive): Used for packaging a web application, including Java classes, web resources, and libraries, into a deployable WAR file.
POM (Project Object Model): Used for a parent POM or a module that doesn't produce an artifact but provides project structure and dependencies.
EAR (Enterprise Archive): Used for packaging multiple JAR, WAR, and other resources into an enterprise application archive.
RAR (Resource Adapter Archive): Used for packaging a JCA (Java Connector Architecture) resource adapter.
<packaging>jar</packaging>
Properties:
This element can be used to define project-specific properties or variables.
<properties>: Defines project-specific properties that can be referenced throughout the pom.xml file.
<java.version>17</java.version>There are several special variables in the maven that are implicitly defined and can be used within the pom.xml file. These variables provide information about the project, environment, and other related details. Here is a list of some commonly used special variables:
${project}: Refers to the current Maven project object.
${basedir}: Refers to the base directory of the project (the directory containing the pom.xml file). For example ${basedir}/src/main/java
${project.build.directory}: Refers to the directory where the build output is generated. For example ${project.build.directory}/classes
${project.build.outputDirectory}: Refers to the directory where the compiled classes are placed.
${project.build.finalName}: Refers to the final name of the built artifact. For example ${project.build.finalName}.jar
${project.version}: Refers to the version of the project.
${project.groupId}: Refers to the group or organization to which the project belongs.
${project.artifactId}: Refers to the unique identifier or name of the project.
${user.home}: Refers to the user's home directory. For example ${user.home}/.m2/repository
${java.home}: Represents the path to the Java installation directory.
<open-api-specs-dir>${project.build.directory}/specs</open-api-specs-dir>
<docker.repo.url>https://example.com/docker-repo</docker.repo.url>
<docker.image.name>${docker.repo.url}/${project.artifactId}</docker.image.name>Project Inheritance:
We can inherit various configurations such as project version, dependencies, repositories, plugin versions, and more from the parent project. This promotes consistency and reduces duplication across multiple modules within a project.
<parent>: This tag helps specifying the parent project from which the current project inherits its configurations.
<groupId>: Identifies the group or organization of the parent project.
<artifactId>: Specifies the identifier or name of the parent project.
<version>: Defines the version of the parent project.
<relativePath> (optional): Specifies the relative path to the parent project directory if it is located outside the current project's directory structure.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>The Super POM, also known as the Super Project Object Model, is a default and implicit POM in Maven. It acts as the ultimate parent of all Maven projects and provides a set of default configurations and properties. The Super POM can contain several default configurations and properties such as Model Information, Project Information, Build Settings, Dependency Management etc. Every Maven pom.xml file implicitly inherits from the Super POM, even if it is not explicitly mentioned.
Sample Super POM - https://maven.apache.org/ref/3.6.3/maven-model-builder/super-pom.html
Super POM itself is not explicitly included in individual project pom.xml files unless we want to customize or override the default configurations provided by the Super POM.
We can override Super POM using the <parent> tag.
Dependency Management:
It allows us to define and manage dependencies for the project in a centralized and controlled manner. It provides a way to specify the versions of dependencies, manage transitive dependencies, and ensure consistency across different modules or projects.
<dependencyManagement>: This tag allows centralized management of dependencies.
<dependencies>: This tag contains a list of dependency declarations.
<dependency>: Specify a managed dependency within this tag.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-library</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.another</groupId>
<artifactId>another-library</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-library-1</artifactId>
</dependency>
<dependency>
<groupId>org.another</groupId>
<artifactId>another-library-1</artifactId>
</dependency>
</dependencies>Dependencies:
This section specifies the external libraries and dependencies required by the project. Maven manages the downloading, resolving, and inclusion of these dependencies automatically.
<dependencies>: It contains a list of project dependencies.
<dependency>: Single dependency can be specified with this tag.
<groupId>: It identifies the group or organization of the dependency.
<artifactId>: Specify the identifier or name of the dependency in this tag.
<version>: Defines the version of the dependency.
<scope>: Specifies the scope of the dependency (e.g., compile, test, provided).
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>Build Settings:
Maven provides a standard build lifecycle with predefined phases like compile, test, package, install, and deploy. We can also define custom build tasks and configurations.
<build>: It contains configuration settings for the build process.
<plugins>: We can configure or define multiple plugins within this tag.
<plugin>: It help specify a build plugin. A plugin is a component that provides specific functionality or performs certain tasks within the build process. Plugins are an essential part of Maven's architecture and allow you to extend and customize the build lifecycle according to your project's needs.
<groupId>: It help Identifies the group or organization of the plugin.
<artifactId>: Specify the identifier or name of the plugin in this tag.
<version>: Defines the version of the plugin.
<executions>: Allows specifying plugin executions and associated goals.
• <execution>: Use to Specify a plugin execution. It is used to configure the execution of a plugin. This element has a number of attributes that can be used to specify the goals that will be executed, the phase in which the goals will be executed, and the configuration for the goals.
• <id>: Help defines the identifier of the execution.
• <phase>: It help specify the build phase in which the execution should occur.
• <goals>: It contains a list of goals to be executed during the specified phase.
• <configuration>: Provide configuration specific to the plugin execution with this tag.
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>maven-compiler-plugin is used to compile the project's source code. In the above example, the maven-compiler-plugin is configured to compile the source code under src/main/java and src/test/java directories with Java 8 as the source and target version.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration-tests</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
<execution>
<id>unit-tests</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>maven-surefire-plugin is used to run the project's unit tests and integration tests. Unit tests will be running during test phase and integration tests will be running during the integration-test phase.
What is Lifecycle?
In Maven, the build process is organized into a predefined sequence of events known as the build lifecycle. The build lifecycle consists of a series of phases, and each phase represents a specific stage in the build process.
A lifecycle encompasses the entire build process and provides a logical flow of actions that are executed in a specific order. The standard Maven build lifecycle includes three main lifecycles:
1. Clean Lifecycle: This lifecycle is responsible for cleaning the project by removing any artifacts or files generated during the build process.
mvn clean - Executes the clean phase, which removes previously built files and directories.
2. Default Lifecycle: This lifecycle is the most commonly used and covers the main build process. It includes phases such as compiling source code, running tests, packaging the project, and deploying artifacts.
mvn validate - Executes the validate phase, which validates the project structure and configuration.
mvn compile - Executes the compile phase, which compiles the source code.
mvn test - Executes the test phase, which runs the tests.
mvn package - Executes the package phase, which packages the compiled code into a distributable format, such as a JAR (Java Archive) or a WAR (Web Application Archive).
mvn install - Executes the install phase, which installs the package into the local repository. This phase not only packages the project like the package phase but also installs the resulting artifact into the local Maven repository.
mvn deploy - Executes the deploy phase, which deploys the package to a remote repository.
mvn generate-sources - Executes the generate-sources phase, which generates any additional source code required by the project.
mvn process-sources - Executes the process-sources phase, which processes the source code, such as applying filtering or transformations.
mvn generate-resources - Executes the generate-resources phase, which generates any additional resources needed by the project.
mvn process-resources - Executes the process-resources phase, which processes the resources, such as filtering or copying files.
mvn process-classes - Executes the process-classes phase, which performs any post-compilation processing, such as bytecode enhancement.
mvn generate-test-sources - Executes the generate-test-sources phase, which generates any additional test source code.
mvn process-test-sources - Executes the process-test-sources phase, which processes the test source code.
mvn generate-test-resources - Executes the generate-test-resources phase, which generates any additional test resources.
mvn process-test-resources - Executes the process-test-resources phase, which processes the test resources.
mvn test-compile - Executes the test-compile phase, which compiles the test source code.
mvn process-test-classes - Executes the process-test-classes phase, which performs any post-compilation processing for tests.
mvn prepare-package - Executes the prepare-package phase, which prepares the package for deployment.
mvn pre-integration-test - Executes the pre-integration-test phase, which performs any necessary actions before integration tests are run.
mvn integration-test - Executes the integration-test phase, which runs integration tests on an assembled environment.
mvn post-integration-test - Executes the post-integration-test phase, which performs any necessary actions after integration tests have been run.
mvn verify - Executes the verify phase, which checks the integrity of the package and verifies that all criteria have been met.
3. Site Lifecycle: This lifecycle is used for generating project documentation and reports.
mvn site - Executes the site phase, which generates the project's site documentation.
mvn site-deploy - Executes the site-deploy phase, which deploys the generated site documentation to a remote repository or server.
Each lifecycle is composed of a set of phases. Phases are the individual steps or tasks that are executed during the build process. The phases represent specific goals or actions that need to be accomplished within a given lifecycle.
For example, the default lifecycle consists of phases like validate, compile, test, package, install, and deploy. Each phase is executed in the order defined by the lifecycle.
Phases vs Goals?
In Maven, the build lifecycle consists of a series of phases, and each phase is composed of one or more goals. Phases represent specific stages of the build process, and goals are the specific tasks that are executed within those phases.
Phases are predefined and standardized by Maven. The standard build lifecycle consists of the following phases, among others:
validate: Validates the project structure and configuration.
compile: Compiles the source code.
test: Runs tests against compiled source code.
package: Packages the compiled code into an artifact (e.g., JAR, WAR).
install: Installs the artifact into the local Maven repository.
deploy: Deploys the artifact to a remote repository.
Goals, on the other hand, are the specific tasks that are executed within a phase. Each phase can have zero or more associated goals. Goals are typically provided by Maven plugins, which are additional software components that extend the build process.
While the standard set of phases and goals are predefined by Maven, we can also define custom phases and goals specific to our project or requirements. Custom phases and goals allows us to extend the build lifecycle and perform additional tasks tailored for project's needs.
Repositories: Maven retrieve dependencies from remote repositories. We can specify the repositories where Maven should search for dependencies. It can also include information about internal or custom repositories. By default, Maven uses the Central Repository (also known as Maven Central) as the primary repository for downloading dependencies. When we don't explicitly declare any repositories in the POM file, Maven automatically includes the Central Repository as the default repository. This allows Maven to download dependencies from the Central Repository without any additional configuration.
If we have multiple repositories configured in pom.xml file, Maven will search these repositories in the order that they are defined. This means that Maven will start by searching the first repository, and if it does not find the dependency there, it will then search the second repository, and so on.
Maven will continue searching the repositories until it finds the dependency, or until it has searched all of the repositories.
If Maven finds the dependency in multiple repositories, it will use the first repository that it finds. This is because Maven does not have a way to prioritize the repositories.
<repositories>: Contains a list of repositories for dependency resolution.
<repository>: Specify a repository details within this tag.
<id>: Defines the identifier of the repository.
<url>: Specifies the URL of the repository.
<repositories>
<repository>
<id>central</id>
<name>Maven Central Repository</name>
<url>https://repo1.maven.org/maven2</url>
</repository>
<repository>
<id>my-repo</id>
<name>Private Repository</name>
<url>https://my-repo.com/maven2</url>
</repository>
</repositories>Profiles: Maven allows the definition of profiles to customize the build process based on different environments or conditions. The pom.xml file can contain profiles with specific configurations and dependencies for specific situations. Once we have defined the profiles in the pom.xml file, we can activate them using the -P command line option. For example, to activate the dev profile, use the following command:
mvn -Pdev clean install<profiles>: Contains a list of profiles with their associated configurations.
<profile>: Specify a profile within this tag.
<id>: Defines the identifier of the profile.
<dependencies>: Configures profile-specific dependencies.
<build>: Configures profile-specific build settings.
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</profile>
<profile>
<id>prod</id>
<activation>
<property>
<name>env</name>
<value>prod</value>
</property>
</activation>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</profile>
</profiles>mvn -Pdev clean install
mvn -Pprod clean installProject Inheritance vs Project Aggregation?
Project Inheritance: Project inheritance refers to the relationship between a parent project and its child projects. We can define a parent project using the <parent> tag in the child project's pom.xml file. The child project inherits the configurations, dependencies, and build settings from its parent project. This allows for the reuse of common configurations and promotes consistency across multiple projects.
Project Aggregation: Project aggregation refers to the relationship between a parent project and its modules in a multi-module project structure. The parent project's pom.xml file acts as the aggregator, which contains a list of module projects defined using the <modules> tag. The modules can be individual subprojects that are built independently. The parent project coordinates the build process and manages dependencies across all the modules. This helps in organizing and managing related projects as a single entity.
Let's go through sample multi module project.
Here is the Project Structure.

Parent pom.xml (Note that packaging is set to pom)
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>com.example</groupId>
<artifactId>sample-multi-module-service</artifactId>
<version>0.0.1-SNAPSHOT-1</version>
<name>Company :: sample-multi-module-service</name>
<description>This is a Sample Multi Module Service</description>
<packaging>pom</packaging>
<properties>
<java.version>17</java.version>
</properties>
<modules>
<module>module1</module>
<module>module2</module>
</modules>
</project>module1 pom.xml
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.module1</groupId>
<artifactId>module1</artifactId>
<version>0.0.1-SNAPSHOT-1</version>
<name>Company :: module1</name>
<description>This is a Sample Module 1 Service</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>module2 pom.xml
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.module2</groupId>
<artifactId>module2</artifactId>
<version>0.0.1-SNAPSHOT-1</version>
<name>Company :: module2</name>
<description>This is a Sample Module 2 Service</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>Sample Application.java file
package com.example.module1;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.SpringApplication;
@SpringBootApplication
public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
}Run the Parent Project as mvn clean install and verify the generated module package files

Thank you for taking the time to read this post. I hope that you found it informative and useful in your own development work.






Comments