16
16
17
17
package org .springframework .boot .build .bom ;
18
18
19
+ import java .io .File ;
19
20
import java .util .ArrayList ;
20
21
import java .util .Arrays ;
21
22
import java .util .Collections ;
31
32
import java .util .regex .Pattern ;
32
33
import java .util .stream .Stream ;
33
34
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
+
34
40
import org .apache .maven .artifact .versioning .DefaultArtifactVersion ;
35
41
import org .apache .maven .artifact .versioning .VersionRange ;
36
42
import org .gradle .api .Project ;
37
43
import org .gradle .api .artifacts .Configuration ;
38
44
import org .gradle .api .artifacts .Dependency ;
39
45
import org .gradle .api .artifacts .result .DependencyResult ;
40
46
import org .gradle .api .artifacts .result .ResolutionResult ;
47
+ import org .w3c .dom .Document ;
41
48
42
49
import org .springframework .boot .build .bom .bomr .version .DependencyVersion ;
43
50
@@ -406,10 +413,18 @@ public String getArtifactId() {
406
413
407
414
}
408
415
416
+ public interface VersionAlignment {
417
+
418
+ Set <String > resolve ();
419
+
420
+ }
421
+
409
422
/**
410
- * Version alignment for a library.
423
+ * Version alignment for a library based on a dependency of another module .
411
424
*/
412
- public static class VersionAlignment {
425
+ public static class DependencyVersionAlignment implements VersionAlignment {
426
+
427
+ private final String dependency ;
413
428
414
429
private final String from ;
415
430
@@ -423,35 +438,44 @@ public static class VersionAlignment {
423
438
424
439
private Set <String > alignedVersions ;
425
440
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 ;
427
444
this .from = from ;
428
445
this .managedBy = managedBy ;
429
446
this .project = project ;
430
447
this .libraries = libraries ;
431
448
this .groups = groups ;
432
449
}
433
450
451
+ @ Override
434
452
public Set <String > resolve () {
435
453
if (this .alignedVersions != null ) {
436
454
return this .alignedVersions ;
437
455
}
438
456
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
+ }
445
469
}
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
+ }
451
475
}
452
476
}
477
+ this .alignedVersions = versionsInLibrary ;
453
478
}
454
- this .alignedVersions = versionsInLibrary ;
455
479
return this .alignedVersions ;
456
480
}
457
481
@@ -539,6 +563,100 @@ public String toString() {
539
563
540
564
}
541
565
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
+
542
660
public record Link (String rootName , Function <LibraryVersion , String > factory , List <String > packages ) {
543
661
544
662
private static final Pattern PACKAGE_EXPAND = Pattern .compile ("^(.*)\\ [(.*)\\ ]$" );
0 commit comments