[JLBP-16] Ensure upper version alignment of dependencies for consumers

For multi-module projects, this best practice assumes you have already applied JLBP-15, so that your project has a BOM.

Upper version alignment is defined in the glossary.

Achieving upper version alignment

Upper version alignment increases the likelihood that consumers’ build systems select the right versions of direct and transitive dependencies, reducing the number of conflicts.

As noted in the definition, to fix a version misalignment caused by a shorter path to a version of a dependency that is not the upper bound in the dependency tree, a direct dependency needs to be added so that Maven consumers select the correct version.

See the details specific to each build system in the following sections.


Use requireUpperBoundDeps enforcement to ensure that you are using the highest version of each dependency in your dependency tree.

To ensure that dependencies between modules in the project are consistent, the parent POM should import the library’s own BOM into its <dependencyManagement> section.

To ensure that usage of dependencies is consistent, for any direct dependencies that have a BOM of their own, import those BOMs in a <dependencyManagement> section.

For direct dependencies that don’t have a BOM (for example, Joda-Time), make sure only one pom.xml defines the version, so that the library doesn’t accidentally depend on different versions in different modules.

For any transitive dependency that fails a requireUpperBoundDeps check, add the dependency as a direct dependency so that the path to the correct version is shorter, leading Maven to select it instead of the wrong version.

Have each module POM inherit from the parent POM of the library so that the parent’s <dependencyManagement> section is used.


Declare variables defining dependency versions in a shared ext section in the root build.gradle file, and use those variables in any place declaring a dependency.