Chapter 5 - Build Profiles | Maven: The Complete Reference

Build Profiles

5.1. What Are They For?

Profiles allow for the ability to customize a particular build for a particular environment; profiles enable portability between different build environments.

What do we mean by different build environments? Two example build environments are production and development. When you are working in a development environment, your system might be configured to read from a development database instance while in production, your system is configured to read from the production database. Maven allows you to define any number of build environments (build profiles) which can override any of the settings in the pom.xml. You could configure your application to read from your local, development instance of a database in your "development" profile, and you can configure it to read from the production database in the "production" profile.

5.1.1. What is Build Portability

A build’s "portability" is a measure of how easy it is to take a particular project and build it in different environments. A build which works without any custom configuration or customization of properties files is more portable than a build which requires a great deal of work to build from scratch. The most portable projects tend to be widely used open source projects like Apache Commons or Apache Velocity which ship with Maven builds which require little or no customization.

Non-Portable Builds

The lack of portability is exactly what all build tools are made to prevent - however, any tool can be configured to be non-portable (even Maven). A non-portable project is buildable only under a specific set of circumstances and criteria (e.g., your local machine). Unless you are working by yourself and you have no plans on ever deploying your application to another machine, it is best to avoid non-portability entirely.

Environment Portability

A build exhibits environment portability if it has a mechanism for customizing behavior and configuration when targeting different environments.

Organizational (In-House) Portability

The center of this level of portability is a project’s requirement that only a select few may access internal resources such as source control or an internally-maintained Maven repository.

Wide (Universal) Portability

Anyone may download a widely portable project’s source, compile, and install it without customizing a build for a specific environment.

5.1.2. Selecting an Appropriate Level of Portability

Clearly, you’ll want to avoid creating the worst-case scenario: the non-portable build. You may have had the misfortune to work or study at an organization that had critical applications with non-portable builds.

On the opposite end of the portability spectrum are widely portable builds.

5.2. Portability through Maven Profiles

A profile in Maven is an alternative set of configuration values which set or override default values. Using a profile, you can customize a build for different environments.

<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>
</project>
<profiles>
    <profile>
        <id>production</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <debug>false</debug>
                        <optimize>true</optimize>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

To execute mvn install under the production profile, you need to pass the -Pproduction argument on the command-line.

5.2.1. Overriding a Project Object Model

A Maven profile can override almost everything that you would have in a pom.xml. The following XML document shows all of the elements, a profile is allowed to override.

Elements Allowed in a Profile.

<project>
    <profiles>
        <profile>
            <build>
                <defaultGoal>...</defaultGoal>
                <finalName>...</finalName>
                <resources>...</resources>
                <testResources>...</testResources>
                <plugins>...</plugins>
            </build>
            <reporting>...</reporting>
            <modules>...</modules>
            <dependencies>...</dependencies>
            <dependencyManagement>...</dependencyManagement>
            <distributionManagement>...</distributionManagement>
            <repositories>...</repositories>
            <pluginRepositories>...</pluginRepositories>
            <properties>...</properties>
        </profile>
    </profiles>
</project>

5.3. Profile Activation

In the previous section, we showed you how to create a profile that overrides default behavior for a specific target environment. What happens when you need to provide customizations based on variables like operating systems or JDK version? Maven provides a way to "activate" a profile for different environmental parameters, this is called profile activation.

Dynamic Inclusion of Submodules Using Profile Activation.

5.4. Listing Active Profiles

Maven profiles can be defined in either pom.xml, profiles.xml, ~/.m2/settings.xml, or ${M2_HOME}/conf/settings.xml. To make it easier to keep track of which profiles are available, and where they have been defined, the Maven Help plugin defines a goal, active-profiles, which lists all the active profiles and where they have been defined. You can run the active-profiles goal, as follows:

$ mvn help:active-profiles
Active Profiles for Project 'My Project':

The following profiles are active:

- my-settings-profile (source: settings.xml)
- my-external-profile (source: profiles.xml)
- my-internal-profile (source: pom.xml)

5.5. Tips and Tricks

Profiles can encourage build portability. If your build needs subtle customizations to work on different platforms or if you need your build to produce different results for different target platforms, project profiles increase build portability.

5.5.1. Common Environments

One of the core motivations for Maven project profiles was to provide for environment-specific configuration settings.

Project Profile Activated by setting environment.type to dev.

<project>
    ...
    <profiles>
        <profile>
            <id>development</id>
            <activation>
                <activeByDefault>true</activeByDefault>
                <property>
                    <name>environment.type</name>
                    <value>dev</value>
                </property>
            </activation>
            <properties>
                <database.driverClassName>com.mysql.jdbc.Driver</database.driverClassName>
                <database.url>
                    jdbc:mysql://localhost:3306/app_dev
                </database.url>
                <database.user>development_user</database.user>
                <database.password>development_password</database.password>
            </properties>
        </profile>
        <profile>
            <id>production</id>
            <activation>
                <property>
                    <name>environment.type</name>
                    <value>prod</value>
                </property>
            </activation>
            <properties>
                <database.driverClassName>com.mysql.jdbc.Driver</database.driverClassName>
                <database.url>jdbc:mysql://master01:3306,slave01:3306/app_prod</database.url>
                <database.user>prod_user</database.user>
            </properties>
        </profile>
    </profiles>
</project>

5.6. Summary

When used judiciously, profiles can make it very easy to customize a build for different platforms. If something in your build needs to define a platform-specific path for something like an application server, you can put these configuration points in a profile which is activated by an operating system parameter. If you have a project which needs to produce different artifacts for different environments, you can customize the build behavior for different environments and platforms via profile-specific plugin behavior. Using profiles, builds can become portable, there is no need to rewrite your build logic to support a new environment, just override the configuration that needs to change and share the configuration points which can be shared.