Using a Custom Maven Settings File

Last Updated: 08 December 2014

java maven

Table of Contents

A Maven settings.xml file defines values that configure Maven execution in various ways. Most commonly, it is used to define a local repository location, alternate remote repository servers, and authentication information for private repositories. In this article you’ll learn how to add a custom setting file to a Java application deployed on Heroku.

If you already have a Java application, you may use it for this example. Otherwise, create a simple application from the Getting Started with Java on Heroku article.

Creating a custom settings file

When a file named settings.xml is present in the root directory of an application, Heroku’s Java Support will automatically use it to configure Maven at compile time.

To demonstrate this, add a settings.xml file to the root directory of your Java project and put the following code in it.

<?xml version="1.0" encoding="UTF-8"?>
<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">
  <profiles>
    <profile>
      <id>jboss-public</id>
      <repositories>
        <repository>
          <id>jboss-public-repository</id>
          <name>JBoss Public Maven Repository Group</name>
          <url>http://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
      </repositories>
    </profile>
  </profiles>

  <activeProfiles>
    <activeProfile>jboss-public</activeProfile>
  </activeProfiles>
</settings>

This tells Maven to search the repository hosted at http://repository.jboss.org/ when resolving dependencies for your application. The repository must be addressed with HTTP or HTTPS. If you require a file:// address, then see the Unmanaged Dependencies article.

We can test the settings locally by adding the -s option to any Maven task. But first, we’ll need to add a new dependency to the project. The jboss.web.servlet-api library is a good example because it’s only available on the JBoss repository. Add the follow element to your project’s pom.xml:

<dependency>
  <groupId>jboss.web</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.1.0.GA</version>
</dependency>

Now run the following command and Maven will download the artifact.

$ mvn -s settings.xml dependency:list
[INFO] Scanning for projects...
...
Downloading: http://repository.jboss.org/nexus/content/groups/public/jboss/web/servlet-api/2.1.0.GA/servlet-api-2.1.0.GA.pom
Downloaded: http://repository.jboss.org/nexus/content/groups/public/jboss/web/servlet-api/2.1.0.GA/servlet-api-2.1.0.GA.pom (195 B at 0.2 KB/sec)
Downloading: http://repository.jboss.org/nexus/content/groups/public/jboss/web/servlet-api/2.1.0.GA/servlet-api-2.1.0.GA.jar
Downloaded: http://repository.jboss.org/nexus/content/groups/public/jboss/web/servlet-api/2.1.0.GA/servlet-api-2.1.0.GA.jar (84 KB at 90.8 KB/sec)

If we had not used the custom settings file, the build would have failed with Maven producing an error like this:

Downloading: http://repo.maven.apache.org/maven2/jboss/web/servlet-api/2.1.0.GA/servlet-api-2.1.0.GA.pom
[WARNING] The POM for jboss.web:servlet-api:jar:2.1.0.GA is missing, no dependency information available
Downloading: http://repo.maven.apache.org/maven2/jboss/web/servlet-api/2.1.0.GA/servlet-api-2.1.0.GA.jar
...
[ERROR] Failed to execute goal on project helloworld: Could not resolve dependencies for project com.example:helloworld:jar:1.0-SNAPSHOT: Could not find artifact jboss.web:servlet-api:jar:2.1.0.GA in central (http://repo.maven.apache.org/maven2) -> [Help 1]

Now add the settings.xml and the pom.xml changes to your Git repository and deploy to Heroku like so:

$ git add pom.xml settings.xml
$ git commit -m "adding jboss servlet-api dependency"
$ git push heroku master

As Maven runs on the dyno, we see the same output we saw locally. This works because Heroku detects the settings.xml file in the root directory, and adds the -s option to the Maven command. Next, we’ll discuss how to customize this location.

Defining the MAVEN_SETTINGS_PATH config variable

If you do not want the settings.xml file in the root directory or if you intend to frequently change between different setting configurations, you may prefer to put a settings file in a custom location. Heroku provides this capability with the MAVEN_SETTINGS_PATH config variable.

We can demonstrate this feature by moving the existing settings.xml into a support/ directory and renaming it like so:

$ mkdir -p support
$ git mv settings.xml support/jboss-settings.xml

Now we tell Heroku where the settings file is located by defining MAVEN_SETTINGS_PATH relative to the root directory.

$ heroku config:set MAVEN_SETTINGS_PATH=support/jboss-settings.xml

Before testing the change, we increment the version of servlet-api – forcing Maven to download it again. Change the dependency in the pom.xml to version 2.1.1.GA. It should look like this:

<dependency>
  <groupId>jboss.web</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.1.1.GA</version>
</dependency>

Now commit the changes to Git, and redeploy to Heroku like so:

$ git commit -am "moved settings file and incremented servlet-api version"
$ git push heroku master

Once again, Maven will download the dependency from the JBoss repository. This provides a bit of flexibility, but sometimes a custom location in your project is not enough. You may want to keep the file out of your code base altogether.

Defining the MAVEN_SETTINGS_URL config variable

When the MAVEN_SETTINGS_URL config variable is defined, Heroku will download the file at the given location and use it to configure Maven. Before demonstrating this, we must unset the variable we defined in the previous example because it will take precedence if both variables are set:

$ heroku config:unset MAVEN_SETTINGS_PATH

Now we can use a settings.xml from a publicly available source such as the Torquebox Application Server code-base. Set the config variable like this:

$ heroku config:set MAVEN_SETTINGS_URL="https://raw.githubusercontent.com/torquebox/torquebox/master/support/settings.xml"

As before, increment the servlet-api version to 2.1.2.GA, add the pom.xml to the Git repo, commit the changes and redeploy to Heroku. Maven will download the new artifact from the JBoss repository as it did earlier.

The JBoss repository is convenient because it is public – it does not require a password to access. But not all repositories are quite so open.

Using password protected repositories

Some artifact repositories require a username and password to access. Many times, the repository is a private server hosting internal artifacts. When this is the case, credentials for accessing the repository must be provided in the settings.xml, which can be a problem if the file is checked into a Git repository.

Fortunately, Maven settings files can detect environment variables. Any token in the form ${env.ENV_VAR} (where ENV_VAR is the name of a variable) will resolve to the value of the associated environment variable. Thus we can define the password for a private Maven repo as a Heroku config variable like this:

$ heroku config:set MAVEN_REPO_PASSWORD="deployment123"

Then we can use the variable in our settings.xml file by creating a <server> element that matches the <id> of the <repository> element in the <activeProfile>.

<servers>
  <server>
    <id>my-private-repo</id>
    <username>deployment</username>
    <password>${env.MAVEN_REPO_PASSWORD}</password>
  </server>
</servers>

In order to demonstrate this, you will need a private Maven repository. You can create a repository by downloading Sonatype Nexus and following the instructions for securing a repository. Or you may use a hosted version of JFrog Artifactory.

In either case a private repository can be used to publish internal artifacts and include them in your Heroku applications.

For more information on customizing Maven with a settings file, please see the Maven Settings Reference from Apache.org.