BRM Lab
BRM Lab
Management
2. Build and Release Management Lab
Prerequisites for this lab
1
2.2.1.3 Repository Settings Details
2.2.3 Profiles
2
Prerequisites for this lab:
1. Openjdk-1.8
3. Nexus Repository
4. Windows 7/10
Maven is based on the concept of POM files (Project Object Model). It is an XML
representation of project resources like dependencies, source code, test code,
etc. All the references of these resources are configured in the POM. The POM file
is present in the root directory of the project.
3
Below diagram illustrates how POM file is used by maven and what POM files
contain:
All the above steps mentioned in the picture are briefly explained in the below
sections of this lab guide:
In maven the build process is split into different build life cycles, phases and goals.
Build life cycle is a sequence of build phases, and each build phase consists of a
sequence of goals. When you run Maven you pass a command to Maven. This
command is the name of a build life cycle, phase or goal. If a life cycle is requested
executed, all build phases in that life cycle are executed. If a build phase is
4
requested executed, all build phases before it in the pre-defined sequence of
build phases are executed too.
One of the first goals Maven executes is to check the dependencies needed by
your project. Dependencies are external JAR files (Java libraries) that your project
uses. If the dependencies are not found in the local Maven repository, Maven
downloads them from a central Maven repository and puts them in your local
repository. The local repository is just a directory on your computer's hard disk.
You can specify where the local repository should be located if you want to (I do).
You can also specify which remote repository to use for downloading
dependencies. All this will be explained in more detail later in this tutorial.
Build plugins are used to insert extra goals into a build phase. If you need to
perform a set of actions for your project which are not covered by the standard
Maven build phases and goals, you can add a plugin to the POM file. Maven has
some standard plugins you can use, and you can also implement your own in Java
if you need to.
Build profiles are used if you need to build your project in different ways. For
instance, you may need to build your project for your local computer, for
development and test. And you may need to build it for deployment on your
production environment. These two builds may be different. To enable different
builds you can add different build profiles to your POM files. When executing
Maven you can tell which build profile to use.
5
2.1.2 Setting up maven
Note: Maven requires a Java platform to run the commands. First, make sure
that you have installed the Java environment on your system, Java Development
Kit (JDK) specifically; Java Runtime Environment (JRE) is not sufficient.
Lab:
1. Windows (X86/64)
The openjdk-8-jre package contains just the Java Runtime Environment. If you
want to develop Java programs then please install the openjdk-8-jdk package.
6
3. Fedora, Oracle Linux, Red Hat Enterprise Linux, etc.
7
Type C:> java -version
1. Set the JAVA_HOME environment variable to point to a valid Java SDK (e.g.,
Java 8).
6. Open a command prompt and type 'mvn -version' (without quotes) and press
enter.
8
After running mvn -version command you can see that maven command is
executed, and the version details of Maven is written out to the command
prompt.
Ensure the contents of you maven installation are similar to the following screenshot:
● The bin folder contains the batch files and shell scripts to run Maven on
various platforms.
● The boot folder contains the jars required for Maven to start.
● The conf folder contains the default settings.xml file used by Maven.
● The lib folder contains the libraries used by Maven. It also contains
an ext folder in which third-party extensions, which can extend or override the
default Maven implementation, can be placed.
9
More details:
The mvn command essentially runs this batch file. It first checks for JAVA_HOME.
This file is present in the bin folder of the Maven installation and, hence, it needs
to be in PATH.
If the batch file does not find JAVA_HOME, it looks for Java in its PATH. This can
lead to unexpected results, as typically the Java in PATH is usually the JRE and not
the JDK.
The batch file, then looks for M2_HOME, which is the location of the Maven
installation. It does this so that it can load the libraries that are present.
Using the values for JAVA_HOME, M2_HOME, and Maven_OPTS, the batch file
run its main class org.codehaus.plexus.classworlds.launcher.Launcher.
Solution: 1. Go to path_to_maven/bin and type mvn -version . If that works then it's a PATH
problem.In command prompt type set PATH=path_to_maven/bin;%PATH%
10
Solution: 2. JAVA_HOME should be set to fix this issue. Refer 2.1.2.2
Note: Restart your command prompt for the changes to PATH to take effect
Lab:
Command output: It will take a while to execute the command because maven is downloading
the most recent artifacts into the local repository. Once the command is executed successfully,
you would see the similar output as below:
[INFO]
11
[INFO]
[INFO]
Every Maven project has a pom file that defines what the project is all about and
how it should be built. Pom is an acronym for the project object model. Let us
take a peek at this file.
Lab:
A pom file is an XML file that is based on a specific schema, as specified at the top
of the file:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
12
<modelVersion>4.0.0</modelVersion>
<groupId>com.skaas.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>my-app</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
There is also a modelVersion element that defines the version of this schema:
13
<modelVersion>4.0.0</modelVersion>
<groupId>...</groupId>
The artifactId element is the name of the project. For our sample project, it
is simple-project:
<artifactId>...</artifactId>
The version element is the specific instance of the project, corresponding to the
source code at a particular instance of time. In our case, it is 1.0-SNAPSHOT,
which is a default version during development:
<version>...</version>
We will explore the difference between the SNAPSHOT and concrete versions
later in the book.
The combination of groupId, artifactId, and version uniquely identifies the project.
In this sense, they are the coordinates of the project.
14
The packaging element indicates the artifact type of the project. This is typically
a jar, war, zip, or in some cases, a pom:
<packaging>...</packaging>
The dependencies element section of the pom file defines all the dependent
projects of this project. This would typically be third-party libraries required to
build, test, and run the project:
<dependencies>...</dependencies>
<parent>...</parent>
Maven properties are placeholders. Their values are accessible anywhere in the
pom file by using ${key}, where key is the property name:
<properties>...</properties>
<modules>...</modules>
15
This section will show how to deploy the artifacts of a project to Nexus, with
Maven.
The configuration for Apache Maven usage itself and projects built with resides in
a number of places:
This variable contains parameters used to start up the JVM running Maven and
can be used to supply additional options to globally to Maven. E.g., JVM memory
settings could be defined with the value -Xms256m -Xmx512m.
• settings.xml file:
• .mvn folder:
Located within the projects top level folder, the files maven.config and
extensions.xml contain the project specific configuration for running Maven.
Lab:
You can use the MAVEN_OPTS environment variable to set the maximum allowed
heap size for Maven at a global level. The following command will set the heap
size in any Unix-based operating system, including Linux and Mac OS X. Make sure
that the value set as the maximum heap size does not exceed your system
memory of the machine, which runs Maven:
16
Open a command prompt on windows and run below command:
If you are running this command on Linux, run the below ommand:
Purpose
17
• Increased performance for interaction with remote SNAPSHOT repositories
• Creates a central storage and access to artifacts and meta data about them,
exposing build outputs to consumer such as other projects and developers, but
also QA or operations teams or even customers
The following list of open source and commercial repository managers are
known to support the repository format used by Maven. Please refer to the
respective linked web sites for further information about repository
management in general and the features provided by these products.
• CloudRepo (commercial)
• packagecloud.io (commercial)
18
The settings element in the settings.xml file contains elements used to define
values which configure Maven execution in various ways, like the pom.xml, but
should not be bundled to any specific project, or distributed to an audience.
These include values such as the local repository location, alternate remote
repository servers, and authentication information.
The former settings.xml is also called global settings, the latter settings.xml is
referred to as user settings. If both files exist, their contents gets merged, with
the user-specific settings.xml being dominant.
Tip: If you need to create user-specific settings from scratch, it’s easiest to copy
the global settings from your Maven installation to
your ${user.home}/.m2 directory. Maven’s default settings.xml is a template with
comments and examples so you can quickly tweak it to match your needs.
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
19
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups/>
<servers/>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles/>
</settings>
Note that properties defined in profiles within the settings.xml cannot be used
for interpolation.
20
2.2.1.3 Repository Settings Details
Simple Values
Half of the top-level settings elements are simple values, representing a range of
values which describe elements of the build system that are active full-time.
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-
1.0.0.xsd">
<localRepository>${user.home}/.m2/repository</localRepository>
<interactiveMode>true</interactiveMode>
<usePluginRegistry>false</usePluginRegistry>
<offline>false</offline>
...
</settings>
• localRepository: This value is the path of this build system’s local repository.
The default value is ${user.home}/.m2/repository. This element is especially useful
for a main build server, allowing all logged-in users to build from a common
local repository.
21
• interactiveMode: true if Maven should attempt to interact with the user for
input, false if not. Defaults to true.
• offline: true if this build system should operate in offline mode, defaults
to false. This element is useful for build servers which cannot connect to a
remote repository, either because of network setup or security reasons.
Plugin Groups
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-
1.0.0.xsd">
...
<pluginGroups>
<pluginGroup>org.mortbay.jetty</pluginGroup>
22
</pluginGroups>
...
</settings>
For example, given the above settings the Maven command line may
execute org.mortbay.jetty:jetty-maven-plugin:run with the truncated command:
Lab:
mvn jetty:run
<distributionManagement>
<snapshotRepository>
<id>nexus-snapshots</id>
<url>http://localhost:8081/nexus/content/repositories/
snapshots</url>
</snapshotRepository>
</distributionManagement>
23
A hosted, public Snapshots repository comes out of the box on Nexus, so there’s
no need to create or configure anything further. Nexus makes it easy to
determine the URLs of its hosted repositories – each repository displays the exact
entry to be added in the <distributionManagement> of the project pom
A new feature - server password and passphrase encryption has been added to
2.1.0+.
Password Encryption
1. Introduction
5. Tips
Introduction
Maven 2.1.0+ now supports server password encryption. The main use case,
addressed by this solution is:
• some users have the privilege to deploy Maven artifacts to repositories, some
don't.
24
o this applies to any server operations, requiring authorization, not only
deployment
o this file either contains encrypted master password, used to encrypt other
passwords
o for now - this is done via CLI after master password has been created and
stored in appropriate location
Lab:
25
Maven will prompt for the password. Earlier versions of Maven will not prompt
for a password, so it must be typed on the command-line in plaintext.
{RbzGWnojSMOVrIt5kPFgsHVpMvz5pI8u+9EF1iFQyJQ=}
<settingsSecurity>
<master>{ RbzGWnojSMOVrIt5kPFgsHVpMvz5pI8u+9EF1iFQyJQ
}</master>
</settingsSecurity>
When this is done, you can start encrypting existing server passwords.
26
This command will produce an encrypted version of it, something like
{6DU6COtcS5PQLCEG=}
Cut-n-paste it into your settings.xml file in the server section. This will look like:
<settings>
...
<servers>
...
<server>
<id>my.server</id>
<username>foo</username>
<password>{COQLCE6DU6GtcS5P=}</password>
</server>
...
</servers>
...
</settings>
27
Please note that the password can contain any information outside of the curly
brackets, so that the following will still work:
<settings>
...
<servers>
...
<server>
<id>my.server</id>
<username>foo</username>
</server>
...
</servers>
...
</settings>
Then you can use, say, deploy plugin, to write to this server:
-DrepositoryId=my.server \
-Dfile=your-artifact-1.0.jar \
28
How to keep the master password on removable drive
<settingsSecurity>
<master>{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}</master>
</settingsSecurity>
<settingsSecurity>
<relocation>/Volumes/mySecureUsb/secure/settings-
security.xml</relocation>
</settingsSecurity>
This assures that encryption will only work when the USB drive is mounted by
the OS. This addresses an use case where only a certain people are authorized to
deploy and are issued these devices.
29
Tips
At times, you might find that your password (or the encrypted form of it) may
actually contain '{' or '}' as a literal value. If you added such a password as-is to
your settings.xml file, you would find that Maven does strange things with it.
Specifically, Maven will treat all the characters preceding the '{' literal, and all the
characters after the '}' literal, as comments. Obviously, this is not the behavior
you want in such a situation. What you really need is a way of escaping the curly-
brace literals in your password.
Starting in Maven 2.2.0, you can do just this, with the widely used '\' escape
character. If your password looks like this:
jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+{EF1iFQyJQ=
Then, the value you would add to your settings.xml would look like this:
{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+\{EF1iFQyJQ=}
Password Security
Editing settings.xml and running the above commands can still leave your
password stored locally in plaintext. You may want to check the following
locations:
• Shell history (e.g. by running history). You may want to clear your history after
encrypting the above passwords
30
• Editor caches (e.g. ~/.viminfo)
Also note that the encrypted passwords can be decrypted by someone that has
the master password and settings security file. Keep this file secure (or stored
separately) if you expect the possibility that the settings.xml file may be
retrieved.
If you are on a linux/unix platform you should use single quotes for the above
master password, otherwise you will be astonished that the usage of the master-
password will not work (caused by the dollar sign and furthermore the
exclamation mark).
31
Prompting for Password
In Maven before version 3.2.1 you have to give the password on command line
as argument, which means you might need to escape your password. In addition
usually the shell stores the full history of commands you have entered, therefore
anyone with access to your computer could restore the password from the
shell`s history.
Starting with Maven 3.2.1 the password is an optional argument, which means if
you omit the password you will be prompted for it which prevents all the issues
mentioned above.
Mirrors
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<mirrors>
<mirror>
32
<id>planetmirror.com</id>
<name>PlanetMirror Australia</name>
<url>http://downloads.planetmirror.com/pub/maven2</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
...
</settings>
• id, name: The unique identifier and user-friendly name of this mirror. The id is
used to differentiate between mirror elements and to pick the corresponding
credentials from the <servers>section when connecting to the mirror.
• url: The base URL of this mirror. The build system will use this URL to connect
to a repository rather than the original repository URL.
• mirrorOf: The id of the repository that this is a mirror of. For example, to point
to a mirror of the Maven central repository
(https://repo.maven.apache.org/maven2/), set this element to central. More
advanced mappings like repo1,repo2 or *,!inhouse are also possible. This must
not match the mirror id.
33
Proxies
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-
1.0.0.xsd">
...
<proxies>
<proxy>
<id>myproxy</id>
<active>true</active>
<protocol>http</protocol>
<host>proxy.somewhere.com</host>
<port>8080</port>
<username>proxyuser</username>
<password>somepassword</password>
<nonProxyHosts>*.google.com|ibiblio.org</nonProxyHosts>
</proxy>
</proxies>
...
</settings>
34
• id: The unique identifier for this proxy. This is used to differentiate
between proxy elements.
• active: true if this proxy is active. This is useful for declaring a set of proxies,
but only one may be active at a time.
• username, password: These elements appear as a pair denoting the login and
password required to authenticate to this proxy server.
2.2.3 Profiles
If a profile is active from settings, its values will override any equivalently ID’d
profiles in a POM or profiles.xml file.
35
Lab:
Activation
Activations are the key of a profile. Like the POM’s profiles, the power of a
profile comes from its ability to modify some values only under certain
circumstances; those circumstances are specified via an activation element.
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-
1.0.0.xsd">
...
<profiles>
<profile>
<id>test</id>
<activation>
<activeByDefault>false</activeByDefault>
<jdk>1.5</jdk>
<os>
<name>Windows 7</name>
<family>Windows</family>
<arch>x86</arch>
<version>5.1.2600</version>
36
</os>
<property>
<name>mavenVersion</name>
<value>2.0.3</value>
</property>
<file>
<exists>${basedir}/file2.properties</exists>
<missing>${basedir}/file1.properties</missing>
</file>
</activation>
...
</profile>
</profiles>
...
</settings>
Activation occurs when all specified criteria have been met, though not all are
required at once.
• jdk: activation has a built in, Java-centric check in the jdk element. This will
activate if the test is run under a jdk version number that matches the prefix
given. In the above example, 1.5.0_06 will match. Ranges are also supported as
of Maven 2.1. See the maven-enforcer-plugin for more details about supported
ranges.
37
• os: The os element can define some operating system specific properties
shown above. See the maven-enforcer-plugin for more details about OS values.
• property: The profile will activate if Maven detects a property (a value which
can be dereferenced within the POM by ${name}) of the
corresponding name=value pair.
• file: Finally, a given filename may activate the profile by the existence of a file, or
if it is missing.
The activation element is not the only way that a profile may be activated.
The settings.xml file’s activeProfile element may contain the profile’s id. They
may also be activated explicitly through the command line via a comma
separated list after the -P flag (e.g. -P test).
To see which profile will activate in a certain build, use the maven-help-plugin.
mvn help:active-profiles
38
In this example, we’ve added a profile named production that overrides the
default configuration of the Maven Compiler plugin. Let’s examine the syntax of
this profile in detail.
2. Each profile has to have an id element. This id element contains the name
which is used to invoke this profile from the command-line. A profile is
invoked by passing the -P<profile_id> command-line argument to Maven.
3. A profile element can contain many of the elements which can appear under
the project element of a POM XML Document. In this example, we’re
overriding the behavior of the Compiler plugin and we have to override the
plugin configuration which is normally enclosed in a build and a plugins
element.
To execute mvn install under the production profile, you need to pass the -
Pproduction argument on the command-line. To verify that
the production profile overrides the default Compiler plugin configuration
39
Using a Maven Profile to Override Production Compiler Settings
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-
v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>simple</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>simple</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
40
<profiles> (1)
<profile>
<id>production</id> (2)
<build> (3)
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-
compiler-plugin</artifactId>
<configuration>
<debug>false</debug>
(4)
<optimize>true</optimize>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
41
Properties
Maven properties are value placeholder, like properties in Ant. Their values are
accessible anywhere within a POM by using the notation ${X}, where X is the
property. They come in five different styles, all accessible from
the settings.xml file:
1. env.X: Prefixing a variable with “env.” will return the shell’s environment
variable. For example, ${env.PATH} contains the $path environment variable
(%PATH% in Windows).
2. project.x: A dot (.) notated path in the POM will contain the corresponding
element’s value. For example: <project><version>1.0</version></project> is
accessible via ${project.version}.
3. settings.x: A dot (.) notated path in the settings.xml will contain the
corresponding element’s value. For
example: <settings><offline>false</offline></settings> is accessible
via ${settings.offline}.
5. x: Set within a <properties /> element or an external files, the value may be
used as ${someVar}.
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
42
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-
1.0.0.xsd">
...
<profiles>
<profile>
...
<properties>
<user.install>${user.home}/our-
project</user.install>
</properties>
...
</profile>
</profiles>
...
</settings>
<project>
...
<properties>
43
<server.url>http://localhost:8080/manager/html</server.url>
</properties>
...
<build>
<plugins>
<plugin>
...
<configuration>
<url>${server.url}</url>
<server>tomcat</server>
</configuration>
...
</plugin>
</plugins>
</build>
</project>
In the above example {Server.url} will be replaced by the actual URL at the run
time.
44
contain different projects, and under the active profile they may be searched for
a matching release or snapshot artifact.
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-
1.0.0.xsd">
...
<profiles>
<profile>
...
<repositories>
<repository>
<id>codehausSnapshots</id>
<name>Codehaus Snapshots</name>
<releases>
<enabled>false</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
45
<updatePolicy>never</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
<url>http://snapshots.maven.codehaus.org/maven2</url>
<layout>default</layout>
</repository>
</repositories>
<pluginRepositories>
...
</pluginRepositories>
...
</profile>
</profiles>
...
</settings>
• releases, snapshots: These are the policies for each type of artifact, Release or
snapshot. With these two sets, a POM has the power to alter the policies for
each type independently of the other within a single repository. For example,
one may decide to enable only snapshot downloads, possibly for development
purposes.
• enabled: true or false for whether this repository is enabled for the respective
type (releases or snapshots).
46
• updatePolicy: This element specifies how often updates should attempt to
occur. Maven will compare the local POM’s timestamp (stored in a repository’s
maven-metadata file) to the remote. The choices
are: always, daily (default), interval:X (where X is an integer in minutes) or never.
• layout: In the above description of repositories, it was mentioned that they all
follow a common layout. This is mostly correct. Maven 2 has a default layout
for its repositories; however, Maven 1.x had a different layout. Use this
element to specify which, if it is default or legacy.
Repositories are home to two major types of artifacts. The first is artifacts that
are used as dependencies of other artifacts. These are the majority of plugins
that reside within central. The other type of artifact is plugins. Maven plugins are
themselves a special type of artifact. Because of this, plugin repositories may be
separated from other repositories (although, I have yet to hear a convincing
argument for doing so). In any case, the structure of
the pluginRepositories element block is similar to the repositories element.
The pluginRepository elements, each specify a remote location of where Maven
can find new plugins.
47
Active Profiles
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-
1.0.0.xsd">
...
<activeProfiles>
<activeProfile>env-test</activeProfile>
</activeProfiles>
</settings>
The final piece of the settings.xml puzzle is the activeProfiles element. This
contains a set of activeProfile elements, which each have a value of a profile id.
Any profile iddefined as an activeProfile will be active, regardless of any
environment settings. If no matching profile is found, nothing will happen. For
example, if env-test is an activeProfile, a profile in a pom.xml (or profile.xml with
a corresponding id will be active. If no such profile is found, then execution will
continue as normal.
48
Lab:
Note: This lab requires the Nexus server to be up and running on the local host
with port 8081
<distributionManagement>
<snapshotRepository>
<id>nexus-snapshots</id>
<url>http://localhost:8081/nexus/content/repositories/snap
shots</url>
</snapshotRepository>
</distributionManagement>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.1</version>
<executions>
<execution>
<id>default-deploy</id>
49
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<configuration>
<serverId>nexus</serverId>
<nexusUrl>http://localhost:8081/nexus/</nexusUrl>
<skipStaging>true</skipStaging>
</configuration>
</plugin>
<servers>
<server>
<id>nexus</id>
50
<username>deployment</username>
<password>password_for_the_deployment_user</password>
</server>
</servers>
Now run below command to deploy the project artifacts to nexus repository:
Maven 2.x and 3.3.x use Plexus logging API with basic Maven implementation
writing to stdout.
We have reached the decision that SLF4J is the best option for a logging API: SLF4J
has reached a certain level of ubiquity and while SLF4J may not be perfect, it's the
de facto standard and it's pointless to try and remake another one. There are
many implementations to choose from, including Logback and Log4j2. All the hard
work has been done. All the bridges and funnels for other systems function well,
which allows others to use whatever logging implementation they like in their
components, while still being able to have integrated logging.
The standard Maven distribution, from Maven 3.1.0 onward, uses the SLF4J
API for logging combined with the SLF4J Simple implementation. Future versions
may use a more advanced implementation, but we chose to start simple.
Looking at the distribution you will see the following layout where
the simplelogger.properties, slf4j-api-x.y.z-jar and slf4j-simple-
x.y.z.jar specifically relates to the SLF4J implementation:
51
1. apache-maven-3.x.y
2. ├── LICENSE.txt
3. ├── NOTICE.txt
4. ├── README.txt
5. ├── bin
6. │ └── ...
7. ├── boot
8. │ └── ...
9. ├── conf
13.└── lib
You can configure a proxy to use for some or all of your HTTP requests with
Maven. The username and password are only required if your proxy requires
basic authentication (note that later releases may support storing your
passwords in a secured keystore - in the meantime, please ensure your
52
settings.xml file (usually ${user.home}/.m2/settings.xml) is secured with
permissions appropriate for your operating system).
The nonProxyHosts setting accepts wild cards, and each host not to proxy is
separated by the | character. This matches the JDK configuration equivalent.
Lab:
<settings>
<proxies>
<proxy>
<id>example-proxy</id>
<active>true</active>
<protocol>http</protocol>
<host>proxy.example.com</host>
<port>8080</port>
<username>proxyuser</username>
<password>somepassword</password>
<nonProxyHosts>www.google.com|*.example.com</nonProxyHosts>
</proxy>
</proxies>
53
.
</settings>
• You want to replace a particular repository with your own internal repository
which you have greater control over.
• You want to run a repository manager to provide a local cache to a mirror and
need to use its URL instead.
54
<settings>
...
<mirrors>
<mirror>
<id>UK</id>
<name>UK Central</name>
<url>http://uk.maven.org/maven2</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
...
</settings>
Note that there can be at most one mirror for a given repository. In other words,
you cannot map a single repository to a group of mirrors that all define the
same <mirrorOf> value. Maven will not aggregate the mirrors, but simply picks
the first match. If you want to provide a combined view of several repositories,
use a repository manager instead.
The settings descriptor documentation can be found on the Maven Local Settings
Model Website.
55
A list of known mirrors is available in the Repository Metadata. These mirrors
may not have the same contents and we don't support them in any way.
You can force Maven to use a single repository by having it mirror all repository
requests. The repository must contain all of the desired artifacts, or be able to
proxy the requests to other repositories. This setting is most useful when using
an internal company repository with the Maven Repository Manager to proxy
external requests.
<settings>
...
<mirrors>
<mirror>
<id>internal-repository</id>
<url>http://repo.mycompany.com/proxy</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
...
56
</settings>
A single mirror can handle multiple repositories when used in conjunction with a
repository manager.
• external:* matches all repositories except those using localhost or file based
When you use the advanced syntax and configure multiple mirrors, keep in mind
that their declaration order matters. When Maven looks for a mirror of some
repository, it first checks for a mirror whose <mirrorOf> exactly matches the
repository identifier. If no direct match is found, Maven picks the first mirror
declaration that matches according to the rules above (if any). Hence, you may
57
influence the match order by changing the order of the definitions in
the settings.xml
Examples:
• * = everything
<settings>
...
<mirrors>
<mirror>
<id>internal-repository</id>
<url>http://repo.mycompany.com/proxy</url>
<mirrorOf>external:*,!foo</mirrorOf>
</mirror>
<mirror>
<id>foo-repository</id>
<name>Foo</name>
58
<url>http://repo.mycompany.com/foo</url>
<mirrorOf>foo</mirrorOf>
</mirror>
</mirrors>
...
</settings>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.1</version>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
59
The maven-deploy-plugin is a viable option to handle the task of deploying to
artifacts of a project to Nexus, but it was not built to take full advantage of what
Nexus has to offer. Because of that fact, Sonatype built a Nexus specific plugin –
the nexus-staging-maven-plugin – that is actually designed to take full advantage
of the more advanced functionality that Nexus has to offer – functionality such as
staging.
The only reason to use the maven-deploy-plugin is to keep open the option of
using an alternative to Nexus in the future – for example,
an Artifactory repository. However, unlike other components that may actually
change throughout the lifecycle of a project, the Maven Repository Manager is
highly unlikely to change, so that flexibility is not required.
So, the first step in using another deployment plugin in the deploy phase is to
disable the existing, default mapping:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
60
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.5.1</version>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<serverId>nexus</serverId>
<nexusUrl>http://localhost:8081/nexus/</nexusUrl>
<skipStaging>true</skipStaging>
</configuration>
</plugin>
The deploy goal of the plugin is mapped to the deploy phase of the Maven build.
61
Also notice that, as discussed, we do not need staging functionality in a simple
deployment of -SNAPSHOT artifacts to Nexus, so that is fully disabled via
the <skipStaging> element.
Configuring Maven with the credentials of this deployment user, so that it can
interact correctly with Nexus, cannot be done in the pom.xml of the project. This
is because the syntax of the pom doesn’t allow it, not to mention the fact that
the pom may be a public artifact, so not well suited to hold credential
information.
The credentials of the server have to be defined in the global Maven setting.xml:
<servers>
<server>
<id>nexus-snapshots</id>
<username>deployment</username>
<password>the_pass_for_the_deployment_user</password>
</server>
</servers>
62
The server can also be configured to use key based security instead of raw and
plaintext credentials.
Maven Plugins
Maven is—at its heart—a plugin execution framework; all work is done by
plugins. Looking for a specific goal to execute? This page lists the core plugins
and others. There are the build and the reporting plugins:
• Build plugins will be executed during the build and they should be configured
in the <build/> element from the POM.
• Reporting plugins will be executed during the site generation and they should
be configured in the <reporting/> element from the POM. Because the result of
a Reporting plugin is part of the generated site, Reporting plugins should be
both internationalized and localized. You can read more about the localization
of our plugins and how you can help.
63
Plugin Version Description
install 3.0.0-M1 Install the built artifact into the local repository.
ejb 3.0.1 Build an EJB (and optional client) from the current
project.
64
Plugin Version Description
65
Plugin Version Description
antrun 1.8 Run a set of ant tasks from a phase of the build.
66
Plugin Version Description
analysis.
invoker 3.1.0 Run a set of Maven projects and verify the output.
patch 1.2 Use the gnu patch tool to apply patch files to source
code.
plugin 3.6.0 Create a Maven plugin descriptor for any mojos found
in the source tree, to include in the JAR.
release 2.5.3 Release the current project - updating the POM and
tagging in the SCM.
67
Plugin Version Description
Lab:
Let's start using the Maven Clean plugin by performing the following steps:
2. Run the following Maven command in the simple Maven project that we
created in the Creating a simple project with Maven recipe in the
previous section
68
mvn clean
If there are no files/folders to delete, you will not see the similar output:
[INFO]
It uses the Maven Clean plugin for this. The plugin has only one goal,
namely clean, to clean the working directory.
In the case of Maven, the working directory is called target . Maven creates this
directory when a build is done. The clean goal of the plugin attempts to delete
this directory.
69
As clean is a separate lifecycle from the default (build) lifecycle, clean needs
to be explicitly called before the default lifecycle if you need to ensure that the
working directory is removed.
CLEANING AUTOMATICALLY
In the previous example, as we used the default behavior of the plugin and did
not need to make any configurations, we did not need to make any change to the
pom configuration file. However, what if we want to ensure that the clean goal
is run without explicitly calling it?
To do this, we need to define the plugin with some parameters in our pom file:
Lab:
<build>
<plugins>
<plugin>
<artifactId>maven-clean-
plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>auto-clean</id>
<phase>initialize</phase>
<goals>
70
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Though the preceding declaration may look verbose, all we are asking is for
the clean goal to be invoked during the initialize phase of the project. We
are identifying this execution with an id called auto-clean.
mvn package
Even though we did not call the clean phase, the clean goal got invoked
because it was configured in the pom file to run in the initialize phase.
71
SKIPPING THE DELETION OF THE WORKING DIRECTORY
Let us look at the converse of the preceding use case. For some reason, we do not
want the working directory to be deleted, even if clean is run. To do this,
perform the following steps:
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.6</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
mvn clean
C:\projects\apache-maven-cookbook\project-with-clean-
disabled>mvn clean
[INFO]
[INFO]
72
[INFO] Building Project with clean disabled 1.0-
SNAPSHOT
[INFO]
[INFO]
Setting the skip plugin property to true indicates to Maven that the clean goal
must be skipped.
What if your project has an additional folder, say report , besides target , which
is perhaps created by another script, and you want that to be deleted as well? We
use the following steps to do the same:
Lab:
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.6</version>
<configuration>
<filesets>
73
<fileset>
<directory>${basedir}/report</directory>
</fileset>
</filesets>
</configuration>
</plugin>
mvn clean
C:\projects\apache-maven-cookbook\project-with-
clean-additional-folder>mvn clean
[INFO]
[INFO]
[INFO]
74
[INFO]
The report folder is deleted as well. In fact, Maven can be configured to delete
(or not delete) specific folders and files inside that folder as well.
Compilation is an essential task performed by a build tool. Maven uses the Maven
Compiler plugin to do the compilation. The plugin provides several configurations
to make the compilation flexible.
Lab:
2. Run the following Maven command on the simple project that we created in
the Creating a simple project with Maven recipe in the previous section
mvn compile
75
[INFO] Compiling 1 source file to
C:\projects\apache-maven-cookbook\simple-
project\target\classes
Lab:
The compile phase itself essentially runs the compile goal of the Maven
Compiler plugin.
This compiles the Java source files to classes in the target/classes folder.
One question would have struck you. What about the test classes? Why does
the compile phase not compile the test sources?
The answer lies in the way Maven handles the lifecycle and phases of the
lifecycle. Why would you want to compile the test sources unless you want to run
the tests?
mvn test
76
Observe the output as shown in the following screenshot:
As we specified the test phase, Maven ran all phases prior to it, which includes
compiling the test sources using the testCompile goal of the Maven Compiler
plugin.
A best practice of software development is writing automated unit tests for the
code that you develop. Let us now see how to run these tests.
The plugin that does this job is the Maven Surefire plugin.
Lab:
To run unit tests using the Maven Surefire plugin, perform the following steps:
mvn test
77
[INFO] Surefire report directory:
C:\projects\apache-maven-cookbook\simple-
project\target\surefire-reports
---
T E S T S
---
Running com.skaas.sample.AppTest
Results:
The test parameter indicates the invocation of the default lifecycle to Maven.
Maven Lifecycle, Maven runs all the phases up to and including the test phase,
in order.
The test phase itself essentially runs the test goal of the Maven Surefire plugin.
This runs the test classes that are present in the target/test-classes folder.
The test that we have is a test written using the JUnit framework. Not only does
the plugin run the test, it also generates a test report that can be used to analyze
failures as well as test coverage.
78
Check the surefire-reports folder:
While the text file contains the summary report, the XML file has the details of
each of the tests.
USING TESTNG
JUnit is not the only way to write automated unit tests. You could use TestNG
(http://testng.org) or even write your tests without using any framework (by
using Java asserts).
Let us now write a test using TestNG and see what needs to change for it to work.
Refer to the Maven project with TestNG.
Lab:
The only change in the pom file is to replace the junit dependency
with testng :
79
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.8</version>
<scope>test</scope>
</dependency>
mvn test
[INFO]
T E S T S
Running com.skaas.sample.AppTest
Set up run
80
Fast test
Slow test
The same tests work with TestNG and JUnit as TestNG can run JUnit tests.
81
SKIPPING TESTS
There may be situations where you might not want to run the tests; some tests
are possibly broken. This can be done in the following ways:
Lab:
● Configuring the Surefire plugin in the pom file: Configure your Surefire plugin
in the pom.xml file using the following code:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-
plugin</artifactId>
<version>2.17</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
mvn test
82
You will see the similar output:
[INFO]
The skipTests parameter used in the preceding mvn command skips running of
tests, but the test sources still get compiled by the earlier phases/goals. To skip
the compilation of test sources, you can run the following command:
This will completely skip the test compilation and test execution.
The Resources plugin comes into picture to copy project resources to the output
directory. The resources can be for the project to run or for the purpose of
testing.
83
Lab:
Let's start using the Maven Resources plugin by performing the following steps:
2. Run the following command on the simple project that we created earlier:
mvn process-resources
In the earlier project, there are no resources and hence, resources are not copied.
84
You could also explicitly invoke the plugin's goal as follows:
mvn resources:resources
You could also invoke any phase following the process-resources phase,
which will trigger resource processing as well:
mvn compile
There is a separate goal to copy test resources to provide separation of the main
and test resources. Like project resources, the test resource processing can be
invoked in three ways, which are as follows:
mvn process-test-resources
mvn resources:testResources
mvn test
85
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/additional</directory>
</resource>
</resources>
</build>
mvn process-resources
The line Copying 1 resource repeats twice, indicating the copying happening
from two folders.
86
2.3.5 Using Eclipse to Run Maven Goals
If you are using Eclipse to develop your project, it is good to know how to run
some of the plugins we have discussed earlier using the IDE.
Lab:
87
Eclipse provides an option to run various goals from the IDE. Among the ones we
have seen in this section, clean , compile , and test are offered by Eclipse.
There are a few other options as well.
Eclipse also allows the project to be Run As a Java Application in the traditional
way (without using any Maven plugins). Likewise, it allows a JUnit Test to be run
without using Maven.
A typical project requirement is to aggregate the project output along with its
dependencies, modules, and other files into a single distributable archive. An
assembly is a group of files, directories, and dependencies that are assembled
into an archive format and distributed. Maven provides prefabricated assembly
descriptors to build these assemblies. The descriptors handle common
operations, such as packaging a project's artifact, along with the dependencies.
Lab:
1. Open a Maven project for which you want to generate the assembly; in our
case, project-with-assembly .
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
88
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-
dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.skaas.sample.App</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
89
4. Observe the output:
C:\projects\apache-maven-cookbook\project-with-
assembly\target>java -jar project-with-assembly-1.0-
SNAPSHOT-jar-with-dependencies.jar
● We also used the archive configuration to specify the main class of the
project. This is to make the JAR file executable.
● We then specified when the single goal of assembly should be run, namely,
the package phase.
90
When Maven ran, it used the preceding configurations to assemble a JAR with
dependencies in the package phase. We could run this as a normal executable
JAR.
The Assembly plugin can also build an assembly from a multi-module project,
where the modules can be part of the final assembly.
While opening the JAR file, you would have observed that all the dependent JARs
have been unpacked as well.
This is due to the default configuration for the predefined descriptor. Let us see
how to create the same distribution but retain dependant JARs as they are. To do
this, we will now use one Maven JAR plugin, which uses a custom class loader to
load dependant JARs within the parent JAR:
Lab:
1. Open the project for which you want to create an executable with unpackaged
dependant jars ( project-with-one-jar ).
91
<plugin>
<groupId>org.dstovall</groupId>
<artifactId>onejar-maven-plugin</artifactId>
<version>1.4.4</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>one-jar</goal>
</goals>
</execution>
</executions>
</plugin>
3. Add the JAR plugin to specify the main class for the executable JAR:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
92
<mainClass>com.skaas.sample.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
4. Add the following code as the plugin binaries are not in the central Maven
repository:
<pluginRepositories>
<pluginRepository>
<id>onejar-maven-
plugin.googlecode.com</id>
<url>http://onejar-maven-
plugin.googlecode.com/svn/mavenrepo</url>
</pluginRepository>
</pluginRepositories>
mvn package
93
7. Open the created JAR file:
We can see that in contrast to the assembly JAR, the executable JAR is created
without unpacking the libraries (dependencies) involved.
94
● Remote: This is the repository from where the required Maven files get
downloaded.
● Mirrors: These are repository managers, such as Nexus and Artifactory, that
mirror various repositories.
You will have seen Maven downloading a number of files (called poms and jars).
Let us see where they are located in your computer:
● You will notice the .m2 folder and within that, a subfolder called repository
● You will see a number of folders and files that are used by Maven
You may want to change this location for the following reasons:
● You may want to conserve space in the C drive and store these folders and files
in the D drive on Microsoft Windows.
● You may want to take a back up of the contents. Backup software usually
backs up contents in specific folders of the filesystem.
● Your organization may have a policy for all users to store a local repository in
the same folder.
To change the location of the Maven repository, perform the following steps:
2. Add the following contents to the settings.xml file that you just created:
95
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>C:/software/maven</localRepository>
</settings>
Notice the highlighted part of the preceding code. We have changed the location
of the repository contents to C:\software\maven. You can change it to any valid
folder name.
3. Delete the repository subfolder and run the mvn package command again.
You will now notice that the repository folder is not created in the .m2 folder.
Instead, it is created in C:\software\maven.
Maven determines the location of the local repository in the following way:
● If it is not present there, Maven will use the default value for the local
repository, which is the user's .m2 folder
96
Manually installing dependencies that are not available in a repository:
There may be situations where a library, which is not present in any Maven
repository, needs to be used. We have seen one way to use it, that is, specifying it
as a dependency with system scope and explicitly specifying the path to it.
The problem with this approach is that this dependency will not be available if
you need to distribute your project as a library.
Lab:
Use the following steps to manually install the dependencies that aren't available
in a repository:
1. Add the following dependency to the simple project that we created earlier:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>apache-tomcat</artifactId>
<version>8.0.14</version>
<type>tar.gz</type>
</dependency>
The project will fail to compile with the error of a missing dependency
97
2. Now run the following Maven command:
[INFO] Installing
C:\Users\raghu\AppData\Local\Temp\mvninstall8295760271813162
395.pom to C:\software\maven\org\apache\tomcat\apache-
tomcat\8.0.14\apache-tomcat-8.0.14.pom
The install-file goal of the Maven Install plugin allows dependencies to be installed
to the local repository. It takes groupId, artifactId, version, and packaging type as
parameters so that it can place the dependency suitably in the repository as well
as create a simple pom file for it.
This method is not ideal in a project with multiple developers, as each developer
needs to perform this step manually. One way to deal with this is to install this
dependency in a repository manager that is used by the organization. As the
98
developers will be using this repository manager as a mirror, Maven will find the
dependency from the mirror and proceed.
In such a case, we could use the deploy goal of the Maven deploy plugin to install
the artifact to the remote repository.
Some remote repositories have access control. Maven allows access details to be
specified in the server element. It is best to specify this in settings.xml as this file
is specific to each user.
Projects with dependencies that are installed by this method are again not
distributable, as those using them will fail to find the dependencies.
1. Create a repository inside your project by adding the following in your pom
file:
<repository>
<id>in-project-repo</id>
<releases>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<url>file://${project.basedir}/lib</url>
</repository>
99
2. Use the following command to install the dependency to this repository:
What have we achieved? Now, the dependency is packaged along with the source
code in the lib folder of our project and available for distribution. This is
transparent to the user as they do not need to do anything special to access it.
Maven is a great tool, but it has a steep learning curve. Therefore, have Maven:
The Complete Reference in your bookmarks and refer to it frequently.
To learn about Maven's command-line options, run mvn -?. Useful options
include:
-B - runs Maven in batch mode, which is particularly useful when invoking Maven
from a continuous server, such as Bamboo because it avoids Maven's reporting of
downloading progress
100
1. Know the standard Maven plugins
To learn about a specific Maven plugin, browse the plugin's Maven site and
read the details on each of the plugin's goals.
For example, if your code base creates three JAR files, have three Maven
projects. If all three JAR files share common code, use a fourth Maven project
to store the common code. Have the original three projects defined a
dependency on the common code.
The target folder is automatically deleted when you run mvn clean. Therefore,
it's the best place to put all build artifacts, such as Java .class files, JAR files, and
temporary files created during the build process. Maven plugins typically place
the temporary artifacts they create somewhere within the target folder.
101
duplication; without the dependencyManagement section, each child project
has to define its own dependency and duplicate the version, scope, and type of
the dependency. For example, suppose a multi-module Java project makes
extensive use of JUnit for unit testing. To specify the project dependency on
JUnit, the project's parent pom.xml can use a dependencyManagementsection
as follows:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
Note that each child project that uses JUnit must still specify its dependency on
JUnit. However, the version and scope of the dependency should be omitted as
this avoids duplication and ensures that the same dependency is used
throughout the project.
102
6. Dependency in child pom.xml (Version and scope inherited from parent)
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
SNAPSHOT versions take some getting used to, but they provide significant
benefits:
They reduce the usage of Forge resources. For example, they reduce the
amount of disk space used by Nexus.
They reduce the frequency of changes that dependent projects make. For
example, when project A depends on project B and both projects are under
development, project A can declare a dependency on the SNAPSHOT version of
project B. That way, project A doesn't need to change its dependency every
time there is a new build of project B.
Use the Maven Dependency Plugin's analyze goals to help identify issues in
your project's dependency management
The Maven Dependency Plugin has an analyze goal that identifies two types of
dependency issues in a project:
103
Dependencies that are directly used, but are not declared. (The project still
compiles because it gets the dependencies transitively.)
You can configure a project's build to fail if it has any dependency warnings -
refer to the Maven documentation.
[WARNING]
com.avaya.ace.aaft:foundation_services_client_api:jar:6.2.0
-SNAPSHOT:compile
104
To fix the problem, project A should define a direct Maven dependency on
project C.
[WARNING] com.gigaspaces:gs-openspaces:jar:7.1.1-
b4534:compile
To fix the problem, the project should remove the dependency from its POM.
9. Use Maven for dependency management rather than writing custom code for it
For example, if one Maven project depends on a zip file created by another
Maven project, have the second project create a Maven artifact and use a
Maven dependency rather than using a relative path.
10. Use Maven for dependency management rather than using Subversion
externals
105
11. Do not write custom Maven code to copy or unzip files. Use Maven's standard
plugins instead.
12. Don’t use deprecated references like ${artifactId} or ${pom.artifactId}. Use the
new ${project.artifactId} syntax. Note that this syntax follows the XML
document structure, which makes it easy to remember and predict the value
that the reference will result in.
13. Try to avoid using inherited properties. Developers can easily forget that a
certain property is used by a child POM and change the value breaking the
build in an unexpected place. Secondly, it’s quite annoying not to be able to
easily lookup a property without having to find and examine the parent POM.
14. Use the dependency management section of the parent pom to define all
dependency versions, but do not set a scope here so that all dependencies
have scope compile by default.
15. Use properties to define the dependency versions. This way you can get an
overview of all versions being used without having to scroll through multiple
pages of dependency sections.
16. Use the plugin management section of the parent pom to define versions for
*all* plugins that your build uses, even standard maven plugins like maven-
compile-plugin and maven-source-plugin. This way your build will not
suddenly behave differently when a new version of a plugin is released.
17. When using a parent POM that is not located in the directory directly above
the current POM define an empty relativePath element in your parent section.
106
18. Use the dependency plugin to check your project for both unnecessary
dependencies and undeclared-but-used-none-the-less dependencies. The goal
is called ‘analyze’, so run the following command on the console: “mvn
dependency:analyze”
19. Make sure the pom files contain all the repository references needed to
download all dependencies. If you want to use a local repository instead of
downloading directly from the Internet then use the maven settings file to
define mirrors for the individual repositories that are defined in the poms.
20. If you use Nexus, then do not create repository groups containing both hosted
and proxied repositories. This will dramatically reduce the responsiveness
because Nexus will check the remote locations of the proxied repositories
even if a hosted repository contains the requested artifact.