Nuxeo Core Developer Guide

Maven Usage

Updated: October 22, 2018 Page Information Edit on GitHub

Overview and Online Documentation

See http://maven.apache.org/users/index.html.

Maven is a software tool for Java project management and build automation, similar in functionality to the Apache Ant tool coupled to a dependency manager such as Ivy, but Maven is based on different concepts.

Maven uses a construct known as a Project Object Model (POM) to describe the software project being built, its dependencies on other external modules and components, and the build order. It comes with predefined targets for performing certain well defined tasks such as compilation of code and its packaging.

Maven is designed to be network-ready. It dynamically downloads libraries and plugins from one or more repositories. A local cache of downloaded artifacts acts as the primary means of synchronizing the requirements and outputs of projects on a local system.

Online Documentation

http://www.sonatype.com/books/maven-book/reference/

http://maven.apache.org/guides/

http://maven.apache.org/guides/introduction/

http://maven.apache.org/ref/2.1.0/maven-settings/settings.html

Nuxeo Documentation

In the knowledge base: How to debug test run with Maven.

Installing Maven

What is Maven?

Quoting the Wikipedia entry for Maven:

Maven is a software tool for Java programming language project management and automated software build. It is similar in functionality to the Apache Ant tool, but has a simpler build configuration model, based on an XML format. Maven is hosted by the Apache Software Foundation, where it was formerly part of the Jakarta Project.

Maven uses a construct known as a Project Object Model (POM) to describe the software project being built, its dependencies on other external modules and components, and the build order. It comes with predefined targets for performing certain well defined tasks such as compilation of code and its packaging.

A key feature of Maven is that it is network-ready. The core engine can dynamically download plugins from a repository, the same repository that provides access to many versions of different Open Source Java projects, from Apache and other organizations and developers. This repository and its reorganized successor the Maven 2 repository are the de facto distribution mechanism for Java applications. Maven provides built in support not just for retrieving files from this repository, but to upload artifacts at the end of the build. A local cache of downloaded artifacts acts as the primary means of synchronizing the output of projects on a local system.

Nuxeo is fully "Maven managed".

Nuxeo holds a Maven repository here: http://maven.nuxeo.org/.

Installing Maven

Since Nuxeo 5.9.2, Maven 3.1.1+ is required (3.3+ recommended). Maven 2.2.1 is required up to Nuxeo 5.9.1.

You should install Maven on your development box by downloading the latest archive from http://maven.apache.org/download.html and then extract the archive into /opt (for instance).

As usual, you have to put the mvn executable into the path of your environment, include the bin/ sub-directory in your PATH by adding in your .bashrc(or .profile.zprofile, ...) something like:

export M2_HOME=/opt/apache-maven-3.3.3/
export PATH=/opt/apache-maven-3.3.3/bin:$PATH

In a new shell you can then test:

$ mvn --version
Apache Maven 3.3.3 (...)
Maven home: /opt/apache-maven-3.3.3
Java version: 1.8.0_51, vendor: Oracle Corporation

Maven relies on JAVA_HOME rather than PATH for Java.

Configure Repositories

Nuxeo uses Sonatype Nexus OSS for storing its artifacts at https://maven.nuxeo.org/.

You will find there a lot of "group", "hosted" and "proxy" repositories:

There are three solutions for enabling your Maven build to use Nuxeo repositories:

  • add public and public-snapshot repositories in your POM:
<repositories>
  <repository>
    <id>public</id>
    <url>http://maven.nuxeo.org/nexus/content/groups/public</url>
    <releases>
      <enabled>true</enabled>
    </releases>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
  <repository>
    <id>public-snapshot</id>
    <url>http://maven.nuxeo.org/nexus/content/groups/public-snapshot</url>
    <releases>
      <enabled>false</enabled>
    </releases>
    <snapshots>
      <updatePolicy>always</updatePolicy>
      <enabled>true</enabled>
    </snapshots>
  </repository>
</repositories>

  • add public and public-snapshot repositories in your $M2_REPO/settings.xml: The same sentence must be put inside a profile.
<?xml version="1.0"?>
<settings>
  <profiles>
    <profile>
      <id>Nuxeo</id>
      <repositories>
        <repository>
          <id>public</id>
          <url>http://maven.nuxeo.org/nexus/content/groups/public</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>false</enabled>
          </snapshots>
        </repository>
        <repository>
          <id>public-snapshot</id>
          <url>http://maven.nuxeo.org/nexus/content/groups/public-snapshot</url>
          <releases>
            <enabled>false</enabled>
          </releases>
          <snapshots>
            <updatePolicy>always</updatePolicy>
            <enabled>true</enabled>
          </snapshots>
        </repository>
      </repositories>
    </profile>
  </profiles>
  <activeProfiles>
    <activeProfile>Nuxeo</activeProfile>
  </activeProfiles>
</settings>

  • define mirrors in your $M2_REPO/settings.xml: If your company is hosting its own Maven repository manager with proxies to Nuxeo repositories, you can define that mirroring in your Maven settings.
<?xml version="1.0"?>
<settings>
  <!-- Bypass POM information to avoid remote repositories and use internal ones instead -->
  <mirrors>
    <mirror>
      <id>public-releases-mirror</id>
      <name>public releases mirror</name>
      <url>http://your.company.com/.../proxy-to-nuxeo-release</url>
      <mirrorOf>public</mirrorOf>
    </mirror>
    <mirror>
      <id>public-snapshots-mirror</id>
      <name>public snapshots mirror</name>
      <url>http://your.company.com/.../proxy-to-nuxeo-snapshot</url>
      <mirrorOf>public-snapshot</mirrorOf>
    </mirror>
  </mirrors>
</settings>

If you are behind an HTTP proxy, see http://maven.apache.org/settings.html#Proxies.

Configure Hotfix Repositories

Nuxeo customers have access to two additional repositories where the "hotfix" artifacts are deployed: hotfix-releases and hotfix-snapshots. Contact the Nuxeo support to get an account.

Add the repositories in your POM:

<repositories>
 <!-- Hotfix Repositories For Nuxeo Customers Only -->
  <repository>
    <id>hotfix-releases</id>
    <url>https://maven.nuxeo.org/nexus/content/repositories/hotfix-releases</url>
    <releases>
      <enabled>true</enabled>
    </releases>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
  <repository>
    <id>hotfix-snapshots</id>
    <url>https://maven.nuxeo.org/nexus/content/repositories/hotfix-snapshots</url>
    <releases>
      <enabled>false</enabled>
    </releases>
    <snapshots>
      <updatePolicy>always</updatePolicy>
      <enabled>true</enabled>
    </snapshots>
  </repository>
</repositories>

Set your credentials in your $M2_REPO/settings.xml:

  <!-- In case of redirection error, for instance, from nuxeo.org to nuxeo-us instead of nuxeo-eu -->
  <!--
  <mirrors>
    <mirror>
      <id>hotfix-releases-eu</id>
      <name>hotfix releases EU</name>
      <url>https://maven-eu.nuxeo.org/nexus/content/repositories/hotfix-releases</url>
      <mirrorOf>hotfix-releases</mirrorOf>
    </mirror>
    <mirror>
      <id>hotfix-snapshots-eu</id>
      <name>hotfix snapshots EU</name>
      <url>https://maven-eu.nuxeo.org/nexus/content/repositories/hotfix-snapshots</url>
      <mirrorOf>hotfix-snapshots</mirrorOf>
    </mirror>
  </mirrors>
  -->

  <servers>
    <server>
      <id>hotfix-releases</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <id>hotfix-snapshots</id>
      <username>****</username>
      <password>****</password>
    </server>
  </servers>

 

Configuring Plugin Repositories

Maven plugins are considered as special artifacts: their repositories must also be configured. Follow exactly the same instructions as above replacing repositories/repository sections with pluginRepositories/pluginRepository.

Configure Eclipse with Maven

The maven-eclipse-plugin provides a goal (eclipse:configure-workspace) for automatically configuring Eclipse with Maven but it's easy to manually configure: in Eclipse, go to Preferences/Java/Build Path/Classpath Variables, click New, name M2_REPO and browse to your local Maven repository (usually ~/.m2/repository).

Generate a New Project with the Nuxeo-Archetype-Start Archetype

This is currently deprecated

The goal of the nuxeo-archetype-start template is to setup a development environment to work on a Nuxeo Platform plugin.

The default code provides: a Maven layout for sources, tests and dependencies, a Ant target for deployment. It also customizes the web application a little bit.

To create a project named my-project in the com.company.sandbox.myproject package:

mvn org.apache.maven.plugins:maven-archetype-plugin:1.0-alpha-7:create \
-DartifactId=my-project \
-DgroupId=com.company.sandbox.myproject \
-DarchetypeArtifactId=nuxeo-archetype-start \
-DarchetypeGroupId=org.nuxeo.archetypes \
-DarchetypeVersion=5.1.6 \
-DremoteRepositories=http://maven.nuxeo.org/nuxeo-release

You can see that you need to supply six arguments:

  • artifactId : the name of your project, usually with '-' to separate the words if there are many.
  • groupId : the domain name of your project. Usually it is the package parent name of your classes, you should use '.' to separate the words ('-' is not supported here).
  • archetypeArtifactId : the Maven archetype artifact id. To generate a new project, Nuxeo provides you with nuxeo-archetype-start
  • archetypeGroupId : unique for all Nuxeo Maven archetypes : org.nuxeo.archetypes
  • archetypeVersion : the version of the archetype which is equivalent to the version of Nuxeo Platform without the _GA_ or _RC_ part. (5.1.6, 5.1.5 ...).
  • remoteRepositories : the repository location to download the archetype.

Decrease Build Time

No Clean

Maven is able to decrease build time but it relies on target content for this. If you don't "clean" the target directory, only out of date modules are rebuilt. Issue is not cleaning the target directory may lead to strange results because of deprecated uncleaned resources.

The incremental-build-plugin provides a solution for this: checking the target content during the Maven validation phase, it deletes the target directory when it's needed.

This plugin is automatically activated when using Nuxeo corporate POM (org.nuxeo:nuxeo-ecm since version 5.4.0-SNAPSHOT).

You don't need to "clean" anymore while building sources.

Note that when using for instance mvn install, even if a module is not rebuilt, its target content is installed; which is a good thing for SNAPSHOT consistency but leads to a consequent build time even if there's nothing to recompile.

Multi-Thread

Maven 3 enables multi-threaded builds. Of course, it requires the activated plugins being thread-safe, as well as the Unit Tests code. See below for -T option details.

No SNAPSHOT Updates and Offline Mode

See related -o and -nsu options below.

Skip Tests

Skip all tests execution with -DskipTests(Unit Tests and Integration Tests).

Skip only the Integration Tests execution with -DskipITs.

Skip only the Unit Tests execution with -Dskip.surefire.tests=true.

Avoid use of -Dmaven.test.skip=true which also skips the tests compilation.

In the Maven Surefire Test Framework:

In the Nuxeo Test Framework:

  • There is no difference about the Unit Tests except that they can act like Integration Tests: "unit testing" multiple modules at once, at a higher level than usual per-module Unit Tests. That advanced behavior may disturb analysis tools (like Cobertura, Jacoco, SonarQube...) and require a specific configuration to get relevant coverage reports (see org.nuxeo:nuxeo-ecm POM).
  • Integration Tests designate Functional and Performance Tests.
  • Selenium, FunkLoad and other custom Integration Tests are managed by the ant-assembly-maven-plugin which mimics maven-failsafe-plugin behaviors, honoring its main properties and output format.
  • WebDriver Integration Tests are managed by the maven-failsafe-plugin; the ant-assembly-maven-plugin acts only during pre-integration-test and post-integration-test phases for the environment set up and tear down.

 

Basic Maven Options

Non Recursive

-N,--non-recursive                     Do not recurse into sub-projects

Offline Mode

-o,--offline                           Work offline

Activate/Deactivate Profiles

-P,--activate-profiles <arg>           Comma-delimited list of profiles to activate

This can also be used to deactivate a profile by preceding the profile to deactivate with a - (dash).

Force Artifacts Update

-U,--update-snapshots                  Forces a check for updated releases and snapshots on remote repositories

Nuxeo default snapshots update policy is "always", so you need this option only if you changed this policy.

No SNAPSHOT updates

 -nsu,--no-snapshot-updates             Suppress SNAPSHOT updates

 

Advanced Maven Options

Projects list (-pl)

-pl,--projects <arg>                   Build specified reactor projects instead of all projects

For instance, the following will build only modules A and B even if there are others in the modules list of your POM:

mvn install -pl A,B

Useful for building a restricted modules list.

Also Make (Upstream Dependencies)

-am,--also-make                        If project list is specified, also build projects required by the list

For instance, the following will build all modules required by A and B, then A and B:

mvn install -pl A,B -am

Useful for building only modules that may impact the restricted modules list you are currently working on.

Also Make (Downstream) Dependencies

-amd,--also-make-dependents            If project list is specified, also build projects that depend on projects on the list

For instance, the following will build A and B, then all modules depending on A or B:

mvn install -pl A,B -amd

Useful to check collateral impacts of changes you've done on a restricted modules list.

Resume From

-rf,--resume-from <arg>                Resume reactor from specified project

Maven will skip modules until it reaches the named module. Useful when your build failed for some reason you've fixed and you don't want to replay useless previous builds.

Multi-Threading

 -T,--threads <arg>                     Thread count, for instance 2.0C where C is core multiplied

Errors and Debug

-e,--errors                            Produce execution error messages
-X,--debug                             Produce execution debug output

 

There are two possible errors raised by the Maven plugins: MojoExecutionException and MojoFailureException. A MojoExecutionException is a fatal exception, stopping the build; whereas a MojoFailureException is more like a warning for which you can customize the build result with the following options. Those options are common to all plugins and must be preferably used to plugins' specific options such as -Dmaven.test.haltafterfailure=true or -Dmaven.test.failure.ignore=true.

-fae,--fail-at-end                     Only fail the build afterwards; allow all non-impacted builds to continue

Regarding the tests, with -fae option, Maven will remember the failing tests and skip their downstream (dependent) modules but only report the failures after the whole build. This is more or less equivalent to the maven.test.haltafterfailure Surefire option.

 

-ff,--fail-fast                        Stop at first failure in reactorized builds
-fn,--fail-never                       NEVER fail the build, regardless of project result

Tips and Workarounds

Fix maven-eclipse-plugin Warning about Workspace's vm (Mac OS X Only)

Because of indefinitely unresolved issue MECLIPSE-668, Mac OS X users get the following warning message when running mvn eclipse:eclipse command: [WARNING] Workspace defines a VM that does not contain a valid jre/lib/rt.jar: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

Apply that workaround:

cd /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
sudo mkdir -p jre/lib
sudo ln -s /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar jre/lib/rt.jar

Common settings.xml File for Nuxeo Core Developers

settings.xml

<settings>
  <!--
  <mirrors>
    <mirror>
      <id>public-releases-mirror</id>
      <name>public releases mirror</name>
      <url>http://mavenin.nuxeo.com/nexus/content/groups/public</url>
      <mirrorOf>public</mirrorOf>
    </mirror>
    <mirror>
      <id>public-snapshots-mirror</id>
      <name>public snapshots mirror</name>
      <url>http://mavenin.nuxeo.com/nexus/content/groups/public-snapshot</url>
      <mirrorOf>public-snapshot</mirrorOf>
    </mirror>
  </mirrors>
  -->
  <servers>
    <!-- See http://maven.apache.org/guides/mini/guide-encryption.html for password encryption -->
    <server>
      <id>nightly-staging</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <id>public-releases</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <!-- private releases -->
      <id>releases</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <id>vendor-releases</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <id>public-snapshots</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <!-- internal snapshots -->
      <id>daily-snapshots</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <!-- private snapshots -->
      <id>snapshots</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <id>vendor-snapshots</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <id>nuxeo-studio</id>
      <username>****</username>
      <password>****</password>
    </server>
    <server>
      <id>maven-website</id>
      <username>mavenweb</username>
    </server>
  </servers>
  <profiles>
    <profile>
      <id>NXP</id>
      <repositories>
        <repository>
          <id>public</id>
          <url>http://maven.nuxeo.org/nexus/content/groups/public</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>false</enabled>
          </snapshots>
        </repository>
        <repository>
          <id>public-snapshot</id>
          <url>http://maven.nuxeo.org/nexus/content/groups/public-snapshot</url>
          <releases>
            <enabled>false</enabled>
          </releases>
          <snapshots>
            <updatePolicy>always</updatePolicy>
            <enabled>true</enabled>
          </snapshots>
        </repository>
      </repositories>
      <properties>
        <connect.password>****</connect.password>
      </properties>
    </profile>
    <profile>
      <id>qa</id>
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
      <repositories>
        <repository>
          <id>internal-releases</id>
          <url>http://mavenin.nuxeo.com/nexus/content/groups/internal-releases</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>false</enabled>
          </snapshots>
        </repository>
        <repository>
          <id>internal-snapshots</id>
          <url>http://mavenin.nuxeo.com/nexus/content/groups/internal-snapshots</url>
          <releases>
            <enabled>false</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
          </snapshots>
        </repository>
      </repositories>
      <properties>
        <connect.password>****</connect.password>
      </properties>
    </profile>
    <profile>
      <!-- No SNAPSHOT Updates (useless Since Maven 3.1.1 which provides a -nsu option) -->
      <id>qansu</id>
      <repositories>
        <repository>
          <id>internal-snapshots</id>
          <url>http://mavenin.nuxeo.com/nexus/content/groups/internal-snapshots</url>
          <releases>
            <enabled>false</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
            <updatePolicy>never</updatePolicy>
          </snapshots>
        </repository>
        <repository>
          <id>public-snapshot</id>
          <url>http://maven.nuxeo.org/public-snapshot</url>
          <releases>
            <enabled>false</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
            <updatePolicy>never</updatePolicy>
          </snapshots>
        </repository>
      </repositories>
    </profile>
    <profile>
      <id>qapriv</id>
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
      <repositories>
        <repository>
          <id>private-releases</id>
          <url>https://mavenpriv.nuxeo.com/nexus/content/groups/private-releases</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>false</enabled>
          </snapshots>
        </repository>
        <repository>
          <id>private-snapshots</id>
          <url>https://mavenpriv.nuxeo.com/nexus/content/groups/private-snapshots</url>
          <releases>
            <enabled>false</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
          </snapshots>
        </repository>
      </repositories>
    </profile>
    <profile>
      <id>release</id>
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
      <properties>
        <keystore.path>****</keystore.path>
        <keystore.password>****</keystore.password>
        <keystore.alias>****</keystore.alias>
        <connect.password>****</connect.password>
      </properties>
    </profile>
    (...)
  </profiles>
  <activeProfiles>
    <activeProfile>qa</activeProfile>
  </activeProfiles>
  <pluginGroups>
    <pluginGroup>org.nuxeo.build</pluginGroup>
    <pluginGroup>org.jvnet.hudson.tools</pluginGroup>
    <pluginGroup>org.jenkins-ci.tools</pluginGroup>
    <pluginGroup>com.versioneye</pluginGroup>
  </pluginGroups>
</settings>

Build and Use a Test-Jar with Maven

If you want to expose your test class to be reused in other test classes of projects you can add the following code at the end of your pom.xml:

pom.xml

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>test-jar</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

If you don't want to include the manifest file of your bundle to use the one defined in your test resources folder, you can add the following code in the execution tag of your pom:

<configuration>
   <archive>
      <manifestFile>src/test/resources/META-INF/MANIFEST.MF</manifestFile>
   </archive>
</configuration>

The aim is to not build a test jar containing the manifest of the main bundle, because the manifest will probably defined a "Nuxeo-Component" item pointing to a service xml file that you don't embedded in the test jar. This will cause the following error when you will deploy your test bundle with maven:

Unknown component 'OSGI-INF/your-service.xml' referenced by bundle 'your.bundle.id'

Then, to use this test package in your code you must define a dependency like this:

<dependency>
      <groupId>the.group.id</groupId>
      <artifactId>the-artifact-name</artifactId>
      <type>test-jar</type>
      <scope>test</scope>
</dependency>
2 months ago manonlumeau NXDOC-1650 fix about integrating changes, add mention on multiple attempts
2 years ago Ronan Daniellou 48 | eplaces 'maven.in' by 'mavenin
3 years ago Manon Lumeau 47
3 years ago Manon Lumeau 46
3 years ago Julien Carsique 45 | Hotfix customer account
3 years ago Solen Guitter 44 | Make TOC shorter
3 years ago Julien Carsique 43
3 years ago Julien Carsique 42
3 years ago Julien Carsique 41
3 years ago Julien Carsique 40 | hotfix
3 years ago Julien Carsique 39
3 years ago Julien Carsique 38 | Maven 3.3.3 recommended
4 years ago Solen Guitter 37
4 years ago Solen Guitter 36
4 years ago Julien Carsique 35 | password encryption in settings.xml
4 years ago Julien Carsique 34
4 years ago Julien Carsique 33
4 years ago Julien Carsique 32 | Skip Tests
4 years ago Thomas Roger 31
4 years ago Manon Lumeau 30
4 years ago Maxime Hilaire 29
4 years ago Maxime Hilaire 28
4 years ago Maxime Hilaire 27 | Add build test jar part
5 years ago Solen Guitter 26
5 years ago Julien Carsique 25
5 years ago Julien Carsique 24
5 years ago Julien Carsique 23 | Maven 3 update (and new options); sample settings.xml for Nuxeo Core dev
5 years ago Solen Guitter 22 | Added TOC
5 years ago Julien Carsique 21
6 years ago Julien Carsique 20
6 years ago Julien Carsique 19
6 years ago Julien Carsique 17
6 years ago Julien Carsique 18 | Migrated to Confluence 4.0
7 years ago Julien Carsique 16 | workaround for MECLIPSE-668
8 years ago Julien Carsique 15 | fix url display
8 years ago Julien Carsique 14
8 years ago Julien Carsique 13
8 years ago Julien Carsique 12 | add information about Maven repositories managed by Nuxeo
8 years ago Florent Guillaume 11
8 years ago Julien Carsique 10
8 years ago Stéfane Fermigier 9
8 years ago Stéfane Fermigier 8
8 years ago Stéfane Fermigier 7
8 years ago Julien Carsique 6
8 years ago Julien Carsique 5
8 years ago Julien Carsique 4
8 years ago Julien Carsique 3
8 years ago Julien Carsique 2
8 years ago Julien Carsique 1
History: Created by Julien Carsique

We'd love to hear your thoughts!

All fields required