Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;

import org.gradle.api.DefaultTask;
import org.gradle.api.file.FileCollection;
Expand Down Expand Up @@ -65,48 +69,72 @@ public void documentConstrainedVersions() throws IOException {
outputFile.getParentFile().mkdirs();
try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
writer.println("|===");
writer.println("| Group ID | Artifact ID | Version");
Set<Id> managedCoordinates = new TreeSet<>((id1, id2) -> {
int result = id1.groupId().compareTo(id2.groupId());
if (result != 0) {
return result;
writer.println("| Group ID | Artifact ID | Version | Version Property");
Map<Id, Set<String>> managedCoordinates = new TreeMap<>((id1, id2) -> {
int groupComparison = id1.groupId().compareTo(id2.groupId());
if (groupComparison != 0) {
return groupComparison;
}
return id1.artifactId().compareTo(id2.artifactId());
int artifactComparison = id1.artifactId().compareTo(id2.artifactId());
if (artifactComparison != 0) {
return artifactComparison;
}
return id1.version().compareTo(id2.version());
});
Comment on lines +73 to 83
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comparator passed to TreeMap duplicates ResolvedBom.Id#compareTo (groupId/artifactId/version ordering). Duplicating the ordering logic makes future changes easy to miss and can lead to subtle ordering/keying inconsistencies. Prefer relying on Id’s natural ordering (for example, using a plain new TreeMap<>() or Comparator.naturalOrder()).

Copilot uses AI. Check for mistakes.
for (File file : getResolvedBoms().getFiles()) {
managedCoordinates.addAll(process(ResolvedBom.readFrom(file)));
process(ResolvedBom.readFrom(file), managedCoordinates);
}
for (Id id : managedCoordinates) {
for (Map.Entry<Id, Set<String>> entry : managedCoordinates.entrySet()) {
Id id = entry.getKey();
writer.println();
writer.printf("| `%s`%n", id.groupId());
writer.printf("| `%s`%n", id.artifactId());
writer.printf("| `%s`%n", id.version());
writer.println(formatVersionProperties(entry.getValue()));
Comment on lines 90 to +93
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ResolvedBom.Id includes a classifier, but this task’s ordering/keying logic (and the generated table columns) ignore it. If the BOM contains managed dependencies that differ only by classifier (e.g., artifacts declared with classifier = 'jakarta'), they can be merged into a single row and the generated documentation will lose information or associate the wrong set of version properties. Consider either including classifier in the table (add a column) and in the map’s comparator, or normalizing/encoding classifier into the output so classifier-specific coordinates remain distinct.

Copilot uses AI. Check for mistakes.
}
writer.println("|===");
}
}

private Set<Id> process(ResolvedBom resolvedBom) {
TreeSet<Id> managedCoordinates = new TreeSet<>();
private void process(ResolvedBom resolvedBom, Map<Id, Set<String>> managedCoordinates) {
for (ResolvedLibrary library : resolvedBom.libraries()) {
for (Id managedDependency : library.managedDependencies()) {
managedCoordinates.add(managedDependency);
}
String versionProperty = library.versionProperty();
addManagedDependencies(managedCoordinates, versionProperty, library.managedDependencies());
for (Bom importedBom : library.importedBoms()) {
managedCoordinates.addAll(process(importedBom));
process(importedBom, managedCoordinates, versionProperty);
}
}
return managedCoordinates;
}

private Set<Id> process(Bom bom) {
TreeSet<Id> managedCoordinates = new TreeSet<>();
bom.managedDependencies().stream().forEach(managedCoordinates::add);
private void process(Bom bom, Map<Id, Set<String>> managedCoordinates, String versionProperty) {
addManagedDependencies(managedCoordinates, versionProperty, bom.managedDependencies());
for (Bom importedBom : bom.importedBoms()) {
process(importedBom, managedCoordinates, versionProperty);
}
Bom parent = bom.parent();
if (parent != null) {
managedCoordinates.addAll(process(parent));
process(parent, managedCoordinates, versionProperty);
}
}

private void addManagedDependencies(Map<Id, Set<String>> managedCoordinates, String versionProperty,
Collection<Id> managedDependencies) {
for (Id managedDependency : managedDependencies) {
Set<String> properties = managedCoordinates.computeIfAbsent(managedDependency, (id) -> new TreeSet<>());
if (versionProperty != null && !versionProperty.isBlank()) {
properties.add(versionProperty);
}
}
}

private String formatVersionProperties(Set<String> versionProperties) {
if (versionProperties.isEmpty()) {
return "|";
}
return managedCoordinates;
String formattedProperties = versionProperties.stream()
.map((property) -> "`%s`".formatted(property))
.collect(Collectors.joining(", "));
return "| " + formattedProperties;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@

The following table provides details of all of the dependency versions that are provided by Spring Boot in its CLI (Command Line Interface), Maven dependency management, and Gradle plugin.
When you declare a dependency on one of these artifacts without declaring a version, the version listed in the table is used.
The `Version Property` column shows the property or properties that can be used to override each managed version.
If a dependency does not have a dedicated version property, the column is empty.
See xref:appendix:dependency-versions/properties.adoc[Version Properties] for the list of available version properties.

include::partial$dependency-versions/documented-coordinates.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
= Version Properties

The following table provides all properties that can be used to override the versions managed by Spring Boot.
See xref:appendix:dependency-versions/coordinates.adoc[Managed Dependency Coordinates] for the dependencies that each
property can influence.
Browse the {code-spring-boot}/platform/spring-boot-dependencies/build.gradle[`spring-boot-dependencies` build.gradle] for a complete list of dependencies.
You can learn how to customize these versions in your application in the xref:build-tool-plugin:index.adoc[] documentation.

Expand Down