Fork me on GitHub

Development documentation (62-SNAPSHOT)

1. Introduction

The BasePOM project aims to make using Apache Maven as a build tool painless. It provides a set of well known plugins for Apache Maven with an opinionated base configuration and a number of configuration options. It is aiming at Java projects but can easily be extended for other languages that are supported by Apache Maven.

It provides base configurations for unified, organization-wide build setups and supports simple project setups and complex Multi Module project use cases.

BasePOM and its private predecessors have been in use in many companies and open-source projects since 2010.

Core features of BasePOM:

  • Opinionated configuration. BasePOM Parent POMs configure Maven Plugins with reasonable defaults

  • Property based customization. BasePOM Parent POMs expose a number of properties that can be customized in Child POMs or from the command line

  • Profile activation. BasePOM Parent POMs contain a number of profiles that activate under specific conditions and customize build steps or activate specific plugins

  • Policy modifications. Any aspect of a BasePOM Parent POM can be customized through Policy POMs

2. Features

BasePOM provides opinionated configuration for the following plugins:

Most of the plugins are configured with reasonable defaults and might not need to be changed.

BasePOM provides:

  • defaults for build lifecycle setup and phases

  • defaults for unit and integration test execution

  • defaults for code quality checks and static code analysis

  • locked versions for auxiliary tool libraries

  • locked versions for Maven plugins

As the BasePOMs stack on top of each other, some features are only available in minimal and oss or just oss. This document applies to all the BasePOMs (foundation, minimal and oss) unless otherwise noted.

2.1. BasePOM Maven Plugins

The BasePOM project maintains a number of Apache Maven plugins that are useful outside the BasePOM project as well:

  • dependency-versions-check - verifies that the resolved versions of project dependencies are mutually compatible to each other

  • duplicate-finder - Finds and flags duplicate and conflicting classes and resources on the java classpath

  • property-helper - generate and manipulate properties during the build process

  • inline - inlines dependencies into a main artifact by rewriting classes and resources

  • repack - repacks code and its dependencies into a single archive for applications and services

  • dependency-management - validates that the versions in dependency management and plugin management match the resolved versions

  • dependency-scope - ensures that tests scoped dependencies do not override dependencies in compile scope

3. Overview

The Apache Maven documentation is vast, very disjointed and spread across many micro-documentation sites, often outdated and generally hard to understand. As a result, Apache Maven projects often "grow" out of a home-made set of plugins which got copied from some other project and then augmented by looking at StackOverflow. Maven builds become hard to understand and often undermaintained.

Even though there have been a number of attempts to improve the documentation situation, getting a Maven build going is often dreaded by developers.

None of that is a fundamental Maven problem. Setting up Maven is much easier than setting up build tools that require programming or scripting. And POM inheritance allow centralized setup of almost all aspects of a build.

3.1. Requirements

  • Java 11 is the minimal version for building. It is highly recommended to use the latest LTS version (Java 17) to execute the build process. Each of those Java versions can build project artifacts that are compatible with JDK version 7 or later.

  • Maven 3.6.0 is the minimal version for building. It is recommended to use Apache Maven 3.8.4 or later. BasePOM will stay compatible with the 3.6.0 version of Maven as long as this constraint does not stop innovating.

3.2. Releases and compatibility

BasePOM uses single digit versioning for releases. Every release is a major version and while there is an effort to keep releases backwards compatible, it is only an effort not goal. Any change in a BasePOM release is listed in the CHANGES file on GitHub.

Build systems are generally stable and there should be no need to upgrade the BasePOM version unless there are compatibility issues with the current version, features from a newer version needed or known security problems.

3.3. License

All BasePOM code is released under the Apache Software License Version 2.0.

4. Glossary

Single Module Project

A Maven project that contains only a single POM file in its root directory. This POM file does not contain a <modules> section.

Multi Module Project

A Maven project that is structured into multiple build units. The POM file in the root directory contains a <modules> section and directories with additional POM files.

POM

Project object model. The configuration file read by the Apache Maven build tool to execute build steps for a project. A standard POM file is structured using XML and is named pom.xml.

Child POM

A POM file that contains a <parent> section and inherits configuration from the referenced POM file.

Parent POM

A POM file that is referenced by a child POM.

Root POM

The POM file in the root directory of a Multi Module project.

Base POM

A Parent POM file that defines configuration and policy for many projects.

Policy POM

A POM file that inherits from a Base POM file and configures specific policies e.g. for an organization. A policy POM in turn serves as a Base POM for an organization.

Diagram

5. BasePOM starting points

BasePOM contains the following Parent POMs:

foundation

The foundation POM provides an opinionated base configuration but not any code-specific policies. It sets the Maven plugins up for further configuration in a specific Policy POM. It is intended as starting point when putting together an organization specific Policy POM. Projects will rarely use this directly.

Usage:

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.basepom</groupId>
        <artifactId>basepom-foundation</artifactId>
        <version>62-SNAPSHOT</version>
    </parent>
...
</project>
minimal

This is a bare-bones Policy POM that defines a small set of policies. It can be used directly for projects that do not need a lot of scrutiny. For larger projects, a custom Policy POM should be defined which can be built on top of the minimal BasePOM.

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.basepom</groupId>
        <artifactId>basepom-minimal</artifactId>
        <version>62-SNAPSHOT</version>
    </parent>
...
</project>
oss

A Policy POM for releasing and distributing projects through the Sonatype OSS repository. It can be used as a parent POM for projects that distribute their artifacts through OSS. The plugin uses the Sonatype Nexus staging plugin by default to deploy a project to OSS.

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.basepom</groupId>
        <artifactId>basepom-oss</artifactId>
        <version>62-SNAPSHOT</version>
    </parent>
...
</project>

6. Customizations using Maven properties

BasePOM provides a set of properties that configure the various Maven plugins. The default values have been chosen so that they make sense for most projects.

Each property can be overridden from the command line, a Policy POM or a project specific POM file.

All properties are namespaced using the . separator.

  • All BasePOM specific properties begin with basepom.

  • Properties that define the version of a library or a dependency begin with dep. and end with .version

  • Properties that define the version of a Maven plugin begin with dep.plugin. and end with .version

Project customization overrides these properties in Policy or Project POM files. The following tables contain a customization column that gives some guidance how common these values are modified:

often

This is a default value that works for some projects. It is common for a Project or Policy POM to override it.

sometimes

This is a default value that works for most projects. Project or Policy POMs can override it but most don’t.

rarely

The default value should work for almost every project. Only in very special cases is it overridden by a Project or Policy POM.

policy

This is a value that is often modified as part of a larger, organization-wide policy set of customizations.

profile

This value is often controlled through specific profile activation.

6.1. Setting the JDK version

Basepom supports different JDK versions for running the tool chain, compiling the main and the test sources:

project.build.systemJdk 11 often foundation Minimal JDK version for running the Apache Maven tool chain

project.build.targetJdk

11

often

foundation

Target JDK version. Source code will be compiled to this JDK version.

project.build.testJdk

${project.build.targetJdk}

rarely

foundation

Test JDK version. Test source code will be compiled to this JDK version.

By default, all three values are identical.

6.2. Standard Maven Properties

Property Name Default Value customization defined in function

project.build.sourceEncoding

UTF-8

rarely

foundation

Character encoding for source files.

project.reporting.inputEncoding

UTF-8

rarely

foundation

Character encoding for all files read when generating reports.

project.reporting.outputEncoding

UTF-8

rarely

foundation

Character encoding for all reporting files generated by Maven.

maven.compiler.source

${project.build.targetJdk} (= 11)

rarely

foundation

The source code specification used in this project.

maven.compiler.target

${project.build.targetJdk} (= 11)

rarely

foundation

The target bytecode specification used in this project.

maven.compiler.release

${project.build.targetJdk} (= 11)

rarely

foundation

The release JDK version used in this project.

The maven.compiler.source and maven.compiler.target properties may need to be set to 1.8 explicitly when setting project.build.targetJdk to 8. This is a limitation of some build plugins (most prominently the GMavenPlus plugin). Unless really having to compile to Java 8, the maven.compiler.source, maven.compiler.target and maven.compiler.release properties should not be changed but project.build.targetJdk should be used.

6.3. Global properties

These properties affect multiple plugins. POMs that add new plugins should evaluate these properties if necessary and not define plugin specific properties.

Property Name Default Value customization defined in function

basepom.build.maxheap-mb

1024

sometimes

foundation

Sets the maximum heap in MB for plugins. This value has no qualifier, so it can be used in plugins that do not take a unit in their configuration value.

basepom.build.jvmsize

${basepom.build.maxheap-mb}m (= 1024m)

rarely

foundation

Sets the maximum heap size for plugins that take a qualifier. This value is rarely modified directly, but uses the value set in basepom.build.maxheap-mb.

basepom.site.skip

false

often

foundation

If set to true, supports generating the Maven documentation site.

basepom.maven.version

3.6.0

sometimes

foundation

The minimum version of Apache Maven required.

6.4. Plugin customizations

These properties control settings for specific plugins. Most plugins have an opinionated default configuration with very little need for further customization. Where it is useful, these customizations are exposed as properties that can be changed in a Project or Policy POM.

Properties are usually grouped by prefix.

6.4.1. Compilation control

All properties in this section should be supported by language compilers. By default, BasePOM uses the maven-compiler-plugin for Java.

Property Name Default Value customization defined in function

basepom.compiler.fail-warnings

false

sometimes

foundation

Fail compilations if warnings are present.

basepom.compiler.parameters

true

rarely

foundation

Generate metadata for reflection on parameter names. By default, this is activated.

basepom.compiler.use-incremental-compilation

false

sometimes

foundation

If a language compiler supports incremental compilation, it should use this property for control. The compiler plugin supports this flag.

6.4.2. Artifact installation, deployment and release customization

Besides building, Apache Maven can install the resulting artifacts into the local repository or deploy them to a remote repository. Releasing an artifact is creating a stable, immutable build with a version that does not end in -SNAPSHOT. All steps of the Apache Maven lifecycle can be customized with the following properties:

Property Name Default Value customization defined in function

basepom.at-end

false

sometimes, policy

foundation

Set the default value for installing and deploying artifacts in the build cycle for Multi Module projects. If true, the respective operation is done after all modules have been built, otherwise it is done as part of the module build cycle.

basepom.at-end.install

${basepom.at-end}

rarely, policy

foundation

If true, install artifacts at the end of a Multi Module project build cycle.

basepom.at-end.deploy

${basepom.at-end}

sometimes, policy

foundation

If true, deploy artifacts at the end of a Multi Module project build cycle.

basepom.install.skip

false

rarely

foundation

If true, skip artifact installation.

basepom.deploy.skip

${basepom.install.skip}

rarely

foundation

If true, skip artifact deployment.

basepom.release.profiles

basepom.deploy-release

rarely

oss

Sets the name of one or more release profiles. Multiple release profiles must be comma-separated. By default, the basepom.deploy-release profile is used, which uploads to Sonatype OSS using the Apache deploy plugin. Alternatively, the basepom.oss-release profile can be used which uses the Sonatype Nexus OSS plugin.

basepom.release.push-changes

false

sometimes

foundation

If true, then running the Maven release:prepare goal will push changes directly to the upstream repository. Defaults to false.

basepom.release.tag-name-format

@{project.artifactId}-@{project.version}

often

foundation

Name tag format for the release tag. See the Maven Release Plugin Documentation for details.

basepom.release.preparation-goals

clean install

sometimes

foundation

Defines the goals run by maven when executing release:prepare. If e.g. local install is not desired, use clean verify.

basepom.nexus-staging.skip

true

rarely

oss

If true skips artifact installation.

basepom.nexus-staging.staging-url

https://s01.oss.sonatype.org/

rarely

oss

The staging repository for deploying to Sonatype OSS. Used only with the nexus staging plugin. The deploy plugin uses the standard maven repository settings.

basepom.nexus-staging.release-after-close

false

often

oss

Whether to release right after the deployment ends. The default is false (either run mvn nexus-staging:release or use the Sonatype OSS GUI to deploy).

6.4.3. Javadoc Generation

Javadoc artifacts are created as part of the build lifecycle. While they are optional, some distribution sites (OSS, Maven Central) require the creation of a Javadoc artifact.

Property Name Default Value customization defined in function

basepom.javadoc.skip

true

often, profile

foundation

If true, generate a javadoc artifact as part of the build.

basepom.javadoc.doclint

none

sometimes

foundation

Controls the Javadoc -Xdoclint setting.

basepom.javadoc.exclude-package-names

``

sometimes

foundation

Allows exclusion of package names from javadoc generation. See Maven javadoc plugin documentation for the exact syntax.

basepom.javadoc.show

public

rarely, policy

foundation

Controls the access level included in the javadocs.

basepom.javadoc.legacy-mode

false

often

foundation

Controls whether the javadoc tool uses the classpath or module path when building post-java 8 projects. Unless a project defines module descriptors, legacy mode should be used.

6.4.4. Unit Tests

The Apache Maven surefire plugin is active by default. Any other test plugin should also use these properties.

Property Name Default Value customization defined in function

basepom.test.arguments

``

sometimes, policy

foundation

Allows additional arguments for the argLine plugin configuration parameter when executing unit tests.

basepom.test.skip

${skipTests}

often, profile

foundation

If true, skip all unit tests. The default is the value of the standard Maven skipTests property.

basepom.test.fork-count

0.75C

sometimes, policy

foundation

Controls the number of parallel tests to run. Default is the 3/4 of number of reported CPU cores.

basepom.test.reuse-vm

true

sometimes, policy

foundation

If true, reuse existing VM instances, otherwise start a new instance for each test.

basepom.test.timeout

30

often

foundation

Maximum time in seconds that a unit test can run.

basepom.test.memory

256m

often

foundation

Memory for each forked VM.

basepom.test.groups

``

sometimes

foundation

Test group selection for unit tests.

6.4.5. Integration Tests

Apache Maven supports multiple plugins for integration tests. BasePOM supports the failsafe and the invoker plugin for integration tests.

Property Name Default Value customization defined in function

basepom.it.arguments

``

sometimes, policy

foundation

Allows additional arguments for the argLine plugin configuration parameter when executing integration tests.

basepom.it.skip

${skipITs}

often, profile

foundation

If true, skip all integration tests. The default is the value of the standard Maven skipITs property.

basepom.it.memory

${basepom.test.memory}

sometimes, policy

foundation

Memory allocated for each integration test VM.

basepom.it.fork-count

0.5C

sometimes, policy

foundation

Controls the number of parallel tests to run. Default is 1/2 the number of reported CPU cores.

basepom.it.timeout

30

often, policy

foundation

Maximum time in seconds that an integration test can run.

basepom.it.groups

``

sometimes

foundation

Test group selection for integration tests.

basepom.invoker.folder

src/it

rarely

foundation

Base directory where all integration tests are located.

basepom.failsafe.reuse-vm

false

sometimes, policy

foundation

If true, reuse existing VM instances, otherwise start a new instance for each test.

6.4.6. git version control support

BasePOM uses the git-commit-id-maven-plugin to provide scm information to the build. The main use case to modify its configuration is if the code base does not actually use git.

Property Name Default Value customization defined in function

basepom.git-id.skip

false

sometimes, policy

foundation

If true, skip the plugin.

basepom.git-id.skip-pom-projects

true

sometimes

foundation

If true, skip plugin execution if the current project is a pom project (packages only a POM file)

basepom.git-id.fail-no-git

false

sometimes, policy

foundation

If true, fail if the current build directory does not use git.

basepom.git-id.fail-no-info

true

rarely, policy

foundation

If true, fail if the plugin can not extract build information from the local git repository.

basepom.git-id.use-native

false

rarely

foundation

Use the system installed git binary instead of the pure Java jgit library. This is intended for troubleshooting.

basepom.git-id.run-only-once

false

rarely, policy

foundation

Execute only once for a Multi Module project build. This is almost never the right thing: If the build uses a pom packaged module as its root, then the plugin will not be executed. Also, for builds that use git submodules, the scm information may be different for each directory.

basepom.git-id.date-format

yyyy-MM-dd’T’HH:mm:ssXXX

rarely, policy

foundation

Timestamp format as defined for java.text.SimpleDateFormat. The default format is compatible for the project.build.outputTimestamp property.

basepom.git-id.date-format-timezone

UTC

rarely, policy

foundation

Timezone for the timestamp defined with the basepom.git-id.date-format property. The default timezone is UTC.

6.4.7. Executable support

Property Name Default Value customization defined in function

basepom.executable.flags

sometimes

foundation

command line parameters for the java command when executing.

basepom.executable.name

${project.name}

rarely

foundation

Sets the name of the executable.

basepom.shaded.main-class

(empty)

deprecated

minimal

Defines the main class for a shaded jar (using the basepom.executable profile). This option was ill-named and should be replaced with the basepom.main-class option which works for both shaded and repacked jars.

basepom.main-class

${basepom.shaded.main-class}

often

minimal

Defines the main class for the executable jar when shading or repacking an artifact.

6.5. Setting plugin and dependency versions

Each BasePOM release defines the versions for all Maven plugins and dependent libraries. The values change from release to release and are chosen based on stability and release quality of the various tools.

These versions can be overwritten in Policy POMs, project POMs or the command line.

Property Name defined in comment

dep.plugin.assembly.version

foundation

dep.plugin.build-helper.version

foundation

dep.plugin.checkstyle.version

foundation

dep.plugin.clean.version

foundation

dep.plugin.compiler.version

foundation

dep.plugin.dependency-management.version

foundation

dep.plugin.dependency-scope.version

foundation

dep.plugin.dependency-versions-check.version

foundation

dep.plugin.dependency.version

foundation

dep.plugin.deploy.version

foundation

dep.plugin.duplicate-finder.version

foundation

dep.plugin.enforcer.version

foundation

dep.plugin.failsafe.version

foundation

dep.plugin.git-commit-id.version

foundation

dep.plugin.gpg.version

oss

dep.plugin.install.version

foundation

dep.plugin.invoker.version

foundation

dep.plugin.jacoco.version

foundation

dep.plugin.jar.version

foundation

dep.plugin.javadoc.version

foundation

dep.plugin.jxr.version

oss

dep.plugin.license.version

oss

dep.plugin.nexus-staging.version

oss

dep.plugin.pmd.version

foundation

dep.plugin.project-info-reports.version

oss

dep.plugin.property-helper.version

foundation

dep.plugin.really-executable.version

foundation

dep.plugin.release.version

foundation

dep.plugin.resources.version

foundation

dep.plugin.scm-publish.version

foundation

dep.plugin.scm.version

foundation

dep.plugin.shade.version

foundation

dep.plugin.site.version

foundation

dep.plugin.source.version

foundation

dep.plugin.spotbugs.version

foundation

dep.plugin.surefire.version

foundation

dep.checkstyle.version

foundation

Checkstyle library version, used by the checkstyle plugin

dep.dependency-analyzer.version

foundation

Dependency Analyzer library version, used by the dependency plugin

dep.pmd.version

foundation

PMD library version, used by the PMD plugin

dep.spotbugs.version

foundation

Spotbugs library version, used by the spotbugs plugin

dep.basepom-policy.version

minimal

BasePOM policy jar version

7. Code quality and Build checkers

BasePOM brings a set of preconfigured plugins to check the quality of the code base and ensure that the resulting artifacts are valid. The following plugins are supported:

All checkers are optional. Each checker can fail the build if it detects a problem.

Execution of each checker is controlled by a basepom.check.skip-<name> property. If this is set to true, the checker will not be executed.

Build failure is controlled through a basepom.check.fail-<name> property. If this is set to true, any error detected by the checker will fail the build.

Checker property for enabling/disabling property for build failure enable/disable

Checker groups

all checkers

basepom.check.skip-all

basepom.check.fail-all

basic checkers

basepom.check.skip-basic

basepom.check.fail-basic

extended checkers

basepom.check.skip-extended

basepom.check.fail-extended

Individual checkers

Maven checkstyle

basepom.check.skip-checkstyle

basepom.check.fail-checkstyle

Jacoco

basepom.check.skip-coverage

basepom.check.fail-coverage

Maven Enforcer

basepom.check.skip-enforcer

basepom.check.fail-enforcer

Maven Dependency

basepom.check.skip-dependency

basepom.check.fail-dependency

Dependency Management

basepom.check.skip-dependency-management

basepom.check.fail-dependency-management

Dependency Scope

basepom.check.skip-dependency-scope

basepom.check.fail-dependency-scope

Dependency Version Check

basepom.check.skip-dependency-versions-check

basepom.check.fail-dependency-versions-check

Duplicate Finder

basepom.check.skip-duplicate-finder

basepom.check.fail-duplicate-finder

License

basepom.check.skip-license

basepom.check.fail-license

Maven PMD

basepom.check.skip-pmd

basepom.check.fail-pmd

Spotbugs

basepom.check.skip-spotbugs

basepom.check.fail-spotbugs

Javadoc

basepom.javadoc.skip

basepom.check.fail-javadoc

Javadoc is special, because it generates an artifact but also provides checking ("linting") of the javadoc blocks in the source code. Javadoc generation is often controlled independently of checker runs, so it is not part of the basepom.check.skip- properties. Failing the build however still uses the basepom.check.fail- convention.

7.1. Checker hierarchy

The different checkers are grouped together but can also be individually controlled. By default, the group properties basepom.check.skip|fail-basic and basepom.check.skip|fail-extended inherit the value of the basepom.check.skip|fail-all properties:

<properties>
    <basepom.check.skip-all>false</basepom.check.skip-all>
    <basepom.check.skip-basic>${basepom.check.skip-all}</basepom.check.skip-basic>
    <basepom.check.skip-extended>${basepom.check.skip-all}</basepom.check.skip-extended>

    <basepom.check.fail-all>true</basepom.check.fail-all>
    <basepom.check.fail-basic>${basepom.check.fail-all}</basepom.check.fail-basic>
    <basepom.check.fail-extended>${basepom.check.fail-all}</basepom.check.fail-extended>
</properties>
Diagram

Changing the all property also affects all its children. Parent or Policy POMs can override these properties to attach or detach a checker from a group.

The foundation BasePOM defines the following groups:

  • all which contains all basic and extended checks.

  • basic, which contains enforcer, dependency, duplicate-finder, dependency-management, dependency-scope and dependency-versions-check

  • extended is different for three BasePOM types:

    • for the foundation BasePOM, it contains spotbugs and coverage

    • for the minimal BasePOM, it contains spotbugs, coverage, pmd, and checkstyle

    • for the oss BasePOM, it contains spotbugs, coverage, pmd, checkstyle and license

In the foundation BasePOM, the pmd and checkstyle checkers are deactivated. All other checkers are active. All active checkers will fail the build if an error is detected.

7.2. Checker execution phases

While some checkers rely on class files, others only look at source code or configuration. These checkers can be executed before compilation ("early") or after compilation and test execution ("late").

There are good reasons for either:

  • early execution avoids long compile times and then checkers failing the artifact generation

  • late execution allows the execution of the compilation and test lifecycle phases without having to continuously fix unrelated problems (e.g. dependencies or code style issues).

The following plugins can be configured for early (use validate) or late (use verify) execution. By default, all checkers are run late (in the verify phase).

Checker Property Name

Dependency Version Check

basepom.check.phase-dependency-versions-check

Dependency Management

basepom.check.phase-dependency-management

Dependency Scope

basepom.check.phase-dependency-scope

Maven Dependency

basepom.check.phase-dependency

Maven checkstyle

basepom.check.phase-checkstyle

License

basepom.check.phase-license

7.3. Checker customization

Most checkers are self-contained and need no additional configuration. Others (especially PMD and checkstyle) require extensive policy configuration (see the Creating a PolicyPOM to apply a build policy section).

Property Name Default Value customization defined in function

basepom.check.checkstyle-severity

error

sometimes, policy

foundation

Controls which severity levels are considered a violation. Only violations fail the build. Valid values are info, warning and error

basepom.dependency-management.allow-versions

false

sometimes, policy

foundation

If true, dependencies are allowed to specify versions to override the <dependencyManagement> section

basepom.dependency-management.allow-exclusions

false

sometimes, policy

foundation

If true, dependencies are allowed to contain <exclusions> elements to override the <dependencyManagement> section

basepom.dependency-management.dependencies

false

often, policy

foundation

If true, all project dependencies must be defined in a dependencyManagement section and dependency sections must not contain versions

basepom.dependency-management.plugins

false

often, policy

foundation

If true, all project plugins must be defined in a pluginManagement section and plugin sections must not contain versions

basepom.dvc.direct-only

true

sometimes, policy

foundation

Only report direct dependencies of a project, not all dependencies

basepom.pmd.fail-level

4

sometimes, policy

foundation

Minimum PMD violation level that will fail the build

basepom.license.header

license/basepom-apache-license-header.txt

often, policy

oss

The license header to use. This is a reference to a file or a resource on the plugin classpath

basepom.license.skip-existing

true

sometimes, policy

oss

Keep existing license headers, do not replace them

basepom.gpg.use-agent

true

rarely

oss

Use the GnuPG agent to manage private signing keys

8. Build cycle

BasePOM configures all the Maven plugins as part of the Maven build lifecycle. Being configured is different from execution, though. Plugin execution can be skipped for many reasons, most common is that the plugin configuration has a skip property set.

Plugin Phase execution id goal(s) function

git-commit-id-maven-plugin

validate

basepom.default

revision

fetch SCM revision information

property-helper-maven-plugin

validate

basepom.default

get

create build specific ids

maven-enforcer-plugin

validate

basepom.default

enforce

enforce maven and jdk version

maven-resources-plugin

process-resources

default-resources

resources

prepare main resources

maven-compiler-plugin

compile

default-compile

compile

compile main sources

maven-resources-plugin

process-test-resources

default-testResources

testResources

prepare test resources

maven-compiler-plugin

test-compile

default-testCompile

testCompile

compile test sources

jacoco-maven-plugin

process-test-classes

basepom.default

prepare-agent

prepare test coverage agent

maven-surefire-plugin

test

default-test

test

run unit tests

maven-jar-plugin

package

default-jar

jar

package main artifact

maven-jar-plugin

package

basepom.default

test-jar

package test artifact

maven-javadoc-plugin

package

basepom.default

jar

package javadocs / run javadoc linter

maven-source-plugin

package

basepom.default

jar-no-fork

package main sources

maven-source-plugin

package

basepom.default

test-jar-no-fork

package test sources

maven-dependency-plugin

validate/verify

basepom.default

analyze-only

build checker

maven-dependency-plugin

validate/verify

basepom.default

analyze-duplicate

build checker

maven-dependency-plugin

validate/verify

basepom.default

analyze-dep-mgt

build checker

dependency-versions-check-maven-plugin

validate/verify

basepom.default

check

build checker

dependency-management-maven-plugin

validate/verify

basepom.default

analyze

build checker

dependency-scope-maven-plugin

validate/verify

basepom.default

check

build checker

duplicate-finder-maven-plugin

verify

basepom.default

check

build checker

spotbugs-maven-plugin

verify

basepom.default

check

build checker

maven-pmd-plugin

verify

basepom.default

check

build checker

maven-checkstyle-plugin

validate/verify

basepom.default

check

build checker

maven-install-plugin

install

default-install

install

install artifacts in the local repository

maven-deploy-plugin

deploy

default-deploy

deploy

deploy artifacts to remote repository

8.1. Build profiles

A BasePOM may contain additional profiles that configure plugins or add goals to the lifecycle.

8.1.1. basepom.invoker-integration-testing (foundation)

This profile activates if the build module contains a src/it directory.

Due to a limitation in Apache Maven is the src/it path hardcoded for profile activation. For that reason, changing the basepom.invoker.folder property is rarely done. If integration tests are located in a different directory, this profile will not activate automatically.

This profile adds the following goals to the lifecycle:

Plugin Phase execution id goal(s) function

jacoco-maven-plugin

pre-integration-test

basepom.default-it

prepare-agent-integration

prepare integration test coverage agent

maven-invoker-plugin

integration-test

basepom.invoker-integration-testing.default

install

install integration test prerequisites

maven-invoker-plugin

integration-test

basepom.invoker-integration-testing.default

integration-test

run integration tests

maven-invoker-plugin

integration-test

basepom.invoker-integration-testing.default

verify

verify integration test results

8.1.2. basepom.executable (foundation)

This profile activates if a .build-executable file exists in the current build module. This file only needs to exist, it can be empty.

This profile is experimental. While it is possible to build executables, there are some shortcomings that will be addressed in the future. The plugins in this profile may be replaced with other plugins.

This profile adds the following goals to the lifecycle:

Plugin Phase execution id goal(s) function

maven-shade-plugin

package

basepom.executable.default

shade

create a jar with all dependencies included

really-executable-jar-maven-plugin

package

basepom.executable.default

really-executable-jar

create an executable from the shaded jar

8.1.3. basepom.repack (foundation)

This profile activates if a .repack-executable file exists in the current build module. This file only needs to exist, it can be empty.

This profile is experimental. While it is possible to build executables, there are a number of configuration options of the repack plugin that have not been exposed yet. This profile will ultimately replace the basepom.executable profile.

This profile adds the following goals to the lifecycle:

Plugin Phase execution id goal(s) function

repack-maven-plugin

package

basepom.repack.default

repack

repacks the main artifact with all dependencies

really-executable-jar-maven-plugin

package

basepom.repack.default

really-executable-jar

create an executable from the repacked jar

8.1.4. basepom.deploy-release (oss)

This is the release profile for releasing an artifact to the OSS repository (and subsequently to Maven Central). It is configured as release profile for the release plugin if the oss BasePOM is used. It gets activated when executing the release:perform goal of the release plugin.

  • skip unit tests (all tests have already passed as part of the release process)

  • skip all checkers that are following the basepom.check.skip-all setting (they have already been executed as part of the release process)

  • always create a javadoc artifact

This profile adds the following goals to the lifecycle:

Plugin Phase execution id goal(s) function

maven-gpg-plugin

verify

basepom.release.default

sign

create GPG signature for releasing to OSS

8.1.5. basepom.oss-release (oss)

This is an alternate release profile for releasing an artifact to a non-staging repository. It must be activated by replacing basepom.deploy-release in the basepom.release.profiles property with basepom.oss-release.

  • disables the regular maven-deploy-plugin

  • skip unit tests (all tests have already passed as part of the release process)

  • skip all checkers that are following the basepom.check.skip-all setting (they have already been executed as part of the release process)

  • always create a javadoc artifact

This profile adds the following goals to the lifecycle:

Plugin Phase execution id goal(s) function

maven-gpg-plugin

verify

basepom.release.default

sign

create GPG signature for releasing to OSS

maven-nexus-staging-plugin

deploy

basepom.release.default

deploy

deploy the project to the Nexus OSS staging area. Depending on the setting of basepom.nexus-staging.release-after-close, the project will be directly released, otherwise the repo will be closed and must be released in an additional step.

This profile is experimental and is known to have problems with some multi-module builds (NEXUS-38262).

8.1.6. basepom.invoker-reporting (oss)

This profile activates if the build module contains a src/it directory.

Due to a limitation in Apache Maven is the src/it path hardcoded for profile activation. For that reason, changing the basepom.invoker.folder property is rarely done. If integration tests are located in a different directory, this profile will not activate automatically.

This profile adds the following reports to the site build:

Plugin Report

maven-invoker-plugin

report

jacoco-maven-plugin

report-integration

9. Creating a PolicyPOM to apply a build policy

Most organizations create internal policies on how builds should be organized, what rules should be enforced etc. Having such policies codified and enforced by the build system are a massive boost for code quality and reuse.

An organization that plans to use BasePOM should also create an organization specific Policy POM.

BasePOMs were designed specifically to allow policy enforcement across many projects. The minimal and oss BasePOMs are examples on how to create Policy POMs that can be used by projects.

A PolicyPOM should define or apply specific rules for

  • property settings (e.g. required JDK level, checker settings etc.)

  • remote repositories for artifacts and artifact deployment

  • specific checker configuration

  • code packaging

  • Unit and integration test configuration

  • Policy profiles

9.1. The minimal Policy POM

When using the minimal BasePOM for a project, some policies are applied:

  • The pmd and checkstyle checkers are added to the extended set of Build checkers.

  • Rule configuration for pmd, checkstyle and spotbugs

  • a repository reference is added that fixes a problem with the popular Spring framework

  • rules for the duplicate-finder build checker

  • rules for the dependency-checkers build checker

  • configuration for the shade plugin

  • environment variables for unit and integration tests

The minimal BasePOM uses a policy jar to store the configuration for spotbugs and checkstyle.

9.1.1. duplicate-finder plugin configuration

The duplicate-finder plugin will flag any class that appears multiple times on the class path (in multiple jars). While this is generally desirable, there are some common jars that overlap in a benign way. Almost all of these overlaps are specific to annotation classes.

package dependencies (jars that may contain these classes)

javax.annotation

com.google.code.findbugs:jsr305 com.google.code.findbugs:annotations

net.jcip.annotations

com.google.code.findbugs:annotations net.jcip:jcip-annotations

edu.umd.cs.findbugs.annotations

com.google.code.findbugs:annotations com.google.code.findbugs:findbugs-annotations com.github.spotbugs:spotbugs-annotations

javax.inject

javax.inject:javax.inject org.glassfish.hk2.external:javax.inject

jakarta.inject

org.glassfish.hk2.external:jakarta.inject jakarta.inject:jakarta.inject-api

org.aopalliance.aop org.aopalliance.intercept

aopalliance:aopalliance org.glassfish.hk2.external:aopalliance-repackaged

Similar to classes, there are other resources on the class path as well. Most of those should be unique, however there are a few resources that are often packaged into jars where duplicates can be tolerated.

The following resource patterns are ignored:

  • any resource ending with .afm, .dtd, .gif, .html, .java, .png, .properties, .txt

  • any resource starting with . about.

  • any resource in a directory named about_files or license

  • resources called schema in any directory

  • resource named mime.types, plugin.properties, plugin.xml, reference.conf, log4j.xml, log4j.properties, logback.xml, logback.properties

9.1.2. pmd plugin configuration

PMD does code analysis and flags common programming errors and anti-patterns. This is useful for code that is actually written but less so for code that is auto-generated where the constructs in auto-generated classes can not be modified unless the code generator itself is changed.

Auto-generated code is usually located in target/generated-sources/stubs and target/generated-sources/annotations. These folders are excluded from being scanned by PMD.

9.1.3. dependency plugin configuration

Similar to the duplicate-checker, the dependency plugin checks what elements are on the class path and whether these are used. This process is more difficult for elements that need to be present at compile-time but not at runtime and that are not referenced from the build artifacts.

For the minimal BasePOM, the dependency plugin is configured to:

  • ignore all non-test scoped dependencies in "test" scope

  • allow the following dependencies on the classpath even if there are no direct references in the resulting artifacts (all of these jars are "annotation-only" jars)

dependency

aopalliance:aopalliance

com.github.spotbugs:spotbugs-annotations

com.google.code.findbugs:annotations

com.google.code.findbugs:jsr305

com.google.errorprone:error_prone_annotations

jakarta.inject:jakarta.inject-api

javax.inject:javax.inject

net.jcip:jcip-annotations

org.checkerframework:checker-qual

org.glassfish.hk2.external:aopalliance-repackaged

org.glassfish.hk2.external:jakarta.inject

org.glassfish.hk2.external:javax.inject

9.1.4. shade plugin configuration

The shade plugin is used to "shade" a build artifact and all its dependencies into a single "fat jar" by rewriting packages and classes.

In the minimal Policy POM, the shade plugin is configured to

  • support basepom.main-class to configure main class for a shaded jar

  • collect all additional, named sections from dependencies into the shaded jar

  • create the X-BasePOM-Build-Id main manifest entry from the ${basepom.shaded.id} to differentiate a shaded jar from the original, non-shaded jar

9.1.5. repack plugin configuration

The repack plugin can create a "fat jar" artifact from a build artifact by including all its dependencies into a single jar. It does not rewrite any classes or unpack dependencies.

In the minimal Policy POM, the repack plugin is configured to

  • support basepom.main-class to configure main class for a repacked jar

9.1.6. surefire and failsafe plugins

The minimal BasePOM adds a few system properties for testing.

property value function

sun.jnu.encoding

${project.build.sourceEncoding}

sun.jnu.encoding is used for encoding/decoding file paths

user.timezone

UTC

user timezone for tests

java.awt.headless

true

tests run without a graphical UI

java.util.logging.SimpleFormatter.format

%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %5$s%6$s%n

formatter for java.util.logging messages

9.2. The oss Policy POM

The oss BasePOM is intended for projects that distribute their artifacts through the Sonatype OSS ecosystem to Maven Central. In addition to the minimal policy, it applies the following configuration:

  • the license checker is added to the extended set of Build checkers.

  • configure the OSS repositories for snapshot and release distribution. The repositories are configured as sonatype-nexus-snapshots and sonatype-nexus-staging. The local settings.xml file must contain credentials for these ids to authenticate to the repositories for artifact upload.

  • set the basepom.deploy-release profile as release profile for the maven-release-plugin, which uses the Apache deploy plugin to upload the project.

The oss BasePOM also adds the following goals to the lifecycle:

Plugin Phase execution id goal(s) function

license-maven-plugin

validate / verify

basepom.default

check

check license headers

10. Reproducible Builds with BasePOM

Apache Maven supports reproducible builds (where it is possible to create bit-identical artefacts from a given SCM revision) as described in the reproducible build mini-guide. Apache Maven writes a timestamp into a build property (project.build.outputTimestamp) and any plugin is expected to create reproducible output when this property is present.

BasePOM supports reproducible builds in version 59 or higher.

10.1. Using the git SCM information for reproducible builds

It is possible to create reproducible builds for any git commit using BasePOM. In every POM in a project, add

<properties>
    <project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp>
</properties>

This uses the commit timestamp of the current commit as timestamp for the reproducible build. BasePOM configures the format of the timestamp to be compatible to the project.build.outputTimestamp property and executes the git-commit-id plugin as the first plugin in the build cycle, therefore ensuring that all other plugins will pick up the setting correctly.

10.2. Using POM inheritance with the git SCM information

While the artifact:check-buildplan goal recommends not using POM inheritance for the project.build.outputTimestamp property, it can be used in combination with the git.commit.time value. However, by default, the git-commit-id plugin will skip execution for POM project, so the value may not be set correctly. To avoid this, also activate the plugin for POM projects as well. Adding the following properties:

<properties>
    <project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp>
    <basepom.git-id.skip-pom-projects>false</basepom.git-id.skip-pom-projects>
</properties>

to the top-most POM makes a multi-module build reproducible (no additional properties in the child POMs are required).

11. Plugin configuration notes

11.1. Unit and integration tests and code coverage

The interaction between the surefire, failsafe and invoker plugin and the respective code coverage plugin (jacoco) is through an agent specification that modifies the command line for test invocation.

To hide this implementation detail, two properties exist for internal BasePOM use that should not be modified: basepom.coverage.test-args for unit tests and basepom.coverage.it-args for integration tests.

If the coverage agent is not active (by setting basepom.check.skip-coverage to true), these properties are empty. If the agent is active, it will write the necessary parameters for adding the coverage agent to these properties.

When the respective test plugin executes, they pick up the content of these properties (through the argLine configuration setting). Using a secondary property (and not the argLine property directly as most stack overflow posts would suggest) allows manual configuration on the command line while still preserving the ability to add the coverage agent through the build lifecycle.

If the argLine configuration needs to be modified (e.g. in a Policy POM), the @{basepom.coverage.test-args} (for surefire) and @{basepom.coverage.it-args} (for failsafe) must be present, otherwise this integration no longer works. Using a @ is not a typo but necessary for late evaluation of these properties.

Unfortunately, for the invoker plugin, this is not possible. For invoker, a invoker.properties file must be used which should contain the line

invoker.mavenOpts = ${basepom.coverage.it-args} -Xmx${basepom.it.memory} -Dfile.encoding=${project.build.sourceEncoding}

to emulate the argLine setting for surefire and failsafe. This property file is also late (at runtime) evaluated.

11.2. Jar properties

The maven-jar-plugin is used to create the main and test artifacts.

It is configured to create the standard implementation and specification entries as described in the Maven Jar documentation.

It also adds a number of custom entries in the jar manifest that allow inspection of build artifacts:

Manifest entry value section function

X-BasePOM-Build-Id

${basepom.build.id}, unique build UUID, created for every build

main

unique build id for each artifact

X-BasePOM-Build-Name

${project.name}

main

project name of the build

X-BasePOM-Build-Git-Commit-Id

${git.commit.id} (created by the git-commit-id-maven-plugin)

main

see git.commit.id in the git-commit-id-maven-plugin documentation

Build-Time

${git.build.time} (created by the git-commit-id-maven-plugin)

${project.groupId}:${project.artifactId}

see git.build.time in the git-commit-id-maven-plugin documentation

Git-Branch

${git.branch} (created by the git-commit-id-maven-plugin)

${project.groupId}:${project.artifactId}

see git.branch in the git-commit-id-maven-plugin documentation

Git-Commit-Id

${git.commit.id} (created by the git-commit-id-maven-plugin)

${project.groupId}:${project.artifactId}

see git.commit.id in the git-commit-id-maven-plugin documentation

Git-Commit-Id-Describe

${git.commit.id.describe} (created by the git-commit-id-maven-plugin)

${project.groupId}:${project.artifactId}

see git.commit.id.describe in the git-commit-id-maven-plugin documentation

Project-ArtifactId

${project.artifactId}

${project.groupId}:${project.artifactId}

The artifact id of the build

Project-GroupId

${project.groupId}

${project.groupId}:${project.artifactId}

The group id of the build

Project-Name

${project.name}

${project.groupId}:${project.artifactId}

The project name of the build

Project-Version

${project.version}

${project.groupId}:${project.artifactId}

The version of the build

The ${project.groupId}:${project.artifactId} section is specific for each project. This allows the maven-shade-plugin to coalesce all these sections without overwriting any of the parameters.

11.3. Jar shading

The maven-shade-plugin is used to create single artifacts with all dependencies ("fat jars") for a project.

BasePOM does not create a dependency reduced POM and all shaded artifacts are attached. Shaded artifacts should never be used as dependencies but should be terminal (e.g. an application jar).

11.4. Jar repacking

The repack-maven-plugin is used to create single artifacts with all dependencies ("fat jars") for a project. This method adds all dependencies "as is" (it does not rewrite the contents of main jar or unpacks dependencies) and produces better outcomes than shading jars.

Repacked artifacts cannot be used as dependencies as its contents are packaged into different directories.

11.5. Using the license plugin

The oss BasePOM configures the license-maven-plugin for releasing artifacts to Maven Central:

  • use the Apache Software License without copyright line

  • map g4, groovy and java files to SLASHSTAR_STYLE

  • map stg files to DOUBLESLASH_STYLE

  • map xml files to XML_PREFIX

  • map yaml files to SCRIPT_STYLE

  • exclude all files in directories starting with .

  • exclude all files ending with .md, .rst, .adoc, .sh, .txt, .thrift, .proto, .g, .releaseBackup, .vm, .st, .raw, .ser

  • exclude all files in the src/license tree

  • exclude all CNAME and .keepme files

12. Maven Site generation

The foundation BasePOM provides basic configuration for the Maven autogenerated site which summarizes information about the build lifecycle. The oss BasePOM contains the necessary reporting setup to generate a base site for a project.

Property Name Default Value customization defined in function

basepom.site.skip

false

often

foundation

If true, skip site and report generation

basepom.site.skip-deploy

true

often, policy

foundation

If true, do not execute site:deploy for deployment using the site plugin

basepom.site.scm.skip-deploy

true

often, policy

foundation

If true, do not execute scm-publish:publish-scm for deployment using the scm-publish plugin

basepom.site.scm.site-path

development

often

foundation

The path on the remote repository where the site is deployed

basepom.site.scm.branch

main

sometimes

foundation

The branch on the remote repository where the site is deployed

basepom.site.scm.url

<unset>

always

foundation

The remote URL of the site repository

basepom.site.scm.id

<unset>

always

foundation

The settings id used for authenticating the site repository

basepom.site.scm.try-update

false

sometimes

foundation

If true, try a local scm update first before doing a full checkout.

basepom.site.scm.checkout-directory

${java.io.tmpdir}/gh-pages-publish/${project.name}

sometimes

foundation

the local checkout directory for the site.

basepom.site.scm.comment

Site checkin for project ${project.name} (${project.version})

sometimes

foundation

The commit message for a site checkin.

basepom.site.test.skip

${basepom.test.skip}

rarely

oss

Skip test report generation.

basepom.site.it.skip

${basepom.it.skip}

rarely

oss

Skip integration test report generation.

basepom.site.skip-checkstyle

${basepom.check.skip-checkstyle}

rarely

oss

Skip checkstyle report generation.

basepom.site.skip-coverage

${basepom.check.skip-coverage}

rarely

oss

Skip coverage (jacoco) report generation.

basepom.site.skip-pmd

${basepom.check.skip-pmd}

rarely

oss

Skip PMD report generation.

basepom.site.skip-spotbugs

${basepom.check.skip-spotbugs}

rarely

oss

Skip spotbugs report generation.

basepom.site.skip-javadoc

${basepom.javadoc.skip}

rarely

oss

Skip javadoc for site generation.

basepom.site.fail-javadoc

${basepom.check.fail-javadoc}

rarely

oss

If true, fail the site build if the javadoc generation fails.

The following reports are generated (oss BasePOM):

Plugin Report

maven-project-info-reports-plugin

index

maven-project-info-reports-plugin

summary

maven-project-info-reports-plugin

dependency-info

maven-project-info-reports-plugin

scm

maven-project-info-reports-plugin

issue-management

maven-project-info-reports-plugin

team

maven-project-info-reports-plugin

modules

maven-project-info-reports-plugin

licenses

maven-project-info-reports-plugin

ci-management

maven-project-info-reports-plugin

dependency-convergence

maven-project-info-reports-plugin

dependencies

maven-project-info-reports-plugin

dependency-management

maven-project-info-reports-plugin

plugins

maven-project-info-reports-plugin

plugin-management

maven-surefire-plugin

report-only

maven-checkstyle-plugin

checkstyle

maven-jxr-plugin

jxr-no-fork

maven-jxr-plugin

test-jxr-no-fork

maven-pmd-plugin

pmd

spotbugs-maven-plugin

spotbugs

jacoco-maven-plugin

report

maven-javadoc-plugin

javadoc-no-fork

maven-javadoc-plugin

test-javadoc-no-fork