Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

Best Practices

Save for later
  • 1740 min read
  • 2014-12-23 00:00:00

article-image

This article by Prabath Siriwardena, author of Mastering Apache Maven 3 focuses on best practices associated with all the core concepts. The following best practices are essential ingredients in creating a successful/productive build environment. The following criteria will help you evaluate the efficiency of your Maven project if you are mostly dealing with a large-scale, multi-module project:

  • The time it takes for a developer to get started with a new project and add it to the build system
  • The effort it requires to upgrade a version of a dependency across all the project modules
  • The time it takes to build the complete project with a fresh local Maven repository
  • The time it takes to do a complete offline build
  • The time it takes to update the versions of Maven artifacts produced by the project, for example, from 1.0.0-SNAPSHOT to 1.0.0
  • The effort it requires for a completely new developer to understand what your Maven build does
  • The effort it requires to introduce a new Maven repository
  • The time it takes to execute unit tests and integration tests

(For more resources related to this topic, see here.)


Dependency management


In the following example, you will notice that the dependency versions are added to each and every dependency defined in the application POM file:

<dependencies>
  <dependency>
    <groupId>com.nimbusds</groupId>
    <artifactId>nimbus-jose-jwt</artifactId>
    <version>2.26</version>
  </dependency>
  <dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.2</version>
  </dependency>
</dependencies>


Imagine that you have a set of application POM files in a multi-module Maven project that has the same set of dependencies. If you have duplicated the artifact version with each and every dependency, then to upgrade to the latest dependency, you need to update all the POM files, which could easily lead to a mess.

Not just that, if you have different versions of the same dependency used in different modules of the same project, then it's going to be a debugging nightmare in case of an issue.

With proper dependency management, we can overcome both the previous issues. If it's a multi-module Maven project, you need to introduce the  dependencyManagement configuration element in the parent POM so that it will be inherited by all the other child modules:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.nimbusds</groupId>
      <artifactId>nimbus-jose-jwt</artifactId>
      <version>2.26</version>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.2</version>
    </dependency>
  </dependencies>
</dependencyManagement>


Once you define dependencies under the dependencyManagement section as shown in the previous code, you only need to refer a dependency by its groupId and artifactId tags. The version tag is picked from the appropriate the dependencyManagement section:

<dependencies>
  <dependency>
    <groupId>com.nimbusds</groupId>
    <artifactId>nimbus-jose-jwt</artifactId>
  <dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
  </dependency>
</dependencies>


With the previous code snippet, if you want to upgrade or downgrade a dependency, you only need to change the version of the dependency under the dependencyManagement section.

The same principle applies to plugins as well. If you have a set of plugins, which are used across multiple modules, you should define them under the pluginManagement section of the parent module. In this way, you can downgrade or upgrade plugin versions seamlessly just by changing the pluginManagement section of the parent POM, as shown in the following code:

<pluginManagement>
  <plugins>
    <plugin>
      <artifactId>maven-resources-plugin</artifactId>
      <version>2.4.2</version>
    </plugin>
    <plugin>
      <artifactId>maven-site-plugin</artifactId>
      <version>2.0-beta-6</version>
    </plugin>
    <plugin>
      <artifactId>maven-source-plugin</artifactId>
      <version>2.0.4</version>
    </plugin>
    <plugin>
      <artifactId>maven-surefire-plugin</artifactId>
      <version>2.13</version
    </plugin
  </plugins>
</pluginManagement>


Once you define the plugins in the pluginManagement section, as shown in the previous code, you only need to refer a plugin from its groupId (optional) and the artifactId tags. The version tag is picked from the appropriate pluginManagement section:

<plugins>
  <plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <executions>……</executions>
  </plugin>
  <plugin>
    <artifactId>maven-site-plugin</artifactId>
    <executions>……</executions>
  </plugin>
  <plugin>
    <artifactId>maven-source-plugin</artifactId>
    <executions>……</executions>
  </plugin>
  <plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <executions>……</executions>
  </plugin>
</plugins>

Defining a parent module


In most of the multi-module Maven projects, there are many things that are shared across multiple modules. Dependency versions, plugins versions, properties, and repositories are only some of them. It is a common as well as a best practice to create a separate module called parent, and in its POM file, define everything in common. The packaging type of this POM file is pom. The artifact generated by the pom packaging type is itself a POM file.

The following are a few examples:


Not all the projects follow this approach. Some just keep the parent POM file under the root directory (not under the parent module). The following are a couple of examples:


Both approaches deliver the same results. However, the first one is much preferred. With the first approach, the parent POM file only defines the shared resources across different Maven modules in the project, while there is another POM file at the root of the project, which defines all the modules to be included in the project build. With the second approach, you define all the shared resources as well as all the modules to be included in the project build in the same POM file, which is under the project's root directory. The first approach is better than the second one, based on the separation of concerns principle.

POM properties


There are six types of properties that you can use within a Maven application POM file:

  • Built-in properties
  • Project properties
  • Local settings
  • Environment variables
  • Java system properties
  • Custom properties


It is always recommended that you use properties, instead of hardcoding values in application POM files. Let''s look at a few examples.

Let's take the application POM file inside the Apache Axis2 distribution module, available at http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/distribution/pom.xml. This defines all the artifacts created in the Axis2 project that need to be included in the final distribution. All the artifacts share the same groupId tag as well as the version tag of the distribution module. This is a common scenario in most of the multi-module Maven projects.

Most of the modules (if not all) share the same groupId tag and the version tag:

<dependencies>
  <dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-java2wsdl</artifactId>
    <version>${project.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-kernel</artifactId>
    <version>${project.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-adb</artifactId>
    <version>${project.version}</version>
  </dependency>
</dependencies>


In the previous configuration, instead of duplicating the version element, Axis2 uses the project property ${project.version}. When Maven finds this project property, it reads the value from the project POM version element. If the project POM file does not have a version element, then Maven will try to read it from the immediate parent POM file. The benefit here is, when you upgrade your project version some day, you only need to upgrade the version element of the distribution POM file (or its parent).

The previous configuration is not perfect; it can be further improved in the following manner:

<dependencies>
  <dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>axis2-java2wsdl</artifactId>
    <version>${project.version}</version>
  </dependency>
  <dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>axis2-kernel</artifactId>
    <version>${project.version}</version>
  </dependency>
  <dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>axis2-adb</artifactId>
    <version>${project.version}</version>
  </dependency>
</dependencies>


Here, we also replace the hardcoded value of groupId in all the dependencies with the project property ${project.groupid}. When Maven finds this project property, it reads the value from the project POM groupId element. If the project POM file does not have a groupId element, then Maven will try to read it from the immediate parent POM file.

The following lists out some of the Maven built-in properties and project properties:

  • project.version: This refers to the value of the version element of the project POM file
  • project.groupId: This refers to the value of the groupId element of the project POM file
  • project.artifactId: This refers to the value of the artifactId element of the project POM file
  • project.name: This refers to the value of the name element of the project POM file
  • project.description: This refers to the value of the description element of the project POM file
  • project.baseUri: This refers to the path of the project's base directory


The following is an example that shows the usage of this project property. Here, we have a system dependency that needs to be referred from a filesystem path:

<dependency>
  <groupId>org.apache.axis2.wso2</groupId>
  <artifactId>axis2</artifactId>
  <version>1.6.0.wso2v2</version>
  <scope>system</scope>
  <systemPath>${project.basedir}/lib/axis2-1.6.jar</systemPath>
</dependency>


In addition to the project properties, you can also read properties from the USER_HOME/.m2/settings.xml file. For example, if you want to read the path to the local Maven repository, you can use the ${settings.localRepository} property. In the same way, with the same pattern, you can read any of the configuration elements that are defined in the settings.xml file.

The environment variables defined in the system can be read using the env prefix, within an application POM file. The ${env.M2_HOME} property will return the path to the Maven home, while ${env.java_home} returns the path to the Java home directory. These properties will be quite useful within certain Maven plugins.

Maven also lets you define your own set of custom properties. Custom properties are mostly used when defining dependency versions.

You should not scatter custom properties all over the place. The ideal place to define them is the parent POM file in a multi-module Maven project, which will then be inherited by all the other child modules.

If you look at the parent POM file of the WSO2 Carbon project, you will find a large set of custom properties, which are defined in https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/parent/pom.xml. The following lists out some of them:

<properties>
  <rampart.version>1.6.1-wso2v10</rampart.version>
  <rampart.mar.version>1.6.1-wso2v10</rampart.mar.version>
  <rampart.osgi.version>1.6.1.wso2v10</rampart.osgi.version>
</properties>


When you add a dependency to the Rampart JAR, you do not need to specify the version there. Just refer it by the ${rampart.version} property name. Also, keep in mind that all the custom defined properties are inherited and can be overridden in any child POM file:

<dependency>
  <groupId>org.apache.rampart.wso2</groupId>
  <artifactId>rampart-core</artifactId>
  <version>${rampart.version}</version>
</dependency>

Avoiding repetitive groupId  and version tags and inherit from the parent POM


In a multi-module Maven project, most of the modules (if not all) share the same groupId and version elements. In this case, you can avoid adding the version and groupId elements to your application POM file. These will be automatically inherited from the corresponding parent POM.

If you look at axis2-kernel (which is a module of the Apache Axis2 project), you will find that no groupId or version is defined at http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/kernel/pom.xml. Maven reads them from the parent POM file:

<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-parent</artifactId>
    <version>1.7.0-SNAPSHOT</version>
    <relativePath>../parent/pom.xml</relativePath>
  </parent>
  <artifactId>axis2-kernel</artifactId>
  <name>Apache Axis2 - Kernel</name>
</project>

Following naming conventions


When defining coordinates for your Maven project, you must always follow the naming conventions.

The value of the groupId element should follow the same naming convention you use in Java package names. It has to be a domain name (the reverse of the domain name) that you own, or at least your project is developed under.

The following lists out some of the naming conventions related to groupId:

  • The name of the groupId element has to be in lower case.
  • Use the reverse of a domain name that can be used to uniquely identify your project. This will also help to avoid collisions between artifacts produced by different projects.
  • Avoid using digits or special characters (that is, org.wso2.carbon.identity-core).
  • Do not try to group two words into a single word by camel casing (that is, org.wso2.carbon.identityCore).
  • Make sure that all the subprojects developed under different teams in the same company finally inherit from the same groupId element and extend the name of the parent groupId element rather than defining their own.


Let's go through some examples. You will notice that all the open source projects developed under Apache Software Foundation (ASF) use the same parent groupId (org.apache) and define their own groupId elements, which extend from the parent:

  • The Apache Axis2 project uses org.apache.axis2, which inherits from the org.apache parent groupId
  • The Apache Synapse project uses org.apache.synapse, which inherits from the org.apache parent groupId
  • The Apache ServiceMix project uses org.apache.servicemix, which inherits from the org.apache parent groupId
  • The WSO2 Carbon project uses org.wso2.carbon


Apart from the groupId element, you should also follow the naming conventions while defining artifactIds.

The following lists out some of the naming conventions related to artifactId:

  • The name of the artifactId has to be in lower case.
  • Avoid duplicating the value of groupId inside the artifactId element. If you find a need to start your artifactId with the value of groupId element and add something to the end, then you need to revisit the structure of your project. You might need to add more module groups.
  • Avoid using special characters (that is, #, $, &, %, and so on).
  • Do not try to group two words into a single word by camel casing (that is, identityCore).


Following naming conventions for version is also equally important. The version of a given Maven artifact can be divided into four categories:

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
<Major version>.<Minor version>.<Incremental version>-<Build   number or the qualifier>


The major version reflects the introduction of a new major feature. A change in the major version of a given artifact can also mean that the new changes are not necessarily backward compatible with the previously released artifact. The minor version reflects an introduction of a new feature to the previously released version, in a backward compatible manner. The incremental version reflects a bug-fixed release of the artifact. The build number can be the revision number from the source code repository.

This versioning convention is not just for Maven artifacts. Apple did a major release of its iOS mobile operating system in September 2014: iOS 8.0.0. Soon after the release, they discovered a critical bug in it that had an impact on cellular network connectivity and TouchID on iPhone. Then, they released iOS 8.0.1 as a patch release to fix the issues.

Let's go through some of the examples:

Maven profiles


When do we need Maven profiles and why is it a best practice?

Think about a large-scale multi-module Maven project. One of the best examples I am aware of is the WSO2 Carbon project. If you look at the application POM file available at http://svn.wso2.org/repos/wso2/tags/carbon/3.2.3/components/pom.xml, you will notice that there are more than hundred modules. Also, if you go deeper into each module, you will further notice that there are more modules within them: http://svn.wso2.org/repos/wso2/tags/carbon/3.2.3/components/identity/pom.xml. As a developer of the WSO2 Carbon project, you do not need to build all these modules. In this specific example, different groups of the modules are later aggregated into build multiple products. However, a given product does not need to build all the modules defined in the parent POM file. If you are a developer in a product team, you only need to worry about building the set of modules related to your product; if not, it's an utter waste of productive time. Maven profiles help you to do this.

With Maven profiles, you can activate a subset of configurations defined in your application POM file, based on some criteria.

If we take the same example we took previously, you will find that multiple profiles are defined under the <profiles> element: http://svn.wso2.org/repos/wso2/tags/carbon/3.2.3/components/pom.xml. Each profile element defines the set of modules that is relevant to it and identified by a unique ID. Also for each module, you need to define a criterion to activate it, under the activation element. By setting the value of the activeByDefault element to true, we make sure that the corresponding profile will get activated when no other profile is picked. In this particular example, if we just execute mvn clean install, the profile with the default ID will get executed. Keep in mind that the magic here does not lie on the name of the profile ID, default, but on the value of the activeByDefault element, which is set to true for the default profile. The value of the id element can be of any name:

<profiles>
  <profile>
    <id>product-esb</id>
    <activation>
      <property>
        <name>product</name>
        <value>esb</value>
      </property>
    </activation>
    <modules></modules>
  </profile>
  <profile>
    <id>product-greg</id>
    <activation>
      <property>
        <name>product</name>
        <value>greg</value>
      </property>
    </activation>
    <modules></modules>
  </profile>
  <profile>
    <id>product-is</id>
    <activation>
      <property>
        <name>product</name>
        <value>is</value>
      </property>
    </activation
    <modules></modules>
  </profile>
  <profile>
    <id>default</id>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
    <modules></modules>
  </profile>
</profiles>


If I am a member of the WSO2 Identity Server (IS) team, then I will execute the build in the following manner:

$ mvn clean install –Dproduct=is


Here, we pass the system property product with the value is. If you look at the activation criteria for all the profiles, all are based on the system property: product. If the value of the system property is is, then Maven will pick the build profile corresponding to the Identity Server:

<activation>
  <property>
    <name>product</name>
    <value>is</value>
  </property>
</activation>


You also can define an activation criterion to execute a profile, in the absence of a property. For example, the following configuration shows how to activate a profile if the product property is missing:

<activation>
  <property>
    <name>!product</name>
  </property>
</activation>


The profile activation criteria can be based on a system property, the JDK version, or an operating system parameter where you run the build.

The following sample configuration shows how to activate a build profile for JDK 1.6:

<activation>
  <jdk>1.6</jdk>
</activation>


The following sample configuration shows how to activate a build profile based on operating system parameters:

<activation>
  <os>
    <name>mac os x</name>
    <family>mac</family>
    <arch>x86_64</arch>
   <version>10.8.5</version>
  </os>
</activation>


The following sample configuration shows how to activate a build profile based on the presence or absence of a file:

<activation>
  <file>
    <exists>……</exists>
    <missing>……</missing>
  </file>
</activation>


In addition to the activation configuration, you can also execute a Maven profile just by its ID, which is defined within the id element. In this case, you need a prefix; use the profile ID with –P, as shown in the following command:

$ mvn clean install -Pproduct-is

Think twice before you write your own plugin


Maven is all about plugins! There is a plugin out there for almost everything. If you find a need to write a plugin, spend some time researching on the Web to see whether you can find something similar—the chances are very high. You can also find a list of available Maven plugins at http://maven.apache.org/plugins.

The Maven release plugin


Releasing a project requires a lot of repetitive tasks. The objective of the Maven release plugin is to automate them. The release plugin defines the following eight goals, which are executed in two stages, preparing the release and performing the release:

  • release:clean: This goal cleans up after a release preparation
  • release:prepare: This goal prepares for a release in Software Configuration Management (SCM)
  • release:prepare-with-pom: This goal prepares for a release in SCM and generates release POMs by fully resolving the dependencies
  • release:rollback: This goal rolls back to a previous release
  • release:perform: This goal performs a release from SCM
  • release:stage: This goal performs a release from SCM into a staging folder/repository
  • release:branch: This goal creates a branch of the current project with all versions updated
  • release:update-versions: This goal updates versions in the POM(s)


The preparation stage will complete the following tasks with the release:prepare goal:

  • Verify that all the changes in the source code are committed.
  • Make sure that there are no SNAPSHOT dependencies. During the project development phase, we use SNAPSHOT dependencies but at the time of the release, all dependencies should be changed to a released version.
  • Change the version of project POM files from SNAPSHOT to a concrete version number.
  • Change the SCM information in the project POM to include the final destination of the tag.
  • Execute all the tests against the modified POM files.
  • Commit the modified POM files to the SCM and tag the code with the version name.
  • Change the version of POM files in the trunk to a SNAPSHOT version and then commit the modified POM files to the trunk.


Finally, the release will be performed with the release:perform goal. This will check the code from the release tag in the SCM and run a set of predefined goals: site, deploy-site.

The maven-release-plugin is not defined in the super POM and should be explicitly defined in your project POM file. The releaseProfiles configuration element defines the profiles to be released and the goals configuration element defines the plugin goals to be executed during the release:perform goal. In the following configuration, the deploy goal of the maven-deploy-plugin and the single goal of the maven-assembly-plugin will get executed:

<plugin>
  <artifactId>maven-release-plugin</artifactId>
  <version>2.5</version>
  <configuration>
    <releaseProfiles>release</releaseProfiles>
    <goals>deploy assembly:single</goals>
  </configuration>
</plugin>

More details about the Maven release plugin are available at http://maven.apache.org/maven-release/maven-release-plugin/.

The Maven enforcer plugin


The Maven enforcer plugin lets you control or enforce constraints in your build environment. These could be the Maven version, Java version, operating system parameters, and even user-defined rules.

The plugin defines two goals: enforce and displayInfo. The enforcer:enforce goal will execute all the defined rules against all the modules in a multi-module Maven project, while enforcer:displayInfo will display the project compliance details with respect to the standard rule set.

The maven-enforcer-plugin is not defined in the super POM and should be explicitly defined in your project POM file:

<plugins>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>1.3.1</version>
    <executions>
      <execution>
        <id>enforce-versions</id>
        <goals>
          <goal>enforce</goal>
        </goals>
        <configuration>
          <rules>
            <requireMavenVersion>
              <version>3.2.1</version>
            </requireMavenVersion>
            <requireJavaVersion>
              <version>1.6</version>
            </requireJavaVersion>
            <requireOS>
              <family>mac</family>
            </requireOS>
          </rules>
        </configuration>
      </execution>
    </executions>
  </plugin>
</plugins>


The previous plugin configuration enforces the Maven version to be 3.2.1, the Java version to be 1.6, and the operating system to be in the Mac family.

The Apache Axis2 project uses the enforcer plugin to make sure that no application POM file defines Maven repositories. All the artifacts required by Axis2 are expected to be in the Maven central repository. The following configuration element is extracted from http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/parent/pom.xml. Here, it bans all the repositories and plugin repositories, except snapshot repositories:

<plugin>
  <artifactId>maven-enforcer-plugin</artifactId>
  <version>1.1</version>
  <executions>
    <execution>
      <phase>validate</phase>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <requireNoRepositories>
            <banRepositories>true</banRepositories>
            <banPluginRepositories>true</banPluginRepositories>
            <allowSnapshotRepositories>true</allowSnapshotRepositories>
            <allowSnapshotPluginRepositories>true</allowSnapshotPluginRepositories>
          </requireNoRepositories>
        </rules>
      </configuration>
    </execution>
  </executions>
</plugin>

In addition to the standard rule set ships with the enforcer plugin, you can also define your own rules. More details about how to write custom rules are available at http://maven.apache.org/enforcer/enforcer-api/writing-a-custom-rule.html.

Avoid using un-versioned plugins


If you have associated a plugin with your application POM, without a version, then Maven will download the corresponding maven-metadata.xml file and store it locally. Only the latest released version of the plugin will be downloaded and used in the project. This can easily create certain uncertainties. Your project might work fine with the current version of a plugin, but later if there is a new release of the same plugin, your Maven project will start to use the latest one automatically. This can result in unpredictable behaviors and lead to a debugging mess.

It is always recommended that you specify the plugin version along with the plugin configuration. You can enforce this as a rule, with the Maven enforcer plugin, as shown in the following code:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-enforcer-plugin</artifactId>
  <version>1.3.1</version>
  <executions>
    <execution>
      <id>enforce-plugin-versions</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <requirePluginVersions>
            <message>………… <message>
            <banLatest>true</banLatest>
            <banRelease>true</banRelease>
            <banSnapshots>true</banSnapshots>
            <phases>clean,deploy,site</phases>
            <additionalPlugins>
              <additionalPlugin>
                org.apache.maven.plugins:maven-eclipse-plugin
              </additionalPlugin>
              <additionalPlugin>
                org.apache.maven.plugins:maven-reactor-plugin
              </additionalPlugin>
            </additionalPlugins>
            <unCheckedPluginList>
              org.apache.maven.plugins:maven-enforcer-plugin,org.apache.maven.plugins:maven-idea-plugin
            </unCheckedPluginList>
          </requirePluginVersions>
        </rules>
      </configuration>
    </execution>
  </executions>
</plugin>


The following points explain each of the key configuration elements defined in the previous code:

  • message: Use this to define an optional message to the user if the rule execution fails.
  • banLatest: Use this to restrict the use of LATEST as the  version for any plugin.
  • banRelease: Use this to restrict the use of RELEASE as the version for any plugin.
  • banSnapshots: Use this to restrict the use of SNAPSHOT plugins.
  • banTimestamps: Use this to restrict the use of SNAPSHOT plugins with the timestamp version.
  • phases: This is a comma-separated list of phases that should be used to find lifecycle plugin bindings. The default value is clean,deploy,site.
  • additionalPlugins: This is a list of additional plugins to enforce to have versions. These plugins might not be defined in application POM files, but are used anyway, such as help and eclipse. The plugins should be specified in the groupId:artifactId form.
  • unCheckedPluginList: This is a comma-separated list of plugins to skip version checking.

You can read more details about the requirePluginVersions rule at http://maven.apache.org/enforcer/enforcer-rules/requirePluginVersions.html.

Using exclusive and inclusive routes


When Maven asks for an artifact from a Nexus proxy repository, Nexus knows where to look at exactly. For example, say we have a proxy repository that runs at http://localhost:8081/nexus/content/repositories/central/, which internally points to the remote repository running at https://repo1.maven.org/maven2/. As there is one-to-one mapping between the proxy repository and the corresponding remote repository, Nexus can route the requests without much trouble. However, if Maven looks for an artifact via a Nexus group repository, then Nexus has to iterate through all the repositories in that group repository to find the exact artifact. There can be cases where we have even more than 20 repositories in a single group repository, which can easily bring delays at the client side. To optimize artifact discovery in group repositories, we need to set correct inclusive/exclusive routing rules.

Avoid having both release and snapshot repositories in the same group repository


With the Nexus repository manager, you can group both the release repositories and snapshot repositories together into a single group repository. This is treated as an extreme malpractice.

Ideally, you should be able to define distinct update policies for release repositories and snapshot repositories.

Summary


In this article, we looked at and highlighted some of the best practices to be followed in a large-scale development project with Maven. It is always recommended to follow best practices, as it will drastically improve developer productivity and will reduce any maintenance nightmares.

Resources for Article:





Further resources on this subject:



Modal Close icon
Modal Close icon