Skip to content

Latest commit

 

History

History
73 lines (52 loc) · 3.19 KB

File metadata and controls

73 lines (52 loc) · 3.19 KB

[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.

Maven

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.

  • If multiple imported BOMs manage the same dependency, use the <dependencyManagement> of the parent POM to select a compatible version, typically the highest.
  • Order doesn't matter for the override, because all explicit version declarations in dependencyManagement take precedence over all BOM imports. (Order between BOMs matters - the earliest import of a dependency takes precedence over later imports of the same dependency.)

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.

  • The first option is to specify dependency versions in the <dependencyManagement> section of the parent POM. Use this option by default because it is the most structured.

    When declaring a dependency anywhere in the project, omit the version number so that the version from the parent's <dependencyManagement> section takes effect.

  • The second option is to use version properties in the parent that are referenced by child modules.

    When declaring a dependency anywhere in the project, use the Maven property declared in the parent.

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.

Gradle

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.