Skip to content

Commit 1a79f66

Browse files
committed
Merge branch '3.4.x'
Closes gh-45703
2 parents 25b72d6 + 89d26db commit 1a79f66

File tree

3 files changed

+200
-23
lines changed

3 files changed

+200
-23
lines changed

buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,17 @@
3838
import org.gradle.api.model.ObjectFactory;
3939
import org.gradle.api.plugins.JavaPlatformPlugin;
4040

41+
import org.springframework.boot.build.bom.BomExtension.LibraryHandler.AlignWithHandler.PropertyHandler;
42+
import org.springframework.boot.build.bom.BomExtension.LibraryHandler.AlignWithHandler.VersionHandler;
43+
import org.springframework.boot.build.bom.Library.DependencyVersionAlignment;
4144
import org.springframework.boot.build.bom.Library.Exclusion;
4245
import org.springframework.boot.build.bom.Library.Group;
4346
import org.springframework.boot.build.bom.Library.ImportedBom;
4447
import org.springframework.boot.build.bom.Library.LibraryVersion;
4548
import org.springframework.boot.build.bom.Library.Link;
4649
import org.springframework.boot.build.bom.Library.Module;
4750
import org.springframework.boot.build.bom.Library.PermittedDependency;
51+
import org.springframework.boot.build.bom.Library.PomPropertyVersionAlignment;
4852
import org.springframework.boot.build.bom.Library.ProhibitedVersion;
4953
import org.springframework.boot.build.bom.Library.VersionAlignment;
5054
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
@@ -106,16 +110,26 @@ public void library(String name, String version, Action<LibraryHandler> action)
106110
(version != null) ? version : "");
107111
action.execute(libraryHandler);
108112
LibraryVersion libraryVersion = new LibraryVersion(DependencyVersion.parse(libraryHandler.version));
109-
VersionAlignment versionAlignment = (libraryHandler.alignWith.version != null)
110-
? new VersionAlignment(libraryHandler.alignWith.version.from,
111-
libraryHandler.alignWith.version.managedBy, this.project, this.libraries, libraryHandler.groups)
112-
: null;
113113
addLibrary(new Library(name, libraryHandler.calendarName, libraryVersion, libraryHandler.groups,
114-
libraryHandler.prohibitedVersions, libraryHandler.considerSnapshots, versionAlignment,
114+
libraryHandler.prohibitedVersions, libraryHandler.considerSnapshots, versionAlignment(libraryHandler),
115115
libraryHandler.alignWith.dependencyManagementDeclaredIn, libraryHandler.linkRootName,
116116
libraryHandler.links));
117117
}
118118

119+
private VersionAlignment versionAlignment(LibraryHandler libraryHandler) {
120+
VersionHandler version = libraryHandler.alignWith.version;
121+
if (version != null) {
122+
return new DependencyVersionAlignment(version.of, version.from, version.managedBy, this.project,
123+
this.libraries, libraryHandler.groups);
124+
}
125+
PropertyHandler property = libraryHandler.alignWith.property;
126+
if (property != null) {
127+
return new PomPropertyVersionAlignment(property.name, property.of, property.managedBy, this.project,
128+
this.libraries);
129+
}
130+
return null;
131+
}
132+
119133
private String createDependencyNotation(String groupId, String artifactId, DependencyVersion version) {
120134
return groupId + ":" + artifactId + ":" + version;
121135
}
@@ -382,23 +396,36 @@ public static class AlignWithHandler {
382396

383397
private VersionHandler version;
384398

399+
private PropertyHandler property;
400+
385401
private String dependencyManagementDeclaredIn;
386402

387403
public void version(Action<VersionHandler> action) {
388404
this.version = new VersionHandler();
389405
action.execute(this.version);
390406
}
391407

408+
public void property(Action<PropertyHandler> action) {
409+
this.property = new PropertyHandler();
410+
action.execute(this.property);
411+
}
412+
392413
public void dependencyManagementDeclaredIn(String bomCoordinates) {
393414
this.dependencyManagementDeclaredIn = bomCoordinates;
394415
}
395416

396417
public static class VersionHandler {
397418

419+
private String of;
420+
398421
private String from;
399422

400423
private String managedBy;
401424

425+
public void of(String of) {
426+
this.of = of;
427+
}
428+
402429
public void from(String from) {
403430
this.from = from;
404431
}
@@ -409,6 +436,28 @@ public void managedBy(String managedBy) {
409436

410437
}
411438

439+
public static class PropertyHandler {
440+
441+
private String name;
442+
443+
private String of;
444+
445+
private String managedBy;
446+
447+
public void name(String name) {
448+
this.name = name;
449+
}
450+
451+
public void of(String dependency) {
452+
this.of = dependency;
453+
}
454+
455+
public void managedBy(String managedBy) {
456+
this.managedBy = managedBy;
457+
}
458+
459+
}
460+
412461
}
413462

414463
}

buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java

Lines changed: 133 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.build.bom;
1818

19+
import java.io.File;
1920
import java.util.ArrayList;
2021
import java.util.Arrays;
2122
import java.util.Collections;
@@ -31,13 +32,19 @@
3132
import java.util.regex.Pattern;
3233
import java.util.stream.Stream;
3334

35+
import javax.xml.parsers.DocumentBuilder;
36+
import javax.xml.parsers.DocumentBuilderFactory;
37+
import javax.xml.xpath.XPath;
38+
import javax.xml.xpath.XPathFactory;
39+
3440
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
3541
import org.apache.maven.artifact.versioning.VersionRange;
3642
import org.gradle.api.Project;
3743
import org.gradle.api.artifacts.Configuration;
3844
import org.gradle.api.artifacts.Dependency;
3945
import org.gradle.api.artifacts.result.DependencyResult;
4046
import org.gradle.api.artifacts.result.ResolutionResult;
47+
import org.w3c.dom.Document;
4148

4249
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
4350

@@ -406,10 +413,18 @@ public String getArtifactId() {
406413

407414
}
408415

416+
public interface VersionAlignment {
417+
418+
Set<String> resolve();
419+
420+
}
421+
409422
/**
410-
* Version alignment for a library.
423+
* Version alignment for a library based on a dependency of another module.
411424
*/
412-
public static class VersionAlignment {
425+
public static class DependencyVersionAlignment implements VersionAlignment {
426+
427+
private final String dependency;
413428

414429
private final String from;
415430

@@ -423,35 +438,44 @@ public static class VersionAlignment {
423438

424439
private Set<String> alignedVersions;
425440

426-
VersionAlignment(String from, String managedBy, Project project, List<Library> libraries, List<Group> groups) {
441+
DependencyVersionAlignment(String dependency, String from, String managedBy, Project project,
442+
List<Library> libraries, List<Group> groups) {
443+
this.dependency = dependency;
427444
this.from = from;
428445
this.managedBy = managedBy;
429446
this.project = project;
430447
this.libraries = libraries;
431448
this.groups = groups;
432449
}
433450

451+
@Override
434452
public Set<String> resolve() {
435453
if (this.alignedVersions != null) {
436454
return this.alignedVersions;
437455
}
438456
Map<String, String> versions = resolveAligningDependencies();
439-
Set<String> versionsInLibrary = new HashSet<>();
440-
for (Group group : this.groups) {
441-
for (Module module : group.getModules()) {
442-
String version = versions.get(group.getId() + ":" + module.getName());
443-
if (version != null) {
444-
versionsInLibrary.add(version);
457+
if (this.dependency != null) {
458+
String version = versions.get(this.dependency);
459+
this.alignedVersions = (version != null) ? Set.of(version) : Collections.emptySet();
460+
}
461+
else {
462+
Set<String> versionsInLibrary = new HashSet<>();
463+
for (Group group : this.groups) {
464+
for (Module module : group.getModules()) {
465+
String version = versions.get(group.getId() + ":" + module.getName());
466+
if (version != null) {
467+
versionsInLibrary.add(version);
468+
}
445469
}
446-
}
447-
for (String plugin : group.getPlugins()) {
448-
String version = versions.get(group.getId() + ":" + plugin);
449-
if (version != null) {
450-
versionsInLibrary.add(version);
470+
for (String plugin : group.getPlugins()) {
471+
String version = versions.get(group.getId() + ":" + plugin);
472+
if (version != null) {
473+
versionsInLibrary.add(version);
474+
}
451475
}
452476
}
477+
this.alignedVersions = versionsInLibrary;
453478
}
454-
this.alignedVersions = versionsInLibrary;
455479
return this.alignedVersions;
456480
}
457481

@@ -539,6 +563,100 @@ public String toString() {
539563

540564
}
541565

566+
/**
567+
* Version alignment for a library based on a property in the pom of another module.
568+
*/
569+
public static class PomPropertyVersionAlignment implements VersionAlignment {
570+
571+
private final String name;
572+
573+
private final String from;
574+
575+
private final String managedBy;
576+
577+
private final Project project;
578+
579+
private final List<Library> libraries;
580+
581+
private Set<String> alignedVersions;
582+
583+
PomPropertyVersionAlignment(String name, String from, String managedBy, Project project,
584+
List<Library> libraries) {
585+
this.name = name;
586+
this.from = from;
587+
this.managedBy = managedBy;
588+
this.project = project;
589+
this.libraries = libraries;
590+
}
591+
592+
@Override
593+
public Set<String> resolve() {
594+
if (this.alignedVersions != null) {
595+
return this.alignedVersions;
596+
}
597+
Configuration alignmentConfiguration = this.project.getConfigurations()
598+
.detachedConfiguration(getAligningDependencies().toArray(new Dependency[0]));
599+
Set<File> files = alignmentConfiguration.resolve();
600+
if (files.size() != 1) {
601+
throw new IllegalStateException(
602+
"Expected a single file when resolving the pom of " + this.from + " but found " + files.size());
603+
}
604+
File pomFile = files.iterator().next();
605+
return Set.of(propertyFrom(pomFile));
606+
}
607+
608+
private List<Dependency> getAligningDependencies() {
609+
Library managingLibrary = findManagingLibrary();
610+
List<Dependency> boms = getBomDependencies(managingLibrary);
611+
List<Dependency> dependencies = new ArrayList<>();
612+
dependencies.addAll(boms);
613+
dependencies.add(this.project.getDependencies().create(this.from + "@pom"));
614+
return dependencies;
615+
}
616+
617+
private Library findManagingLibrary() {
618+
if (this.managedBy == null) {
619+
return null;
620+
}
621+
return this.libraries.stream()
622+
.filter((candidate) -> this.managedBy.equals(candidate.getName()))
623+
.findFirst()
624+
.orElseThrow(() -> new IllegalStateException("Managing library '" + this.managedBy + "' not found."));
625+
}
626+
627+
private List<Dependency> getBomDependencies(Library manager) {
628+
return manager.getGroups()
629+
.stream()
630+
.flatMap((group) -> group.getBoms()
631+
.stream()
632+
.map((bom) -> this.project.getDependencies()
633+
.platform(group.getId() + ":" + bom.name() + ":" + manager.getVersion().getVersion())))
634+
.toList();
635+
}
636+
637+
private String propertyFrom(File pomFile) {
638+
try {
639+
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
640+
Document document = documentBuilder.parse(pomFile);
641+
XPath xpath = XPathFactory.newInstance().newXPath();
642+
return xpath.evaluate("/project/properties/" + this.name + "/text()", document);
643+
}
644+
catch (Exception ex) {
645+
throw new RuntimeException(ex);
646+
}
647+
}
648+
649+
@Override
650+
public String toString() {
651+
String result = "version from properties of " + this.from;
652+
if (this.managedBy != null) {
653+
result += " that is managed by " + this.managedBy;
654+
}
655+
return result;
656+
}
657+
658+
}
659+
542660
public record Link(String rootName, Function<LibraryVersion, String> factory, List<String> packages) {
543661

544662
private static final Pattern PACKAGE_EXPAND = Pattern.compile("^(.*)\\[(.*)\\]$");

spring-boot-project/spring-boot-dependencies/build.gradle

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,9 +1009,12 @@ bom {
10091009
}
10101010
}
10111011
library("Jedis", "6.0.0") {
1012-
prohibit {
1013-
contains "-beta"
1014-
because "we don't want beta dependencies"
1012+
alignWith {
1013+
property {
1014+
name "jedis"
1015+
of "org.springframework.data:spring-data-redis"
1016+
managedBy "Spring Data Bom"
1017+
}
10151018
}
10161019
group("redis.clients") {
10171020
modules = [
@@ -1596,6 +1599,13 @@ bom {
15961599
}
15971600
}
15981601
library("MongoDB", "5.5.0") {
1602+
alignWith {
1603+
version {
1604+
of "org.mongodb:mongodb-driver-core"
1605+
from "org.springframework.data:spring-data-mongodb"
1606+
managedBy "Spring Data Bom"
1607+
}
1608+
}
15991609
group("org.mongodb") {
16001610
bom("mongodb-driver-bom")
16011611
}

0 commit comments

Comments
 (0)