From 04a4f415a9158c2cc00cd4d282ba330bd7937527 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 6 Mar 2026 14:10:01 +0000 Subject: [PATCH] Avoid conflict caused by Micrometer Tracing's bom Micrometer Tracing's bom isn't a pure bill of materials for the Micrometer Tracing project as it also imports Micrometer's bom. As Boot itself also imports Micrometer's bom this can lead to conflicts when the versions do not all align. For example, at the time of writing, Boot is using 1.5.10-SNAPSHOT of Micrometer Tracing and trying to use 1.15.10-SNAPSHOT of Micrometer. This results in some conflicts as the Micrometer Tracing bom imports 1.15.9 of the Micrometer bom. Closes gh-49456 --- .../boot/build/bom/BomExtension.java | 28 ++++++++++++-- .../boot/build/bom/CheckBom.java | 12 ++++-- .../boot/build/bom/Library.java | 38 +++++++++++++++---- .../antora/AntoraAsciidocAttributesTests.java | 3 +- .../boot/build/bom/LibraryTests.java | 5 ++- .../spring-boot-dependencies/build.gradle | 17 ++++++++- 6 files changed, 83 insertions(+), 20 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java index d787decf1a0..3d4dc4b6d6c 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java @@ -23,6 +23,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.function.Predicate; import javax.inject.Inject; @@ -40,6 +41,7 @@ import org.gradle.api.plugins.JavaPlatformPlugin; import org.springframework.boot.build.bom.BomExtension.LibraryHandler.AlignWithHandler.PropertyHandler; import org.springframework.boot.build.bom.BomExtension.LibraryHandler.AlignWithHandler.VersionHandler; +import org.springframework.boot.build.bom.Library.BomAlignment; import org.springframework.boot.build.bom.Library.DependencyVersionAlignment; import org.springframework.boot.build.bom.Library.Exclusion; import org.springframework.boot.build.bom.Library.Group; @@ -51,6 +53,7 @@ import org.springframework.boot.build.bom.Library.PermittedDependency; import org.springframework.boot.build.bom.Library.PomPropertyVersionAlignment; import org.springframework.boot.build.bom.Library.ProhibitedVersion; import org.springframework.boot.build.bom.Library.VersionAlignment; +import org.springframework.boot.build.bom.ResolvedBom.Id; import org.springframework.boot.build.bom.bomr.version.DependencyVersion; import org.springframework.boot.build.properties.BuildProperties; import org.springframework.util.PropertyPlaceholderHelper; @@ -112,8 +115,8 @@ public class BomExtension { LibraryVersion libraryVersion = new LibraryVersion(DependencyVersion.parse(libraryHandler.version)); addLibrary(new Library(name, libraryHandler.calendarName, libraryVersion, libraryHandler.groups, libraryHandler.upgradePolicy, libraryHandler.prohibitedVersions, libraryHandler.considerSnapshots, - versionAlignment(libraryHandler), libraryHandler.alignWith.dependencyManagementDeclaredIn, - libraryHandler.linkRootName, libraryHandler.links)); + versionAlignment(libraryHandler), libraryHandler.alignWith.bomAlignment, libraryHandler.linkRootName, + libraryHandler.links)); } private VersionAlignment versionAlignment(LibraryHandler libraryHandler) { @@ -404,7 +407,7 @@ public class BomExtension { private PropertyHandler property; - private String dependencyManagementDeclaredIn; + private BomAlignment bomAlignment; public void version(Action action) { this.version = new VersionHandler(); @@ -417,7 +420,14 @@ public class BomExtension { } public void dependencyManagementDeclaredIn(String bomCoordinates) { - this.dependencyManagementDeclaredIn = bomCoordinates; + this.bomAlignment = new BomAlignment(bomCoordinates, (id) -> false); + } + + public void dependencyManagementDeclaredIn(String bomCoordinates, + Action action) { + DependencyManagementDeclaredInHandler handler = new DependencyManagementDeclaredInHandler(); + action.execute(handler); + this.bomAlignment = new BomAlignment(bomCoordinates, handler.exclusions); } public static class VersionHandler { @@ -464,6 +474,16 @@ public class BomExtension { } + public static class DependencyManagementDeclaredInHandler { + + private Predicate exclusions = (id) -> false; + + public void excluding(Predicate exclusion) { + this.exclusions = this.exclusions.or(exclusion); + } + + } + } } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java index b55ff0ae7f3..8abb6e5d934 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeSet; +import java.util.function.Predicate; import java.util.stream.Collectors; import javax.inject.Inject; @@ -45,6 +46,7 @@ import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.VerificationException; +import org.springframework.boot.build.bom.Library.BomAlignment; import org.springframework.boot.build.bom.Library.Group; import org.springframework.boot.build.bom.Library.ImportedBom; import org.springframework.boot.build.bom.Library.Module; @@ -291,20 +293,22 @@ public abstract class CheckBom extends DefaultTask { @Override public List check(Library library, ResolvedLibrary resolvedLibrary) { List errors = new ArrayList<>(); - String alignsWithBom = library.getAlignsWithBom(); + BomAlignment alignsWithBom = library.getAlignsWithBom(); if (alignsWithBom != null) { Bom mavenBom = this.bomResolver - .resolveMavenBom(alignsWithBom + ":" + library.getVersion().getVersion()); - checkDependencyManagementAlignment(resolvedLibrary, mavenBom, errors); + .resolveMavenBom(alignsWithBom.getCoordinates() + ":" + library.getVersion().getVersion()); + checkDependencyManagementAlignment(resolvedLibrary, mavenBom, errors, alignsWithBom::exclude); } return errors; } - private void checkDependencyManagementAlignment(ResolvedLibrary library, Bom mavenBom, List errors) { + private void checkDependencyManagementAlignment(ResolvedLibrary library, Bom mavenBom, List errors, + Predicate excluded) { List managedByLibrary = library.managedDependencies(); List managedByBom = managedDependenciesOf(mavenBom); List missing = new ArrayList<>(managedByBom); + missing.removeIf(excluded); missing.removeAll(managedByLibrary); List unexpected = new ArrayList<>(managedByLibrary); diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java index fdd16c25460..fe83fd9d0b2 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java @@ -30,6 +30,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; @@ -48,6 +49,7 @@ import org.gradle.api.artifacts.result.DependencyResult; import org.gradle.api.artifacts.result.ResolutionResult; import org.w3c.dom.Document; +import org.springframework.boot.build.bom.ResolvedBom.Id; import org.springframework.boot.build.bom.bomr.version.DependencyVersion; /** @@ -76,7 +78,7 @@ public class Library { private final VersionAlignment versionAlignment; - private final String alignsWithBom; + private final BomAlignment bomAlignment; private final String linkRootName; @@ -95,15 +97,14 @@ public class Library { * @param prohibitedVersions version of the library that are prohibited * @param considerSnapshots whether to consider snapshots * @param versionAlignment version alignment, if any, for the library - * @param alignsWithBom the coordinates of the bom, if any, that this library should - * align with + * @param bomAlignment the bom, if any, that this library should align with * @param linkRootName the root name to use when generating link variable or * {@code null} to generate one based on the library {@code name} * @param links a list of HTTP links relevant to the library */ public Library(String name, String calendarName, LibraryVersion version, List groups, UpgradePolicy upgradePolicy, List prohibitedVersions, boolean considerSnapshots, - VersionAlignment versionAlignment, String alignsWithBom, String linkRootName, + VersionAlignment versionAlignment, BomAlignment bomAlignment, String linkRootName, Map> links) { this.name = name; this.calendarName = (calendarName != null) ? calendarName : name; @@ -115,7 +116,7 @@ public class Library { this.prohibitedVersions = prohibitedVersions; this.considerSnapshots = considerSnapshots; this.versionAlignment = versionAlignment; - this.alignsWithBom = alignsWithBom; + this.bomAlignment = bomAlignment; this.linkRootName = (linkRootName != null) ? linkRootName : generateLinkRootName(name); this.links = (links != null) ? Collections.unmodifiableMap(new TreeMap<>(links)) : Collections.emptyMap(); } @@ -164,8 +165,8 @@ public class Library { return this.linkRootName; } - public String getAlignsWithBom() { - return this.alignsWithBom; + public BomAlignment getAlignsWithBom() { + return this.bomAlignment; } public Map> getLinks() { @@ -193,7 +194,7 @@ public class Library { public Library withVersion(LibraryVersion version) { return new Library(this.name, this.calendarName, version, this.groups, this.upgradePolicy, - this.prohibitedVersions, this.considerSnapshots, this.versionAlignment, this.alignsWithBom, + this.prohibitedVersions, this.considerSnapshots, this.versionAlignment, this.bomAlignment, this.linkRootName, this.links); } @@ -439,6 +440,27 @@ public class Library { } + public static class BomAlignment { + + private final String coordinates; + + private final Predicate excluding; + + public BomAlignment(String bomCoordinates, Predicate excluding) { + this.coordinates = bomCoordinates; + this.excluding = excluding; + } + + public String getCoordinates() { + return this.coordinates; + } + + public boolean exclude(Id id) { + return this.excluding.test(id); + } + + } + /** * Version alignment for a library based on a dependency of another module. */ diff --git a/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java b/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java index 51b89c5b88f..dff2df1c211 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java @@ -26,6 +26,7 @@ import java.util.function.Function; import org.junit.jupiter.api.Test; import org.springframework.boot.build.bom.Library; +import org.springframework.boot.build.bom.Library.BomAlignment; import org.springframework.boot.build.bom.Library.Group; import org.springframework.boot.build.bom.Library.LibraryVersion; import org.springframework.boot.build.bom.Library.Link; @@ -235,7 +236,7 @@ class AntoraAsciidocAttributesTests { List prohibitedVersion = Collections.emptyList(); boolean considerSnapshots = false; VersionAlignment versionAlignment = null; - String alignsWithBom = null; + BomAlignment alignsWithBom = null; String linkRootName = null; Library library = new Library(name, calendarName, version, groups, null, prohibitedVersion, considerSnapshots, versionAlignment, alignsWithBom, linkRootName, links); diff --git a/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java b/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java index 85750195992..4d35d610a76 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java @@ -22,6 +22,7 @@ import java.util.Map; import org.junit.jupiter.api.Test; +import org.springframework.boot.build.bom.Library.BomAlignment; import org.springframework.boot.build.bom.Library.Group; import org.springframework.boot.build.bom.Library.LibraryVersion; import org.springframework.boot.build.bom.Library.Link; @@ -47,7 +48,7 @@ class LibraryTests { List prohibitedVersion = Collections.emptyList(); boolean considerSnapshots = false; VersionAlignment versionAlignment = null; - String alignsWithBom = null; + BomAlignment alignsWithBom = null; String linkRootName = null; Map> links = Collections.emptyMap(); Library library = new Library(name, calendarName, version, groups, null, prohibitedVersion, considerSnapshots, @@ -64,7 +65,7 @@ class LibraryTests { List prohibitedVersion = Collections.emptyList(); boolean considerSnapshots = false; VersionAlignment versionAlignment = null; - String alignsWithBom = null; + BomAlignment alignsWithBom = null; String linkRootName = "spring-data"; Map> links = Collections.emptyMap(); Library library = new Library(name, calendarName, version, groups, null, prohibitedVersion, considerSnapshots, diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index b9b547ba845..192bbbc3acf 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1613,8 +1613,23 @@ bom { } library("Micrometer Tracing", "1.5.10-SNAPSHOT") { considerSnapshots() + alignWith { + dependencyManagementDeclaredIn("io.micrometer:micrometer-tracing-bom") { + excluding { id -> + !id.artifactId().startsWith("micrometer-tracing") && !id.artifactId().equals("docs") + } + } + } group("io.micrometer") { - bom("micrometer-tracing-bom") + modules = [ + "docs", + "micrometer-tracing", + "micrometer-tracing-bridge-brave", + "micrometer-tracing-bridge-otel", + "micrometer-tracing-integration-test", + "micrometer-tracing-reporter-wavefront", + "micrometer-tracing-test" + ] } links { site("https://micrometer.io")