Apache Maven Guide
Apache Maven Guide
Maven
1: Apache Maven
1. Overview 1
3.2. Dependencies 4
3.3. Repositories 4
3.4. Properties 5
3.5. Build 6
6. Conclusion 11
2: Apache Maven Standard Directory Layout
1. Overview 13
2. Directory Layout 14
6. Conclusion 18
2. A Basic Example 21
3. Declaring Profiles 22
4. Activating Profiles 23
5. Deactivating a Profile 27
6. Conclusion 28
2. Transitive Dependency 31
3. Dependency Scopes 32
3.1. Compile 33
3.2. Provided 33
3.3. Runtime 34
3.4. Test 34
3.5. System 34
3.6. Import 35
5. Conclusion 37
2. Plugin Configuration 40
3. Plugin Management 41
4. Example 42
5. Core Plugins 45
6. Conclusion 46
3. Maven Phase 50
4. Maven Goal 51
5. Maven Plugin 52
7. Conclusion 55
4. Parent POM 60
5. Submodules 61
7. Conclusion 67
2. Usage 70
2.1. dependencyManagement 70
2.2. dependencies 70
3. Similarities 72
4. Differences 73
5. Real-World Example 74
7. Common Mistakes 76
8. Conclusion 77
2.1. jar 80
2.2. war 81
2.3. ear 81
2.4. pom 82
2.5. maven-plugin 82
2.6. ejb 83
2.7. rar 83
4. Conclusion 86
10: The settings.xml File in Maven
1. Overview 88
2. Configurations 89
2.3. Proxies 90
2.4. Mirrors 91
2.5. Servers 92
3. Profiles 93
3.1. Activation 94
3.2. Properties 95
3.3. Repositories 96
4. Settings Level 98
5. Conclusion 100
1: Apache Maven
9
1. Overview
Building a software project typically consists of tasks such as downloading dependencies; putting
additional jars on a classpath; compiling source code into binary code; running tests; packaging
compiled code into deployable artifacts, such as JAR, WAR, and ZIP files; and deploying these
artifacts to an application server or repository.
Apache Maven automates these tasks, which minimizes the risk of human error, while building
the software manually and separating the work of compiling and packaging our code from that
of code construction.
In this chapter, we’ll explore this powerful tool for describing, building, and managing Java
software projects using a central piece of information, the Project Object Model (POM), which is
written in XML.
1
2. Why Use Maven?
• simple project setup that follows best practices: Maven tries to avoid as much
configuration as possible by supplying project templates (named archetypes).
• isolation between project dependencies and plugins: with Maven, project dependencies
are retrieved from the dependency repositories, while any plugin’s dependencies are
retrieved from the plugin repositories, resulting in fewer conflicts when plugins start to
download additional dependencies.
• central repository system: project dependencies can be loaded from the local file system
or public repositories, such as Maven Central.
In order to learn how to install Maven on our system, we can check out this tutorial on
Baeldung.
2
3. Project Object Model
The configuration of a Maven project is done via a Project Object Model (POM), represented by a
pom.xml file. The POM describes the project, manages dependencies, and configures plugins
for building the software.
The POM also defines the relationships among modules of multi-module projects. Let’s look at
the basic structure of a typical POM file:
1. <project>
2. <modelVersion>4.0.0</modelVersion>
3. <groupId>com.baeldung</groupId>
4. <artifactId>baeldung</artifactId>
5. <packaging>jar</packaging>
6. <version>1.0-SNAPSHOT</version>
7. <name>com.baeldung</name>
8. <url>http://maven.apache.org</url>
9. <dependencies>
10. <dependency>
11. <groupId>org.junit.jupiter</groupId>
12. <artifactId>junit-jupiter-api</artifactId>
13. <version>5.8.2</version>
14. <scope>test</scope>
15. </dependency>
16. </dependencies>
17. <build>
18. <plugins>
19. <plugin>
20. //...
21. </plugin>
22. </plugins>
23. </build>
24. </project>
• groupId – a unique base name of the company or group that created the project
• artifactId – a unique name of the project
• version – a version of the project
• packaging – a packaging method (e.g. WAR /JAR / ZIP)
3
The first three of these (groupId:artifactId:version) combine to form the unique identifier, and are
the mechanism by which we specify which versions of external libraries (e.g. JARs) our project
will use.
3.2. Dependencies
These external libraries that a project uses are called dependencies. The dependency
management feature in Maven ensures the automatic download of these libraries from a
central repository, so we don’t have to store them locally.
• uses less storage by significantly reducing the number of downloads off remote
repositories
• provides an effective platform for exchanging binary artifacts within our organization and
beyond, without the need for building artifacts from source every time
1. <dependency>
2. <groupId>org.springframework</groupId>
3. <artifactId>spring-core</artifactId>
4. <version>5.3.16</version>
5. </dependency>
As Maven processes the dependencies, it’ll download the Spring Core library into our local
Maven repository.
3.3. Repositories
A repository in Maven is used to hold build artifacts and dependencies of varying types. The
default local repository is located in the .m2/repository folder under the home directory of the
user.
If an artifact or plugin is available in the local repository, Maven uses it. Otherwise, it’s downloaded
from a central repository and stored in the local repository. The default central repository is
Maven Central.
4
Some libraries, such as the JBoss server, aren’t available at the central repository, but are available
at an alternate repository. For those libraries, we need to provide the URL to the alternate
repository inside the pom.xml file:
1. <repositories>
2. <repository>
3. <id>JBoss repository</id>
4. <url>http://repository.jboss.org/nexus/content/groups/public/</
5. url>
6. </repository>
7. </repositories>
3.4. Properties
Custom properties can help make our pom.xml file easier to read and maintain. In a classic use
case, we would use custom properties to define versions for our project’s dependencies.
Maven properties are value-placeholders and are accessible anywhere within a pom.xml by
using the notation ${name}, where name is the property:
1. <properties>
2. <spring.version>5.3.16</spring.version>
3. </properties>
1. <dependencies>
2. <dependency>
3. <groupId>org.springframework</groupId>
4. <artifactId>spring-core</artifactId>
5. <version>${spring.version}</version>
6. </dependency>
7. <dependency>
8. <groupId>org.springframework</groupId>
9. <artifactId>spring-context</artifactId>
10. <version>${spring.version}</version>
11. </dependency>
12. </dependencies>
5
Now if we want to upgrade Spring to a newer version, we only have to change the value
inside the <spring.version> property tag, and all the dependencies using that property in their
<version> tags will be updated.
1. <properties>
2. <project.build.folder>${project.build.directory}/tmp/</project.
3. build.folder>
4. </properties>
1. <plugin>
2. //...
3. <outputDirectory>${project.resources.build.folder}</outputDirectory>
4. //...
5. </plugin>
3.5. Build
The build section is also a very important section of the Maven POM. It provides information
about the default Maven goal, the directory for the compiled project, and the final name of the
application. The default build section looks like this:
1. <build>
2. <defaultGoal>install</defaultGoal>
3. <directory>${basedir}/target</directory>
4. <finalName>${artifactId}-${version}</finalName>
5. <filters>
6. <filter>filters/filter1.properties</filter>
7. </filters>
8. //...
9. </build>
The default output folder for compiled artifacts is named target, and the final name of the
packaged artifact consists of the artifactId and version, but we can change it at any time.
6
1. <profiles>
2. <profile>
3. <id>production</id>
4. <build>
5. <plugins>
6. <plugin>
7. //...
8. </plugin>
9. </plugins>
10. </build>
11. </profile>
12. <profile>
13. <id>development</id>
14. <activation>
15. <activeByDefault>true</activeByDefault>
16. </activation>
17. <build>
18. <plugins>
19. <plugin>
20. //...
21. </plugin>
22. </plugins>
23. </build>
24. </profile>
25. </profiles>
As we can see in the example above, the default profile is set to development. If we want to run
the production profile, we can use the following Maven command:
7
4. Maven Build Lifecycles
Every Maven build follows a specified lifecycle. We can execute several build lifecycle goals,
including the ones to compile the project’s code, create a package, and install the archive file in
the local Maven dependency repository.
The rich list of plugins that are officially supported by Maven is available here. There’s also an
interesting article on Baeldung about how to build an executable JAR using various plugins.
To gain a better understanding of which goals are run in which phases by default, take a look
at the default Maven lifecycle bindings.
To go through any one of the above phases, we just have to call one command:
mvn <phase>
For example, mvn clean install will remove the previously created jar/war/zip files and
compiled classes (clean), as well as execute all the phases necessary to install the new archive
(install).
Please note that goals provided by plugins can be associated with different phases of the
lifecycle.
8
5. Our First Maven Project
In this section, we’ll use the command line functionality of Maven to create a Java project.
mvn archetype:generate \
-DgroupId=com.baeldung \
-DartifactId=baeldung \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4 \
-DinteractiveMode=false
The groupId is a parameter indicating the group or individual that created a project, which is
often a reversed company domain name. The artifactId is the base package name used in the
project, and we use the standard archetype. Here we’re using the latest archetype version to
ensure our project is created with the updated and latest structure.
Since we didn’t specify the version and packaging type, these will be set to default values; the
version will be set to 1.0-SNAPSHOT, and the packaging will be jar by default.
If we don’t know which parameters to provide, we can always specify interactiveMode=true,
so that Maven asks for all the required parameters.
After the command completes, we have a Java project containing an App.java class, which is
just a simple “Hello World” program, in the src/main/java folder. We also have an example test
class in src/test/java. The pom.xml of this project will look similar to this:
1. <project>
2. <modelVersion>4.0.0</modelVersion>
3. <groupId>com.baeldung</groupId>
4. <artifactId>baeldung</artifactId>
5. <version>1.0-SNAPSHOT</version>
6. <name>baeldung</name>
7. <url>http://www.example.com</url>
8. <dependencies>
9. <dependency>
10. <groupId>junit</groupId>
11. <artifactId>junit</artifactId>
12. <version>4.11</version>
13. <scope>test</scope>
14. </dependency>
15. </dependencies>
16. </project>
9
5.2. Compiling and Packaging a Project
The next step is to compile the project:
mvn compile
Maven will run through all lifecycle phases needed by the compile phase to build the project’s
sources. If we want to run only the test phase, we can use:
mvn test
Now let’s invoke the package phase, which will produce the compiled archive jar file:
mvn package
1. <build>
2. <sourceDirectory>src</sourceDirectory>
3. <plugins>
4. <plugin>
5. <artifactId>maven-compiler-plugin</artifactId>
6. <version>3.6.1</version>
7. <configuration>
8. <source>1.8</source>
9. <target>1.8</target>
10. </configuration>
11. </plugin>
12. <plugin>
13. <groupId>org.codehaus.mojo</groupId>
14. <artifactId>exec-maven-plugin</artifactId>
15. <version>3.0.0</version>
16. <configuration>
17. <mainClass>com.baeldung.java.App</mainClass>
18. </configuration>
19. </plugin>
20. </plugins>
21. </build>
The first plugin, maven-compiler-plugin, is responsible for compiling the source code using
Java version 1.8. The exec-maven-plugin searches for the mainClass in our project.
10
6. Conclusion
In this chapter, we discussed some of the more popular features of the Apache Maven build
tool.
All code examples on Baeldung are built using Maven, so check out our GitHub project
website to see various Maven configurations.
11
2: Apache Maven Standard Directory
Layout
12
1. Overview
Apache Maven is one of the most popular build tools for Java projects. Apart from
decentralizing dependencies and repositories, promoting a uniform directory structure across
projects is one of its most important aspects.
In this quick chapter, we’ll explore the standard directory layout of a typical Maven project.
13
2. Directory Layout
A typical Maven project has a pom.xml file and a directory structure based on defined
conventions:
The default directory layout can be overridden using project descriptors, but this is uncommon
and discouraged.
Going ahead in this chapter, we’ll uncover more details about each standard file and
subdirectory.
14
3. The Root Directory
Let’s take a closer look at the standard files and subdirectories that are typically found at root:
• maven-project/src/main – contains source code and resources that become part of the
artifact
• maven-project/src/it – usually reserved for integration tests used by the Maven Failsafe
Plugin
15
4. The src/main Directory
As the name indicates, src/main is the most important directory of a Maven project. Anything
that’s supposed to be part of an artifact, be it a jar or war, should be present here.
• src/main/webapp – for web applications, contains resources like JavaScript, CSS, HTML
files, view templates, and images
• src/main/filters – contains files that inject values into configuration properties in the
resources folder during the build phase
16
5. The src/test Directory
The directory src/test is the place where tests of each component in the application reside.
Note that none of these directories or files will become part of the artifact. Let’s see its
subdirectories:
• src/main/filters – contains files that inject values into configuration properties in the
resources folder during the test phase
17
6. Conclusion
In this chapter, we looked at the standard directory layout for an Apache Maven project.
Multiple examples of Maven project structures can be found in the GitHub project.
18
3: Guide to Maven Profiles
19
1. Overview
Maven profiles can be used to create customized build configurations, like targeting a level
of test granularity, or a specific deployment environment.
20
2. A Basic Example
Normally when we run mvn package, the unit tests are executed as well. But what if we want
to quickly package the artifact and run it to see if it works?
First, we’ll create a no-tests profile that sets the maven.test.skip property to true:
1. <profile>
2. <id>no-tests</id>
3. <properties>
4. <maven.test.skip>true</maven.test.skip>
5. </properties>
6. </profile>
Next, we’ll execute the profile by running the mvn package -Pno-tests command. Now the
artifact is created and the tests are skipped. In this case, the mvn package -Dmaven.test.skip
command would’ve been easier.
However, this was just an introduction to Maven profiles. Let’s take a look at some more
complex setups.
21
3. Declaring Profiles
In the previous section, we saw how to create one profile. We can configure as many profiles
as we want by giving them unique ids.
Let’s say we wanted to create a profile that only ran our integration tests, and another profile for
a set of mutation tests.
1. <profiles>
2. <profile>
3. <id>integration-tests</id>
4. </profile>
5. <profile>
6. <id>mutation-tests</id>
7. </profile>
8. </profiles>
Within each profile element, we can configure many elements, such as dependencies,
plugins, resources, and finalName.
So, for the above example, we could add plugins and their dependencies separately for
integration-tests and mutation-tests.
Separating tests into profiles can make the default build faster by having it focus, for instance,
on just the unit tests.
We try to configure profiles in the pom.xml whenever possible. This is because we want to
use the profiles both on our development machines and build machines. Using the settings.
xml is more difficult and error-prone, as we have to distribute it across build environments
ourselves.
22
4. Activating Profiles
After we create one or more profiles, we can start using them, or in other words, activating
them.
mvn help:active-profiles
default build:
Well, nothing.
We’ll activate them in just a moment, but another way to see what’s activated is to include the
maven-help-plugin in our pom.xml and tie the
active-profiles goal to the compile phase:
1. <build>
2. <plugins>
3. <plugin>
4. <groupId>org.apache.maven.plugins</groupId>
5. <artifactId>maven-help-plugin</artifactId>
6. <version>3.2.0</version>
7. <executions>
8. <execution>
9. <id>show-profiles</id>
10. <phase>compile</phase>
11. <goals>
12. <goal>active-profiles</goal>
13. </goals>
14. </execution>
15. </executions>
16. </plugin>
17. </plugins>
18. </build>
23
4.2. Using -P
We already saw one way at the beginning, which is that we can activate profiles with the -P
argument. So let’s begin by enabling the
integration-tests profile:
If we verify the active profiles with the maven-help-plugin or the mvn help:active-profiles -P
integration-tests command, we’ll get the following result:
If we want to activate multiple profiles at the same time, we can use a comma-separated list of
profiles:
1. <profile>
2. <id>integration-tests</id>
3. <activation>
4. <activeByDefault>true</activeByDefault>
5. </activation>
6. </profile>
Then we can run mvn package without specifying the profiles, and we can verify that the
integration-test profile is active.
However, if we run the Maven command and enable another profile, then the
activeByDefault profile is skipped. So when we run mvn package -P mutation-tests, only the
mutation-tests profile is active.
When we activate in other ways, the activeByDefault profile is also skipped, as we’ll see in
the next sections.
24
4.4. Based on a Property
We can activate profiles on the command-line; however, it’s sometimes more convenient if
they’re activated automatically. For instance, we can base it on a -D system property:
1. <profile>
2. <id>active-on-property-environment</id>
3. <activation>
4. <property>
5. <name>environment</name>
6. </property>
7. </activation>
8. </profile>
We now activate the profile with the mvn package -Denvironment command. It’s also
possible to activate a profile if a property isn’t present:
1. <property>
2. <name>!environment</name>
3. </property>
1. <property>
2. <name>environment</name>
3. <value>test</value>
4. </property>
1. <property>
2. <name>environment</name>
3. <value>!test</value>
4. </property>
25
1. <profile>
2. <id>active-on-jdk-11</id>
3. <activation>
4. <jdk>11</jdk>
5. </activation>
6. </profile>
We can also use ranges for the JDK version, as explained in Maven Version Range Syntax.
After that, we can configure a profile that’s activated only on Windows 10:
1. <profile>
2. <id>active-on-windows-10</id>
3. <activation>
4. <os>
5. <name>windows 10</name>
6. <family>Windows</family>
7. <arch>amd64</arch>
8. <version>10.0</version>
9. </os>
10. </activation>
11. </profile>
1. <activation>
2. <file>
3. <missing>target/testreport.html</missing>
4. </file>
5. </activation>
26
5. Deactivating a Profile
We’ve seen many ways to activate profiles, but sometimes we need to disable them as well.
27
6. Conclusion
In this chapter, we learned how to work with Maven profiles in order to create different build
configurations.
28
4: Maven Dependency Scopes
29
1. Overview
Maven is one of the most popular build tools in the Java ecosystem, and one of its core
features is dependency management.
In this chapter, we’ll describe and explore the mechanism that helps with managing transitive
dependencies in Maven projects - dependency scopes.
30
2. Transitive Dependency
Direct dependencies are the ones that we explicitly include in the project.
1. <dependency>
2. <groupId>junit</groupId>
3. <artifactId>junit</artifactId>
4. <version>4.12</version>
5. </dependency>
We can list all dependencies, including transitive dependencies, in the project using the mvn
dependency:tree command.
31
3. Dependency Scopes
Dependency scopes can help to limit the transitivity of the dependencies. They also modify
the classpath for different build tasks. Maven has six default dependency scopes.
It’s important to understand that each scope, except for import, has an impact on transitive
dependencies.
32
3.1. Compile
This is the default scope when no other scope is provided.
Dependencies with this scope are available on the classpath of the project in all build tasks.
They are also propagated to the dependent projects.
1. <dependency>
2. <groupId>commons-lang</groupId>
3. <artifactId>commons-lang</artifactId>
4. <version>2.6</version>
5. </dependency>
3.2. Provided
We use this scope to mark dependencies that should be provided at runtime by JDK or a
container.
A good use case for this scope would be a web application deployed in a container, where the
container already provides some libraries itself.
For example, this could be a web server that already provides the Servlet API at runtime.
In our project, we can define those dependencies with the provided scope:
1. <dependency>
2. <groupId>javax.servlet</groupId>
3. <artifactId>javax.servlet-api</artifactId>
4. <version>4.0.1</version>
5. <scope>provided</scope>
6. </dependency>
The provided dependencies are available only at compile time and in the test classpath of the
project. These dependencies are not transitive.
33
3.3. Runtime
The dependencies with this scope are required at runtime, but we don’t need them for the
compilation of the project code.
As a result, dependencies marked with the runtime scope will be present in the runtime and
test classpath, but they’ll be missing from the compile classpath.
A JDBC driver is a good example of dependencies that should use the runtime scope:
1. <dependency>
2. <groupId>mysql</groupId>
3. <artifactId>mysql-connector-java</artifactId>
4. <version>8.0.28</version>
5. <scope>runtime</scope>
6. </dependency>
3.4. Test
We use this scope to indicate that a dependency isn’t required at standard runtime of the
application, and is only used for test purposes. Test dependencies aren’t transitive and are
only present for test and execution classpaths.
The standard use case for this scope is adding a test library, such as JUnit, to our application:
1. <dependency>
2. <groupId>junit</groupId>
3. <artifactId>junit</artifactId>
4. <version>4.12</version>
5. <scope>test</scope>
6. </dependency>
3.5. System
The System scope is very similar to the provided scope. The main difference is that system
requires us to point directly to a specific jar on the system.
It’s worthwhile to mention that the system scope is deprecated. The important thing to
remember is that building a project with system scope dependencies may fail on different
machines if the dependencies aren’t present or are located in a different place than the one
systemPath points to:
34
1. <dependency>
2. <groupId>com.baeldung</groupId>
3. <artifactId>custom-dependency</artifactId>
4. <version>1.3.2</version>
5. <scope>system</scope>
6. <systemPath>${project.basedir}/libs/custom-dependency-1.3.2.jar</
7. systemPath>
8. </dependency>
3.6. Import
It’s only available for the dependency type pom.
import indicates that this dependency should be replaced with all effective dependencies
declared in its POM.
Here, the custom-project dependency will be replaced with all the dependencies declared in
the custom-project’s pom.xml <dependencyManagement> section:
1. <dependency>
2. <groupId>com.baeldung</groupId>
3. <artifactId>custom-project</artifactId>
4. <version>1.3.2</version>
5. <type>pom</type>
6. <scope>import</scope>
7. </dependency>
35
4. Scope and Transitivity
Each dependency scope affects transitive dependencies in its own way. This means that
different transitive dependencies may end up in the project with different scopes. However,
dependencies with scopes provided and test will never be included in the main project.
• For the compile scope, all dependencies with the runtime scope will be pulled in with the
runtime scope in the project, and all dependencies with the compile scope will be pulled in
with the compile scope in the project.
• For the provided scope, both the runtime and compile scope dependencies will be pulled
in with the provided scope in the project.
• For the test scope, both the runtime and compile scope transitive dependencies will be
pulled in with the test scope in the project.
• For the runtime scope, both the runtime and compile scope transitive dependencies will be
pulled in with the runtime scope in the project.
36
5. Conclusion
In this quick chapter, we focused on Maven dependency scopes, their purpose, and the details
of how they operate.
37
5: Plugin Management in Maven
38
1. Overview
Apache Maven is a powerful tool that uses plugins to automate and perform all the build and
reporting tasks in a Java project.
However, there are likely to be several of these plugins used in the build, along with different
versions and configurations, especially in a
multi-module project. This can lead to problems of complex POM files with redundant or
duplicate plugin artifacts, as well as configurations scattered across various child projects.
In this chapter, we’ll see how to use Maven’s plugin management mechanism to handle such
issues and effectively maintain plugins across the whole project.
39
2. Plugin Configuration
• Build – executed during the build process. Examples include Clean, Install, and Surefire
plugins. These should be configured in the build section of the POM.
• Reporting – executed during site generation to produce various project reports. Examples
include Javadoc and Checkstyle plugins. These are configured in the reporting section of
the project POM.
Maven plugins provide all the useful functionalities required to execute and manage the
project build.
1. <build>
2. ....
3. <plugins>
4. <plugin>
5. <groupId>org.apache.maven.plugins</groupId>
6. <artifactId>maven-jar-plugin</artifactId>
7. <version>3.2.0</version>
8. ....
9. </plugin>
10. ....
11. </plugins>
12. </build>
Here we included the plugin in the build section to add the capability to compile our project
into a jar.
40
3. Plugin Management
In addition to the plugins, we can also declare plugins in the pluginManagement section of the
POM. This contains the plugin elements in much the same way as we previously saw. However,
by adding the plugin in the pluginManagement section, it becomes available to this POM, and
all inheriting child POMs.
This means that any child POMs will inherit the plugin executions simply by referencing the
plugin in their plugin section. All we need to do is add the relevant groupId and artifactId,
without having to duplicate the configuration or manage the version.
41
4. Example
Let’s start by creating a simple multi-module project with two submodules. We’ll include the
Build Helper Plugin in the parent POM, which contains several small goals to assist with the
build lifecycle. In our example, we’ll use it to copy some additional resources to the project
output for a child project.
42
4.1. Parent POM Configuration
First, we’ll add the plugin to the pluginManagement section of the parent POM:
1. <pluginManagement>
2. <plugins>
3. <plugin>
4. <groupId>org.codehaus.mojo</groupId>
5. <artifactId>build-helper-maven-plugin</artifactId>
6. <version>3.3.0</version>
7. <executions>
8. <execution>
9. <id>add-resource</id>
10. <phase>generate-resources</phase>
11. <goals>
12. <goal>add-resource</goal>
13. </goals>
14. <configuration>
15. <resources>
16. <resource>
17. <directory>src/resources</directory>
18. <targetPath>json</targetPath>
19. </resource>
20. </resources>
21. </configuration>
22. </execution>
23. </executions>
24. </plugin>
25. </plugins>
26. </pluginManagement>
This binds the plugin’s add-resource goal to the generate-resources phase in the default POM
lifecycle. We also specified the src/resources directory containing the additional resources.
The plugin execution will copy these resources to the target location in the project output as
required.
Next, we’ll run the maven command to ensure that the configuration is valid and the build is
successful:
After running this, we can see the target location doesn’t yet contain the expected resources.
43
4.2. Child POM Configuration
Now let’s reference this plugin from the child POM:
1. <build>
2. <plugins>
3. <plugin>
4. <groupId>org.codehaus.mojo</groupId>
5. <artifactId>build-helper-maven-plugin</artifactId>
6. </plugin>
7. </plugins>
8. </build>
Similar to dependency management, we don’t declare the version or any plugin configuration.
Instead, child projects inherit these values from the declaration in the parent POM.
Finally, let’s run the build again and look at the output:
....
[INFO] --- build-helper-maven-plugin:3.3.0:add-resource (add-resource) @
submodule-1 ---
[INFO]
Here the plugin executes during the build, but only in the child project with the corresponding
declaration. As a result, the project output now contains the additional resources from the
specified project location, as we expected.
We should note that only the parent POM contains the plugin declaration and configuration,
whilst the child projects just reference this as needed.
The child projects are also free to modify the inherited configuration if required.
44
5. Core Plugins
There are some Maven core plugins that are used by default as part of the build lifecycle. For
example, the clean and compiler plugins don’t need to be declared explicitly.
We can, however, explicitly declare and configure these in the pluginManagement element in
the POM. The main difference is that the core plugin configuration takes effect automatically
without any reference in the child projects.
Let’s try this out by adding the compiler plugin to the familiar pluginManagement section:
1. <pluginManagement>
2. ....
3. <plugin>
4. <groupId>org.apache.maven.plugins</groupId>
5. <artifactId>maven-compiler-plugin</artifactId>
6. <version>3.10.0</version>
7. <configuration>
8. <source>1.8</source>
9. <target>1.8</target>
10. </configuration>
11. </plugin>
12. ....
13. </pluginManagement>
Here we locked down the plugin version, and configured it to use Java 8 to build the project.
However, there’s no additional plugin declaration required in any child projects. The build
framework activates this configuration by default. Therefore, this configuration means that the
build must use Java 8 to compile this project across all modules.
Overall, it can be good practice to explicitly declare the configuration and lockdown the
versions for any plugins required in a multi-module project. Consequently, different child
projects can inherit only the required plugin configurations from the parent POM and apply
them as needed.
This eliminates duplicate declarations, simplifies the POM files, and improves build
reproducibility.
45
6. Conclusion
In this chapter, we learned how to centralize and manage the Maven plugins required for
building a project.
First, we looked at plugins and their usage in the project POM. Then we took a more detailed
look at the Maven plugin management mechanism, and how it helps to reduce duplication
and improve the maintainability of the build configuration.
46
6: Maven Goals and Phases
47
1. Overview
In this chapter, we’ll explore different Maven build lifecycles and their phases.
We’ll also discuss the core relation between Goals and Phases.
48
2. Maven Build Lifecycle
The Maven build follows a specific lifecycle to deploy and distribute the target project.
• clean: to clean the project and remove all files generated by the previous build
Each lifecycle consists of a sequence of phases. The default build lifecycle consists of 23
phases, as it’s the main build lifecycle.
On the other hand, the clean lifecycle consists of 3 phases, while the site lifecycle is made up
of 4 phases.
49
3. Maven Phase
A Maven phase represents a stage in the Maven build lifecycle. Each phase is responsible for
a specific task.
Here are some of the most important phases in the default build lifecycle:
• integration-test: process and deploy the package if needed to run integration tests
For the full list of each lifecycle’s phases, check out the Maven Reference.
Phases are executed in a specific order. This means that if we run a specific phase using the
command:
mvn <PHASE>
It won’t only execute the specified phase, but all the preceding phases as well.
For example, if we run the deploy phase, which is the last phase in the default build lifecycle,
it’ll execute all the phases before the deploy phase as well, which is the entire default lifecycle:
mvn deploy
50
4. Maven Goal
Each phase is a sequence of goals, and each goal is responsible for a specific task.
When we run a phase, all goals bound to this phase are executed in order.
Here are some of the phases and default goals bound to them:
• compiler:compile – the compile goal from the compiler plugin is bound to the compile phase
We can list all goals bound to a specific phase and their plugins using the command:
For example, to list all goals bound to the compile phase, we can run:
org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
As mentioned above, this means the compile goal from the compiler plugin is bound to the
compile phase.
51
5. Maven Plugin
A Maven plugin is a group of goals; however, these goals aren’t necessarily all bound to the
same phase.
For example, here’s a simple configuration of the Maven Failsafe plugin, which is responsible
for running integration tests:
1. <build>
2. <plugins>
3. <plugin>
4. <artifactId>maven-failsafe-plugin</artifactId>
5. <version>${maven.failsafe.version}</version>
6. <executions>
7. <execution>
8. <goals>
9. <goal>integration-test</goal>
10. <goal>verify</goal>
11. </goals>
12. </execution>
13. </executions>
14. </plugin>
15. </plugins>
16. </build>
As we can see, the Failsafe plugin has two main goals configured here:
We can use the following command to list all goals in a specific plugin:
mvn <PLUGIN>:help
For example, to list all goals in the Failsafe plugin, we can run:
mvn failsafe:help
52
And the output will be:
failsafe:help
Display help information on maven-failsafe-plugin.
Call mvn failsafe:help -Ddetail=true -Dgoal=<goal-name> to display parameter
details.
failsafe:integration-test
Run integration tests using Surefire.
failsafe:verify
Verify integration tests ran using Surefire.
To run a specific goal without executing its entire phase (and the preceding phases), we can
use the command:
mvn <PLUGIN>:<GOAL>
For example, to run the integration-test goal from the Failsafe plugin, we need to run:
mvn failsafe:integration-test
53
6. Building a Maven Project
To build a Maven project, we need to execute one of the lifecycles by running one of their
phases:
mvn deploy
This will execute the entire default lifecycle. Alternatively, we can stop at the install phase:
mvn install
But usually, we’ll clean the project first by running the clean lifecycle before the new build:
mvn compiler:compile
Note that if we try to build a Maven project without specifying a phase or goal, we’ll get an
error:
[ERROR] No goals have been specified for this build. You must specify a valid
lifecycle phase or a goal
54
7. Conclusion
In this chapter, we discussed Maven build lifecycles, as well as the relation between Maven
phases and goals.
55
7: Multi-Module Project with Maven
56
1. Overview
In this chapter, we’ll learn how to build a multi-module project with Maven.
First, we’ll discuss what a multi-module project is, and have a look at the benefits of following
this approach. Then we’ll set up our sample project. For a good introduction to Maven, check out
this tutorial.
57
2. Maven’s Multi-Module Project
A multi-module project is built from an aggregator POM that manages a group of submodules.
In most cases, the aggregator is located in the project’s root directory and must have
packaging of type pom.
The submodules are regular Maven projects, and they can be built separately or through the
aggregator POM.
By building the project through the aggregator POM, each project that has a packaging type
different from pom will result in the built archive file.
58
3. Benefits of Using Multi-Modules
The significant advantage of using this approach is that we may reduce duplication.
Let’s say we have an application that consists of several modules, a front-end module and a
back-end module. Now imagine we work on them and change the functionality, which affects
them both. In that case, without a specialized build tool, we’d have to build both components
separately, or write a script to compile the code, run tests, and show the results. Then, after we
got even more modules in the project, it would become harder to manage and maintain.
In the real world, projects may need certain Maven plugins to perform various operations
during the build lifecycle, to share dependencies and profiles, and to include other BOM
projects.
59
4. Parent POM
Maven supports inheritance in a way that each pom.xml file has the implicit parent POM. It’s
called Super POM and can be located in the Maven binaries.
We can create our own pom.xml file, which will serve us as the parent project. Then we
can include in it all the configuration with dependencies, and set it as the parent of our child
modules, so they’ll inherit from it.
Besides inheritance, Maven provides the notion of aggregation. A parent POM that leverages
this functionality is called an aggregate POM. Basically, this kind of POM declares its modules
explicitly in its pom.xml file.
60
5. Submodules
Submodules, or subprojects, are regular Maven projects that inherit from the parent POM.
As we already know, inheritance lets us share the configuration and dependencies with
submodules. However, if we’d like to build or release our project in one shot, we have to
declare our submodules explicitly in the parent POM. Ultimately, our parent POM will be the
parent, as well as the aggregate POM.
61
6. Building the Application
Now that we understand Maven’s submodules and hierarchy, let’s build a sample application to
demonstrate them. We’ll use Maven’s command-line interface to generate our projects.
Since we’ll focus on Maven, the implementation of these services will remain undefined.
Once the parent is generated, we have to open the pom.xml file located in the parent’s
directory and add the packaging as pom:
<packaging>pom</packaging>
By setting the packaging to pom type, we’re declaring that the project will serve as a parent or
an aggregator; it won’t produce further artifacts.
However, we need to note, this is where all the configuration to be shared is located, which
will eventually be re-used in child modules. Among other things, we can make use of
dependencyManagement or pluginManagement here.
cd parent-project
mvn archetype:generate -DgroupId=com.baeldung -DartifactId=core
mvn archetype:generate -DgroupId=com.baeldung -DartifactId=service
mvn archetype:generate -DgroupId=com.baeldung -DartifactId=webapp
62
Notice the command used. It’s the same as we used for the parent. The thing here is, these
modules are regular Maven projects, yet Maven recognized that they’re nested. When we
changed the directory to the parent-project, it found that the parent has the packaging of type
pom, and modified the pom.xml files accordingly.
In the parent-project‘s pom.xml, it’ll add all the submodules inside the modules section:
1. <modules>
2. <module>core</module>
3. <module>service</module>
4. <module>webapp</module>
5. </modules>
And in the individual submodules’ pom.xml, it’ll add the parent-project in the parent section:
1. <parent>
2. <artifactId>parent-project</artifactId>
3. <groupId>com.baeldung</groupId>
4. <version>1.0-SNAPSHOT</version>
5. </parent>
It’s important to note that submodules can have only one parent. However, we can import
many BOMs. More details about the BOM files can be found in this article.
mvn package
This will build all the modules. We should see the following output of the command:
63
[INFO] Reactor Summary for parent-project 1.0-SNAPSHOT:
[INFO] parent-project ..................................... SUCCESS [ 0.272 s]
[INFO] core ............................................... SUCCESS [ 2.043 s]
[INFO] service ............................................ SUCCESS [ 0.627 s]
[INFO] webapp ............................................. SUCCESS [ 0.572 s]
[INFO]
------------------------------------------------------------------------[INFO]
BUILD SUCCESS
[INFO]
------------------------------------------------------------------------
The Reactor lists the parent-project, but since it’s pom type, it’s excluded, and the build results
in three separate .jar files for all the other modules. In this case, build occurs in all three of
them.
Moreover, Maven Reactor will analyze our project and build it in the proper order. So if our
webapp module depends on the service module, Maven will first build the service, then the
webapp.
When we have a set of projects or modules that inherit a common parent, we can put all the
required information about the dependencies in the common pom.xml file. This will simplify the
references to the artifacts in the child POMs.
1. <dependencyManagement>
2. <dependencies>
3. <dependency>
4. <groupId>org.springframework</groupId>
5. <artifactId>spring-core</artifactId>
6. <version>5.3.16</version>
7. </dependency>
8. //...
9. </dependencies>
10. </dependencyManagement>
By declaring the spring-core version in the parent, all submodules that depend on spring-core
can declare the dependency using only the groupId and artifactId, and the version will be
inherited:
64
1. <dependencies>
2. <dependency>
3. <groupId>org.springframework</groupId>
4. <artifactId>spring-core</artifactId>
5. </dependency>
6. //...
7. </dependencies>
Moreover, we can provide exclusions for dependency management in the parent’s pom.xml, so
that specific libraries won’t be inherited by child modules:
1. <exclusions>
2. <exclusion>
3. <groupId>org.springframework</groupId>
4. <artifactId>spring-context</artifactId>
5. </exclusion>
6. </exclusions>
Finally, if a child module needs to use a different version of a managed dependency, we can
override the managed version in the child’s pom.xml file:
1. <dependency>
2. <groupId>org.springframework</groupId>
3. <artifactId>spring-core</artifactId>
4. <version>4.3.30.RELEASE</version>
5. </dependency>
Please note that while child modules inherit from their parent project, a parent project
doesn’t necessarily have any modules that it aggregates. On the other hand, a parent project
may also aggregate projects that don’t inherit from it.
For more information on inheritance and aggregation, please refer to this documentation.
1. <packaging>war</packaging>
65
1. <build>
2. <plugins>
3. <plugin>
4. <groupId>org.apache.maven.plugins</groupId>
5. <artifactId>maven-war-plugin</artifactId>
6. <version>3.3.2</version>
7. <configuration>
8. <failOnMissingWebXml>false</failOnMissingWebXml>
9. </configuration>
10. </plugin>
11. </plugins>
12. </build>
Now we can test the build of our project by using the mvn clean install command. The output
of the Maven logs should be similar to this:
//.............
66
7. Conclusion
Maven is a great tool, but it’s complex on its own. If we want to learn more details about Maven,
we can look at the Sonatype Maven reference or Apache Maven guides. If we seek advanced
usages of Maven’s multi-modules set-up, we can look at how the Spring Boot project
leverages its usage.
All the code examples used in this chapter are available over Github.
67
8: Maven dependencyManagement
vs. dependencies Tags
68
1. Overview
In this chapter, we’ll review two important Maven tags, dependencyManagement and
dependencies.
We’ll review the similarities and differences between the two tags, and then we’ll look at some
common mistakes developers make when using them that can cause confusion.
69
2. Usage
In general, we use the dependencyManagement tag to avoid repeating the version and scope
tags when we define our dependencies in the dependencies tag. In this way, the required
dependency is declared in a central POM file.
2.1. dependencyManagement
This tag consists of a dependencies tag, which in itself might contain multiple dependency tags.
Each dependency is supposed to have at least three main tags: groupId, artifactId, and version.
Let’s see an example:
1. <dependencyManagement>
2. <dependencies>
3. <dependency>
4. <groupId>org.apache.commons</groupId>
5. <artifactId>commons-lang3</artifactId>
6. <version>3.12.0</version>
7. </dependency>
8. </dependencies>
9. </dependencyManagement>
The above code just declares the new artifact, commons-lang3, but it doesn’t really add it to
the project dependency resource list.
2.2. dependencies
This tag contains a list of dependency tags. Each dependency is supposed to have at least two
main tags: groupId and artifactId.
1. <dependencies>
2. <dependency>
3. <groupId>org.apache.commons</groupId>
4. <artifactId>commons-lang3</artifactId>
5. <version>3.12.0</version>
6. </dependency>
7. </dependencies>
70
The version and scope tags can be inherited implicitly if we’ve used the
dependencyManagement tag before in the POM file:
1. <dependencies>
2. <dependency>
3. <groupId>org.apache.commons</groupId>
4. <artifactId>commons-lang3</artifactId>
5. </dependency>
6. </dependencies>
71
3. Similarities
Both of these tags aim to declare some third-party or sub-module dependency. They
complement each other.
In fact, we usually define the dependencyManagement tag once, preceding the dependencies
tag. This is used in order to declare the dependencies in the POM file. This declaration is just
an announcement, and it doesn’t really add the dependency to the project.
1. <dependencyManagement>
2. <dependencies>
3. <dependency>
4. <groupId>junit</groupId>
5. <artifactId>junit</artifactId>
6. <version>4.13.2</version>
7. <scope>test</scope>
8. </dependency>
9. </dependencies>
10. </dependencyManagement>
As we can see in the above code, there’s a dependencyManagement tag that in itself contains
another dependencies tag.
Now let’s see the other side of the code, which adds the actual dependency to the project:
1. <dependencies>
2. <dependency>
3. <groupId>junit</groupId>
4. <artifactId>junit</artifactId>
5. </dependency>
6. </dependencies>
The current tag is very similar to the previous one. Both of them will define a list of
dependencies. Of course, there are small differences, which we’ll cover soon.
The same groupId and artifactId tags are repeated in both code snippets, and there’s a
meaningful correlation between them; both of them refer to the same artifact.
As we can see, there isn’t any version tag present in our later dependency tag. Surprisingly,
it’s valid syntax, and it can be parsed and compiled without any problem. The reason can be
guessed easily; it’ll use the version declared by dependencyManagement.
72
4. Differences
73
5. Real-World Example
Now let’s see an example from the Maven project itself. We can see the hamcrest-
core dependency, which exists in the Maven project. It’s declared first in the
dependencyManagement tag, and then it’s imported by the main dependencies tag:
1. dependencyManagement>
2. <dependencies>
3. <dependency>
4. <groupId>org.hamcrest</groupId>
5. <artifactId>hamcrest-core</artifactId>
6. <version>2.2</version>
7. <scope>test</scope>
8. </dependency>
9. </dependencies>
10. </dependencyManagement>
1. <dependencies>
2. <dependency>
3. <groupId>org.hamcrest</groupId>
4. <artifactId>hamcrest-core</artifactId>
5. <scope>test</scope>
6. </dependency>
7. </dependencies>
74
6. Common Use Cases
Imagine we have a big project that consists of different modules. Each module has its own
dependencies, and each developer might use a different version for the used dependencies.
That could lead to a mesh of different artifact versions, which can also create difficult and hard-
to-resolve conflicts.
The easy solution to this problem is using the dependencyManagement tag in the root POM
file (usually called the “parent”), and then using the dependencies in the child’s POM files
(sub-modules) and even the parent module itself (if applicable).
So if we have a single module, does it make sense to use this feature or not? Although it’s
very useful in multi-module environments, it can also be a rule of thumb to obey it as a best
practice even in a single-module project. This helps the project readability, and also makes it
ready to extend to a multi-module project.
75
7. Common Mistakes
1. <dependencyManagement>
2. <dependencies>
3. <dependency>
4. <groupId>org.apache.commons</groupId>
5. <artifactId>commons-lang3</artifactId>
6. <version>3.12.0</version>
7. </dependency>
8. ...
9. </dependencies>
10. </dependencyManagement>
Imagine the above POM code snippet, and then suppose we’re going to use this library in a
sub-module source file:
1. import org.apache.commons.lang3.StringUtils;
2.
3. public class Main {
4.
5. public static void main(String[] args) {
6. StringUtils.isBlank(“ “);
7. }
8. }
This code won’t compile because of the missing library. The compiler complains about an
error:
To avoid this error, it’s enough to add the below dependencies tag to the sub-module POM file:
1. <dependencies>
2. <dependency>
3. <groupId>org.apache.commons</groupId>
4. <artifactId>commons-lang3</artifactId>
5. </dependency>
6. </dependencies>
76
8. Conclusion
77
9: Maven Packaging Types
78
1. Overview
The packaging type is an important aspect of any Maven project. It specifies the type of artifact
the project produces. Generally, a build produces a jar, war, pom, or other executable.
Maven offers many default packaging types and also provides the flexibility to define a
custom one.
In this chapter, we’ll take a deep dive into Maven packaging types. First, we’ll look at the build
lifecycles in Maven. Then we’ll discuss each packaging type, what they represent, and their
effect on the project’s lifecycle. Finally, we’ll learn how to define a custom packaging type.
79
2. Default Packaging Types
Maven offers many default packaging types that include a jar, war, ear, pom, rar, ejb, and
maven-plugin. Each packaging type follows a build lifecycle that consists of phases.
Different packaging types may have different goals in a particular phase. For example, in the
package phase of a jar packaging type, maven-jar-plugin‘s jar goal is executed. Conversely, for
a war project,
2.1. jar
Java archive, or jar, is one of the most popular packaging types. Projects with this packaging
type produce a compressed zip file with the .jar extension. It may include pure Java classes,
interfaces, resources, and metadata files.
To begin with, let’s look at some of the default goal-to-build-phase bindings for the jar:
• resources: resources
• compiler: compile
• resources: testResources
• compiler: testCompile
• surefire: test
• jar: jar
• install: install
• deploy: deploy
• install: install
• deploy: deploy
1. <packaging>jar</packaging>
If nothing has been specified, Maven assumes the packaging type is a jar.
80
2.2. war
Simply put, a web application archive, or war, contains all files related to a web application. It
may include Java servlets, JSPs, HTML pages, a deployment descriptor, and related resources.
Overall, war has the same goal bindings as a jar, but with one exception; the package phase of
the war has a different goal, which is war.
Without a doubt, jar and war are the most popular packaging types in the Java community. A
detailed difference between these two might be an interesting read.
1. <packaging>war</packaging>
The other packaging types, ejb, par, and rar, also have similar lifecycles, but each has a
different package goal:
2.3. ear
Enterprise application archive, or ear, is a compressed file that contains a J2EE application.
It consists of one or more modules that can be web modules (packaged as a war file), EJB
modules (packaged as a jar file), or both of them.
To put it differently, the ear is a superset of jars and wars, and requires an application server
to run the application, whereas war requires only a web container or web server to deploy it.
The aspects that distinguish a web server from an application server, and what those popular
servers are in Java, are important concepts for a Java developer.
• ear: generate-application-xml
• resources: resources
• ear: ear
• install: install
• deploy: deploy
1. <packaging>ear</packaging>
81
2.4. pom
Among all packaging types, pom is the simplest one. It helps to create aggregators and parent
projects.
A parent project allows us to define the inheritance relationship between POMs. The parent
POM shares certain configurations, plugins, and dependencies, along with their versions. Most
elements from the parent are inherited by its children, but exceptions include artifactId, name,
and prerequisites.
This is because there are no resources to process and no code to compile or test. Therefore,
the artifacts of pom projects generate themselves instead of any executable.
1. <packaging>pom</packaging>
Such projects have the simplest lifecycle that consists of only two steps: install and deploy.
2.5. maven-plugin
Maven offers a variety of useful plugins; however, there might be cases when default plugins
aren’t sufficient enough. In those cases, the tool provides the flexibility to create a maven-
plugin, according to the project’s needs.
1. <packaging>maven-plugin</packaging>
The maven-plugin has a lifecycle similar to jar‘s lifecycle, but with two exceptions:
82
2.6. ejb
Enterprise Java Beans, or ejb, help to create scalable, distributed server-side applications. EJBs
often provide the business logic of an application.
A typical EJB architecture consists of three components: Enterprise Java Beans (EJBs), the EJB
container, and an application server.
1. <packaging>ejb</packaging>
The ejb packaging type also has a similar lifecycle as jar packaging, but with a different
package goal. The package goal for this type of project is ejb:ejb.
The project, with ejb packaging type, requires a maven-ejb-plugin to execute lifecycle goals.
Maven provides support for EJB 2 and 3. If no version is specified, then the default version 2 is
used.
2.7. rar
Resource adapter, or rar, is an archive file that serves as a valid format for the deployment of
resource adapters to an application server. Basically, it’s a system-level driver that connects a
Java application to an enterprise information system (EIS).
1. <packaging>rar</packaging>
Every resource adapter archive consists of two parts: a jar file that contains source code, and a
ra.xml that serves as a deployment descriptor.
Again, the lifecycle phases are the same as a jar or war packaging with one exception; the
package phase executes the rar goal that consists of a maven-rar-plugin to package the
archives.
83
3. Other Packaging Types
So far, we’ve looked at the various packaging types that Maven offers by default. Now let’s
imagine we want our project to produce an artifact with a .zip extension. In this case, the
default packaging types can’t help us.
Maven also provides some more packaging types through plugins. With the help of these
plugins, we can define a custom packaging type and its build lifecycle. Some of these types
are:
• msi
• rpm
• tar
• tar.bz2
• tar.gz
• tbz
• zip
To define a custom type, we have to define its packaging type and phases in its lifecycle.
For this, we’ll create a components.xml file under the src/main/resources/META-INF/plexus
directory:
1. <component>
2. <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
3. <role-hint>zip</role-hint>
4. <implementation>org.apache.maven.lifecycle.mapping.
5. DefaultLifecycleMapping</implementation>
6. <configuration>
7. <phases>
8. <process-resources>org.apache.maven.plugins:maven-resources-
9. plugin:resources</process-resources>
10. <package>com.baeldung.maven.plugins:maven-zip-plugin:zip</
11. package>
12. <install>org.apache.maven.plugins:maven-install-
13. plugin:install</install>
14. <deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</
15. deploy>
16. </phases>
17. </configuration>
18. </component>
Up to this point, Maven doesn’t know anything about our new packaging type and its lifecycle.
To make it visible, we’ll add the plugin in the pom file of the project and set extensions to true:
84
1. <plugins>
2. <plugin>
3. <groupId>com.baeldung.maven.plugins</groupId>
4. <artifactId>maven-zip-plugin</artifactId>
5. <extensions>true</extensions>
6. </plugin>
7. </plugins>
Now the project will be available for a scan, and the system will look into the plugins and
components.xml files, too.
In addition to all of these types, Maven offers a lot of other packaging types through external
projects and plugins. For example, nar (native archive), swf, and swc are packaging types for
the projects that produce Adobe Flash and Flex content. For such projects, we need a plugin
that defines custom packaging and a repository that contains the plugin.
85
4. Conclusion
In this chapter, we looked at the various packaging types available in Maven. We also became
familiar with what these types represent, and how they differ in their lifecycles. Finally, we
learned how to define a custom packaging type and customize the default build lifecycle.
All code examples on Baeldung are built using Maven. Be sure to check out our various Maven
configurations over on GitHub.
86
10: The settings.xml File in Maven
87
1. Overview
While using Maven, we keep most of the project-specific configuration in the pom.xml.
Maven provides a settings file, settings.xml, which allows us to specify which local and remote
repositories it’ll use. We can also use it to store settings that we don’t want in our source code,
such as credentials.
In this chapter, we’ll learn how to use the settings.xml. We’ll look at proxies, mirroring, and
profiles. We’ll also discuss how to determine the current settings that apply to our project.
88
2. Configurations
The settings.xml file configures a Maven installation. It’s similar to a pom.xml file, but is defined
globally or per user.
Let’s explore the elements we can configure in the settings.xml file. The main settings element
of the settings.xml file can contain nine possible predefined child elements:
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0
4. https://maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <localRepository/>
6. <interactiveMode/>
7. <offline/>
8. <pluginGroups/>
9. <servers/>
10. <mirrors/>
11. <proxies/>
12. <profiles/>
13. <activeProfiles/>
14. </settings>
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <localRepository>${user.home}/.m2/repository</localRepository>
6. <interactiveMode>true</interactiveMode>
7. <offline>false</offline>
8. </settings>
89
The localRepository element points to the path of the system’s local repository. The local
repository is where all the dependencies from our projects get cached. The default is to use
the user’s home directory; however, we could change it to allow all logged-in users to build
from a common local repository.
The interactiveMode flag defines if we allow Maven to interact with the user asking for input.
This flag defaults to true.
The offline flag determines if the build system may operate in offline mode. This defaults to
false; however, we can switch it to true in cases where the build servers cannot connect to a
remote repository.
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <pluginGroups>
6. <pluginGroup>org.apache.tomcat.maven</pluginGroup>
7. </pluginGroups>
8. </settings>
Maven searches the list of plugin groups when a plugin is used without a groupId provided
at the command line. The list contains the groups
org.apache.maven.plugins and org.codehaus.mojo by default.
The settings.xml file defined above allows us to execute truncated Tomcat plugin commands:
mvn tomcat7:help
mvn tomcat7:deploy
mvn tomcat7:run
2.3. Proxies
We can configure a proxy for some or all of Maven’s HTTP requests. The proxies element
allows a list of child proxy elements, but only one proxy can be active at a time:
90
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <proxies>
6. <proxy>
7. <id>baeldung-proxy</id>
8. <active>true</active>
9. <protocol>http</protocol>
10. <host>baeldung.proxy.com</host>
11. <port>8080</port>
12. <username>demo-user</username>
13. <password>dummy-password</password>
14. <nonProxyHosts>*.baeldung.com|*.apache.org</nonProxyHosts>
15. </proxy>
16. </proxies>
17. </settings>
We define the currently active proxy via the active flag. Then with the nonProxyHosts element,
we specify which hosts aren’t proxied. The delimiter used depends on the specific proxy server.
The most common delimiters are pipe and comma.
2.4. Mirrors
Repositories can be declared inside a project pom.xml. This means that the developers sharing
the project code get the right repository settings out of the box.
We can use mirrors in cases where we want to define an alternative mirror for a particular
repository. This overrides what’s in the pom.xml.
For example, we can force Maven to use a single repository by mirroring all repository
requests:
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <mirrors>
6. <mirror>
7. <id>internal-baeldung-repository</id>
8. <name>Baeldung Internal Repo</name>
9. <url>https://baeldung.com/repo/maven2/</url>
10. <mirrorOf>*</mirrorOf>
11. </mirror>
12. </mirrors>
13. </settings>
91
We may define only one mirror for a given repository, and Maven will pick the first match.
Normally, we should use the official repository distributed worldwide via CDN.
2.5. Servers
Defining repositories in the project pom.xml is a good practice. However, we shouldn’t put
security settings, such as credentials, into our source code repository with the pom.xml. Instead,
we define this secure information in the settings.xml file:
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <servers>
6. <server>
7. <id>internal-baeldung-repository</id>
8. <username>demo-user</username>
9. <password>dummy-password</password>
10. <privateKey>${user.home}/.ssh/bael_key</privateKey>
11. <passphrase>dummy-passphrase</passphrase>
12. <filePermissions>664</filePermissions>
13. <directoryPermissions>775</directoryPermissions>
14. <configuration></configuration>
15. </server>
16. </servers>
17. </settings>
We should note that the ID of the server in the settings.xml needs to match the ID element of
the repository mentioned in the pom.xml. The XML also allows us to use placeholders to pick
up credentials from environment variables.
92
3. Profiles
The profiles element enables us to create multiple profile child elements differentiated by their
ID child element. The profile element in the
settings.xml is a truncated version of the same element available in the
pom.xml.
It can contain only four child elements: activation, repositories, pluginRepositories, and
properties. These elements configure the build system as a whole, instead of any particular
project.
It’s important to note that values from an active profile in settings.xml will override any
equivalent profile values in a pom.xml or profiles.xml file. Profiles are matched by ID.
93
3.1. Activation
We can use profiles to modify certain values only under given circumstances. We can specify
those circumstances using the activation element. Consequently, profile activation occurs
when all specified criteria are met:
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <profiles>
6. <profile>
7. <id>baeldung-test</id>
8. <activation>
9. <activeByDefault>false</activeByDefault>
10. <jdk>1.8</jdk>
11. <os>
12. <name>Windows 10</name>
13. <family>Windows</family>
14. <arch>amd64</arch>
15. <version>10.0</version>
16. </os>
17. <property>
18. <name>mavenVersion</name>
19. <value>3.0.7</value>
20. </property>
21. <file>
22. <exists>${basedir}/activation-file.properties</
23. exists>
24. <missing>${basedir}/deactivation-file.properties</
25. missing>
26. </file>
27. </activation>
28. </profile>
29. </profiles>
30. </settings>
There are four possible activators, and not all of them need to be specified:
• jdk: activates based on the JDK version specified (ranges are supported)
• os: activates based on operating system properties
• property: activates the profile if Maven detects a specific property value
• file: activates the profile if a given filename exists or is missing
In order to check which profile will activate a certain build, we can use the Maven help plugin:
mvn help:active-profiles
94
The output will display the currently active profiles for a given project:
[INFO]
Active Profiles for Project ‘com.baeldung.core-java-modules:core-java-streams-
3:jar:0.1.0-SNAPSHOT’:
3.2. Properties
Maven properties can be thought of as named placeholders for a certain value. The values are
accessible within a pom.xml file using the
${property_name} notation:
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <profiles>
6. <profile>
7. <id>baeldung-test</id>
8. <properties>
9. <user.project.folder>${user.home}/baeldung-tutorials</
10. user.project.folder>
11. </properties>
12. </profile>
13. </profiles>
14. </settings>
• Properties using the env prefix return an environment variable value, such as ${env.PATH}.
• Properties using the project prefix return a property value set in the project element of the
pom.xml, such as ${project.version}.
• Properties using the settings prefix return the corresponding element’s value from the
settings.xml, such as ${settings.localRepository}.
• We may reference all properties available via the System.getProperties method in Java
directly, such as ${java.home}.
• We may use properties set within a properties element without a prefix, such as ${junit.
version}.
95
3.3. Repositories
Remote repositories contain collections of artifacts that Maven uses to populate our local
repository. Different remote repositories may be needed for particular artifacts. Maven
searches the repositories enabled under the active profile:
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <profiles>
6. <profile>
7. <id>adobe-public</id>
8. <repositories>
9. <repository>
10. <id>adobe-public-releases</id>
11. <name>Adobe Public Repository</name>
12. <url>https://repo.adobe.com/nexus/content/groups/
13. public</url>
14. <releases>
15. <enabled>true</enabled>
16. <updatePolicy>never</updatePolicy>
17. </releases>
18. <snapshots>
19. <enabled>false</enabled>
20. </snapshots>
21. </repository>
22. </repositories>
23. </profile>
24. </profiles>
25. </settings>
We can use the repository element to enable only release or snapshots versions of artifacts
from a specific repository.
96
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <profiles>
6. <profile>
7. <id>adobe-public</id>
8. <pluginRepositories>
9. <pluginRepository>
10. <id>adobe-public-releases</id>
11. <name>Adobe Public Repository</name>
12. <url>https://repo.adobe.com/nexus/content/groups/
13. public</url>
14. <releases>
15. <enabled>true</enabled>
16. <updatePolicy>never</updatePolicy>
17. </releases>
18. <snapshots>
19. <enabled>false</enabled>
20. </snapshots>
21. </pluginRepository>
22. </pluginRepositories>
23. </profile>
24. </profiles>
25. </settings>
Notably, the structure of the pluginRepositories element is very similar to the repositories
element.
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <activeProfiles>
6. <activeProfile>baeldung-test</activeProfile>
7. <activeProfile>adobe-public</activeProfile>
8. </activeProfiles>
9. </settings>
97
4. Settings Level
If both files exist, their contents are merged. Configurations from the user settings take
precedence.
mvn help:effective-settings
1. <settings xmlns=”http://maven.apache.org/SETTINGS/1.0.0”
2. xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
3. xsi:schemaLocation=”http://maven.apache.org/SETTINGS/1.0.0 https://
4. maven.apache.org/xsd/settings-1.0.0.xsd”>
5. <localRepository>C:\Users\Baeldung\.m2\repository</localRepository>
6. <pluginGroups>
7. <pluginGroup>org.apache.tomcat.maven</pluginGroup>
8. <pluginGroup>org.apache.maven.plugins</pluginGroup>
9. <pluginGroup>org.codehaus.mojo</pluginGroup>
10. </pluginGroups>
11. </settings>
98
4.3. Override the Default Location
Maven allows us to override the location of the global and user settings via the command line:
99
5. Conclusion
We learned how to configure proxies, repositories, and profiles. Next, we looked at the
difference between global and user settings files, and how to determine which are in use.
Finally, we looked at determining the effective settings used, and overriding default file
locations.
100