From 1047c2158a094bd78bea8c8ddc39e6a3afcd3aa3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 25 Mar 2025 16:28:27 +0000 Subject: [PATCH] Use resolved bom as source of javadoc links Closes gh-44878 --- .../boot/build/bom/BomResolver.java | 15 +++- .../boot/build/bom/CreateResolvedBom.java | 6 +- .../boot/build/bom/ResolvedBom.java | 11 ++- .../build/docs/ConfigureJavadocLinks.java | 72 +++++++++++++++++++ .../spring-boot-docs/build.gradle | 22 +----- 5 files changed, 102 insertions(+), 24 deletions(-) create mode 100644 buildSrc/src/main/java/org/springframework/boot/build/docs/ConfigureJavadocLinks.java diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomResolver.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomResolver.java index 93b86c88a86..b195b9f0487 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomResolver.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomResolver.java @@ -17,7 +17,9 @@ package org.springframework.boot.build.bom; import java.io.File; +import java.net.URI; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,9 +42,12 @@ import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.springframework.boot.build.bom.Library.Group; +import org.springframework.boot.build.bom.Library.Link; import org.springframework.boot.build.bom.Library.Module; import org.springframework.boot.build.bom.ResolvedBom.Bom; import org.springframework.boot.build.bom.ResolvedBom.Id; +import org.springframework.boot.build.bom.ResolvedBom.JavadocLink; +import org.springframework.boot.build.bom.ResolvedBom.Links; import org.springframework.boot.build.bom.ResolvedBom.ResolvedLibrary; /** @@ -85,15 +90,23 @@ class BomResolver { imports.add(bom); } } + List javadocLinks = javadocLinksOf(library).stream() + .map((link) -> new JavadocLink(URI.create(link.url(library)), link.packages())) + .toList(); ResolvedLibrary resolvedLibrary = new ResolvedLibrary(library.getName(), library.getVersion().getVersion().toString(), library.getVersionProperty(), managedDependencies, - imports); + imports, new Links(javadocLinks)); libraries.add(resolvedLibrary); } String[] idComponents = bomExtension.getId().split(":"); return new ResolvedBom(new Id(idComponents[0], idComponents[1], idComponents[2]), libraries); } + private List javadocLinksOf(Library library) { + List javadocLinks = library.getLinks("javadoc"); + return (javadocLinks != null) ? javadocLinks : Collections.emptyList(); + } + Bom resolveMavenBom(String coordinates) { return bomFrom(resolveBom(coordinates)); } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/CreateResolvedBom.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/CreateResolvedBom.java index 468e5ca30ee..5dd62a0e102 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/CreateResolvedBom.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/CreateResolvedBom.java @@ -49,10 +49,10 @@ public abstract class CreateResolvedBom extends DefaultTask { public abstract RegularFileProperty getOutputFile(); @TaskAction - void describeDependencyManagement() throws IOException { - ResolvedBom dependencyManagement = this.bomResolver.resolve(this.bomExtension); + void createResolvedBom() throws IOException { + ResolvedBom resolvedBom = this.bomResolver.resolve(this.bomExtension); try (FileWriter writer = new FileWriter(getOutputFile().get().getAsFile())) { - dependencyManagement.writeTo(writer); + resolvedBom.writeTo(writer); } } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/ResolvedBom.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/ResolvedBom.java index 3fa12f72741..6a4e6f2b9dc 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/ResolvedBom.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/ResolvedBom.java @@ -21,6 +21,7 @@ import java.io.FileReader; import java.io.IOException; import java.io.UncheckedIOException; import java.io.Writer; +import java.net.URI; import java.util.List; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -66,7 +67,7 @@ public record ResolvedBom(Id id, List libraries) { } public record ResolvedLibrary(String name, String version, String versionProperty, List managedDependencies, - List importedBoms) { + List importedBoms, Links links) { } @@ -109,4 +110,12 @@ public record ResolvedBom(Id id, List libraries) { } + public record Links(List javadoc) { + + } + + public record JavadocLink(URI uri, List packages) { + + } + } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/docs/ConfigureJavadocLinks.java b/buildSrc/src/main/java/org/springframework/boot/build/docs/ConfigureJavadocLinks.java new file mode 100644 index 00000000000..9f9bb13a394 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/boot/build/docs/ConfigureJavadocLinks.java @@ -0,0 +1,72 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.build.docs; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.gradle.api.Action; +import org.gradle.api.file.FileCollection; +import org.gradle.api.tasks.javadoc.Javadoc; +import org.gradle.external.javadoc.StandardJavadocDocletOptions; + +import org.springframework.boot.build.bom.ResolvedBom; +import org.springframework.boot.build.bom.ResolvedBom.JavadocLink; + +/** + * An {@link Action} to configure the links option of a {@link Javadoc} task. + * + * @author Andy Wilkinson + */ +public class ConfigureJavadocLinks implements Action { + + private final FileCollection resolvedBoms; + + private final Collection includedLibraries; + + public ConfigureJavadocLinks(FileCollection resolvedBoms, Collection includedLibraries) { + this.resolvedBoms = resolvedBoms; + this.includedLibraries = includedLibraries; + } + + @Override + public void execute(Javadoc javadoc) { + javadoc.options((options) -> { + if (options instanceof StandardJavadocDocletOptions standardOptions) { + configureLinks(standardOptions); + } + }); + } + + private void configureLinks(StandardJavadocDocletOptions options) { + ResolvedBom resolvedBom = ResolvedBom.readFrom(this.resolvedBoms.getSingleFile()); + List links = new ArrayList<>(); + links.add("https://docs.oracle.com/en/java/javase/17/docs/api/"); + links.add("https://jakarta.ee/specifications/platform/9/apidocs/"); + resolvedBom.libraries() + .stream() + .filter((candidate) -> this.includedLibraries.contains(candidate.name())) + .flatMap((library) -> library.links().javadoc().stream()) + .map(JavadocLink::uri) + .map(URI::toString) + .forEach(links::add); + options.setLinks(links); + } + +} diff --git a/spring-boot-project/spring-boot-docs/build.gradle b/spring-boot-project/spring-boot-docs/build.gradle index 0d5db463b6b..a1f750d8abe 100644 --- a/spring-boot-project/spring-boot-docs/build.gradle +++ b/spring-boot-project/spring-boot-docs/build.gradle @@ -1,3 +1,5 @@ +import org.springframework.boot.build.docs.ConfigureJavadocLinks + plugins { id "dev.adamko.dokkatoo-html" id "java" @@ -200,7 +202,6 @@ dokkatoo { } task aggregatedJavadoc(type: Javadoc) { - dependsOn dependencyVersions project.rootProject.gradle.projectsEvaluated { Set publishedProjects = rootProject.subprojects.findAll { it != project } .findAll { it.plugins.hasPlugin(JavaPlugin) && it.plugins.hasPlugin(MavenPublishPlugin) } @@ -222,24 +223,7 @@ task aggregatedJavadoc(type: Javadoc) { use = true windowTitle = "Spring Boot ${project.version} API" } - doFirst { - def versionConstraints = dependencyVersions.versionConstraints - def toMajorMinorVersion = version -> { - String formatted = version.split("\\.").take(2).join('.') + '.x' - return version.endsWith("-SNAPSHOT") ? formatted + "-SNAPSHOT" : formatted - } - def springFrameworkVersion = toMajorMinorVersion(versionConstraints["org.springframework:spring-core"]) - def springSecurityVersion = toMajorMinorVersion(versionConstraints["org.springframework.security:spring-security-core"]) - def tomcatVersion = "${versionConstraints["org.apache.tomcat:tomcat-annotations-api"]}" - def tomcatDocsVersion = tomcatVersion.substring(0, tomcatVersion.lastIndexOf(".")); - options.links = [ - "https://docs.oracle.com/en/java/javase/17/docs/api/", - "https://docs.spring.io/spring-framework/docs/${springFrameworkVersion}/javadoc-api/", - "https://docs.spring.io/spring-security/site/docs/${springSecurityVersion}/api/", - "https://jakarta.ee/specifications/platform/9/apidocs/", - "https://tomcat.apache.org/tomcat-${tomcatDocsVersion}-doc/api/", - ] as String[] - } + doFirst(new ConfigureJavadocLinks(configurations.resolvedBom, ["Spring Framework", "Spring Security", "Tomcat"])) } }