Merge branch '3.0.x'

pull/34342/head
Phillip Webb 2 years ago
commit b07269a018

@ -72,8 +72,9 @@ class AsciidoctorConventions {
makeAllWarningsFatal(project); makeAllWarningsFatal(project);
upgradeAsciidoctorJVersion(project); upgradeAsciidoctorJVersion(project);
createAsciidoctorExtensionsConfiguration(project); createAsciidoctorExtensionsConfiguration(project);
project.getTasks().withType(AbstractAsciidoctorTask.class, project.getTasks()
(asciidoctorTask) -> configureAsciidoctorTask(project, asciidoctorTask)); .withType(AbstractAsciidoctorTask.class,
(asciidoctorTask) -> configureAsciidoctorTask(project, asciidoctorTask));
}); });
} }
@ -87,12 +88,14 @@ class AsciidoctorConventions {
private void createAsciidoctorExtensionsConfiguration(Project project) { private void createAsciidoctorExtensionsConfiguration(Project project) {
project.getConfigurations().create(EXTENSIONS_CONFIGURATION_NAME, (configuration) -> { project.getConfigurations().create(EXTENSIONS_CONFIGURATION_NAME, (configuration) -> {
project.getConfigurations().matching((candidate) -> "dependencyManagement".equals(candidate.getName())) project.getConfigurations()
.all(configuration::extendsFrom); .matching((candidate) -> "dependencyManagement".equals(candidate.getName()))
configuration.getDependencies().add(project.getDependencies() .all(configuration::extendsFrom);
configuration.getDependencies()
.add(project.getDependencies()
.create("io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.4")); .create("io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.4"));
configuration.getDependencies() configuration.getDependencies()
.add(project.getDependencies().create("org.asciidoctor:asciidoctorj-pdf:1.5.3")); .add(project.getDependencies().create("org.asciidoctor:asciidoctorj-pdf:1.5.3"));
}); });
} }
@ -140,13 +143,15 @@ class AsciidoctorConventions {
private Sync createSyncDocumentationSourceTask(Project project, AbstractAsciidoctorTask asciidoctorTask) { private Sync createSyncDocumentationSourceTask(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Sync syncDocumentationSource = project.getTasks() Sync syncDocumentationSource = project.getTasks()
.create("syncDocumentationSourceFor" + StringUtils.capitalize(asciidoctorTask.getName()), Sync.class); .create("syncDocumentationSourceFor" + StringUtils.capitalize(asciidoctorTask.getName()), Sync.class);
File syncedSource = new File(project.getBuildDir(), "docs/src/" + asciidoctorTask.getName()); File syncedSource = new File(project.getBuildDir(), "docs/src/" + asciidoctorTask.getName());
syncDocumentationSource.setDestinationDir(syncedSource); syncDocumentationSource.setDestinationDir(syncedSource);
syncDocumentationSource.from("src/docs/"); syncDocumentationSource.from("src/docs/");
asciidoctorTask.dependsOn(syncDocumentationSource); asciidoctorTask.dependsOn(syncDocumentationSource);
asciidoctorTask.getInputs().dir(syncedSource).withPathSensitivity(PathSensitivity.RELATIVE) asciidoctorTask.getInputs()
.withPropertyName("synced source"); .dir(syncedSource)
.withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("synced source");
asciidoctorTask.setSourceDir(project.relativePath(new File(syncedSource, "asciidoc/"))); asciidoctorTask.setSourceDir(project.relativePath(new File(syncedSource, "asciidoc/")));
return syncDocumentationSource; return syncDocumentationSource;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -46,12 +46,16 @@ public class DeployedPlugin implements Plugin<Project> {
MavenPublication mavenPublication = publishing.getPublications().create("maven", MavenPublication.class); MavenPublication mavenPublication = publishing.getPublications().create("maven", MavenPublication.class);
project.afterEvaluate((evaluated) -> project.getPlugins().withType(JavaPlugin.class).all((javaPlugin) -> { project.afterEvaluate((evaluated) -> project.getPlugins().withType(JavaPlugin.class).all((javaPlugin) -> {
if (((Jar) project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME)).isEnabled()) { if (((Jar) project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME)).isEnabled()) {
project.getComponents().matching((component) -> component.getName().equals("java")) project.getComponents()
.all(mavenPublication::from); .matching((component) -> component.getName().equals("java"))
.all(mavenPublication::from);
} }
})); }));
project.getPlugins().withType(JavaPlatformPlugin.class).all((javaPlugin) -> project.getComponents() project.getPlugins()
.matching((component) -> component.getName().equals("javaPlatform")).all(mavenPublication::from)); .withType(JavaPlatformPlugin.class)
.all((javaPlugin) -> project.getComponents()
.matching((component) -> component.getName().equals("javaPlatform"))
.all(mavenPublication::from));
} }
} }

@ -121,16 +121,18 @@ class JavaConventions {
} }
private void configureJarManifestConventions(Project project) { private void configureJarManifestConventions(Project project) {
ExtractResources extractLegalResources = project.getTasks().create("extractLegalResources", ExtractResources extractLegalResources = project.getTasks()
ExtractResources.class); .create("extractLegalResources", ExtractResources.class);
extractLegalResources.getDestinationDirectory().set(project.getLayout().getBuildDirectory().dir("legal")); extractLegalResources.getDestinationDirectory().set(project.getLayout().getBuildDirectory().dir("legal"));
extractLegalResources.setResourcesNames(Arrays.asList("LICENSE.txt", "NOTICE.txt")); extractLegalResources.setResourcesNames(Arrays.asList("LICENSE.txt", "NOTICE.txt"));
extractLegalResources.property("version", project.getVersion().toString()); extractLegalResources.property("version", project.getVersion().toString());
SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class); SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
Set<String> sourceJarTaskNames = sourceSets.stream().map(SourceSet::getSourcesJarTaskName) Set<String> sourceJarTaskNames = sourceSets.stream()
.collect(Collectors.toSet()); .map(SourceSet::getSourcesJarTaskName)
Set<String> javadocJarTaskNames = sourceSets.stream().map(SourceSet::getJavadocJarTaskName) .collect(Collectors.toSet());
.collect(Collectors.toSet()); Set<String> javadocJarTaskNames = sourceSets.stream()
.map(SourceSet::getJavadocJarTaskName)
.collect(Collectors.toSet());
project.getTasks().withType(Jar.class, (jar) -> project.afterEvaluate((evaluated) -> { project.getTasks().withType(Jar.class, (jar) -> project.afterEvaluate((evaluated) -> {
jar.metaInf((metaInf) -> metaInf.from(extractLegalResources)); jar.metaInf((metaInf) -> metaInf.from(extractLegalResources));
jar.manifest((manifest) -> { jar.manifest((manifest) -> {
@ -167,7 +169,8 @@ class JavaConventions {
testRetry.getFailOnPassedAfterRetry().set(true); testRetry.getFailOnPassedAfterRetry().set(true);
testRetry.getMaxRetries().set(isCi() ? 3 : 0); testRetry.getMaxRetries().set(isCi() ? 3 : 0);
}); });
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> project.getDependencies() project.getPlugins()
.withType(JavaPlugin.class, (javaPlugin) -> project.getDependencies()
.add(JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME, "org.junit.platform:junit-platform-launcher")); .add(JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME, "org.junit.platform:junit-platform-launcher"));
} }
@ -220,7 +223,7 @@ class JavaConventions {
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion(); String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies(); DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
checkstyleDependencies checkstyleDependencies
.add(project.getDependencies().create("io.spring.javaformat:spring-javaformat-checkstyle:" + version)); .add(project.getDependencies().create("io.spring.javaformat:spring-javaformat-checkstyle:" + version));
} }
private void configureDependencyManagement(Project project) { private void configureDependencyManagement(Project project) {
@ -231,14 +234,18 @@ class JavaConventions {
configuration.setCanBeResolved(false); configuration.setCanBeResolved(false);
}); });
configurations configurations
.matching((configuration) -> configuration.getName().endsWith("Classpath") .matching((configuration) -> configuration.getName().endsWith("Classpath")
|| JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME.equals(configuration.getName())) || JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME.equals(configuration.getName()))
.all((configuration) -> configuration.extendsFrom(dependencyManagement)); .all((configuration) -> configuration.extendsFrom(dependencyManagement));
Dependency springBootParent = project.getDependencies().enforcedPlatform(project.getDependencies() Dependency springBootParent = project.getDependencies()
.enforcedPlatform(project.getDependencies()
.project(Collections.singletonMap("path", ":spring-boot-project:spring-boot-parent"))); .project(Collections.singletonMap("path", ":spring-boot-project:spring-boot-parent")));
dependencyManagement.getDependencies().add(springBootParent); dependencyManagement.getDependencies().add(springBootParent);
project.getPlugins().withType(OptionalDependenciesPlugin.class, (optionalDependencies) -> configurations project.getPlugins()
.getByName(OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME).extendsFrom(dependencyManagement)); .withType(OptionalDependenciesPlugin.class,
(optionalDependencies) -> configurations
.getByName(OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME)
.extendsFrom(dependencyManagement));
} }
private void configureToolchain(Project project) { private void configureToolchain(Project project) {
@ -260,9 +267,9 @@ class JavaConventions {
} }
private void createProhibitedDependenciesCheck(Configuration classpath, Project project) { private void createProhibitedDependenciesCheck(Configuration classpath, Project project) {
CheckClasspathForProhibitedDependencies checkClasspathForProhibitedDependencies = project.getTasks().create( CheckClasspathForProhibitedDependencies checkClasspathForProhibitedDependencies = project.getTasks()
"check" + StringUtils.capitalize(classpath.getName() + "ForProhibitedDependencies"), .create("check" + StringUtils.capitalize(classpath.getName() + "ForProhibitedDependencies"),
CheckClasspathForProhibitedDependencies.class); CheckClasspathForProhibitedDependencies.class);
checkClasspathForProhibitedDependencies.setClasspath(classpath); checkClasspathForProhibitedDependencies.setClasspath(classpath);
project.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkClasspathForProhibitedDependencies); project.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkClasspathForProhibitedDependencies);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -44,8 +44,9 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile;
class KotlinConventions { class KotlinConventions {
void apply(Project project) { void apply(Project project) {
project.getPlugins().withId("org.jetbrains.kotlin.jvm", project.getPlugins()
(plugin) -> project.getTasks().withType(KotlinCompile.class, this::configure)); .withId("org.jetbrains.kotlin.jvm",
(plugin) -> project.getTasks().withType(KotlinCompile.class, this::configure));
} }
private void configure(KotlinCompile compile) { private void configure(KotlinCompile compile) {

@ -67,8 +67,9 @@ class MavenPublishingConventions {
mavenRepository.setName("deployment"); mavenRepository.setName("deployment");
}); });
} }
publishing.getPublications().withType(MavenPublication.class) publishing.getPublications()
.all((mavenPublication) -> customizeMavenPublication(mavenPublication, project)); .withType(MavenPublication.class)
.all((mavenPublication) -> customizeMavenPublication(mavenPublication, project));
project.getPlugins().withType(JavaPlugin.class).all((javaPlugin) -> { project.getPlugins().withType(JavaPlugin.class).all((javaPlugin) -> {
JavaPluginExtension extension = project.getExtensions().getByType(JavaPluginExtension.class); JavaPluginExtension extension = project.getExtensions().getByType(JavaPluginExtension.class);
extension.withJavadocJar(); extension.withJavadocJar();
@ -79,8 +80,9 @@ class MavenPublishingConventions {
private void customizeMavenPublication(MavenPublication publication, Project project) { private void customizeMavenPublication(MavenPublication publication, Project project) {
customizePom(publication.getPom(), project); customizePom(publication.getPom(), project);
project.getPlugins().withType(JavaPlugin.class) project.getPlugins()
.all((javaPlugin) -> customizeJavaMavenPublication(publication, project)); .withType(JavaPlugin.class)
.all((javaPlugin) -> customizeJavaMavenPublication(publication, project));
suppressMavenOptionalFeatureWarnings(publication); suppressMavenOptionalFeatureWarnings(publication);
} }
@ -102,7 +104,7 @@ class MavenPublishingConventions {
private void customizeJavaMavenPublication(MavenPublication publication, Project project) { private void customizeJavaMavenPublication(MavenPublication publication, Project project) {
addMavenOptionalFeature(project); addMavenOptionalFeature(project);
publication.versionMapping((strategy) -> strategy.usage(Usage.JAVA_API, (mappingStrategy) -> mappingStrategy publication.versionMapping((strategy) -> strategy.usage(Usage.JAVA_API, (mappingStrategy) -> mappingStrategy
.fromResolutionOf(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME))); .fromResolutionOf(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)));
publication.versionMapping( publication.versionMapping(
(strategy) -> strategy.usage(Usage.JAVA_RUNTIME, VariantVersionMappingStrategy::fromResolutionResult)); (strategy) -> strategy.usage(Usage.JAVA_RUNTIME, VariantVersionMappingStrategy::fromResolutionResult));
} }
@ -117,7 +119,7 @@ class MavenPublishingConventions {
extension.registerFeature("mavenOptional", extension.registerFeature("mavenOptional",
(feature) -> feature.usingSourceSet(extension.getSourceSets().getByName("main"))); (feature) -> feature.usingSourceSet(extension.getSourceSets().getByName("main")));
AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.getComponents() AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.getComponents()
.findByName("java"); .findByName("java");
javaComponent.addVariantsFromConfiguration( javaComponent.addVariantsFromConfiguration(
project.getConfigurations().findByName("mavenOptionalRuntimeElements"), project.getConfigurations().findByName("mavenOptionalRuntimeElements"),
ConfigurationVariantDetails::mapToOptional); ConfigurationVariantDetails::mapToOptional);

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -61,36 +61,45 @@ public class MavenRepositoryPlugin implements Plugin<Project> {
mavenRepository.setName("project"); mavenRepository.setName("project");
mavenRepository.setUrl(repositoryLocation.toURI()); mavenRepository.setUrl(repositoryLocation.toURI());
}); });
project.getTasks().matching((task) -> task.getName().equals(PUBLISH_TO_PROJECT_REPOSITORY_TASK_NAME)) project.getTasks()
.all((task) -> setUpProjectRepository(project, task, repositoryLocation)); .matching((task) -> task.getName().equals(PUBLISH_TO_PROJECT_REPOSITORY_TASK_NAME))
project.getTasks().matching((task) -> task.getName().equals("publishPluginMavenPublicationToProjectRepository")) .all((task) -> setUpProjectRepository(project, task, repositoryLocation));
.all((task) -> setUpProjectRepository(project, task, repositoryLocation)); project.getTasks()
.matching((task) -> task.getName().equals("publishPluginMavenPublicationToProjectRepository"))
.all((task) -> setUpProjectRepository(project, task, repositoryLocation));
} }
private void setUpProjectRepository(Project project, Task publishTask, File repositoryLocation) { private void setUpProjectRepository(Project project, Task publishTask, File repositoryLocation) {
publishTask.doFirst(new CleanAction(repositoryLocation)); publishTask.doFirst(new CleanAction(repositoryLocation));
Configuration projectRepository = project.getConfigurations().create(MAVEN_REPOSITORY_CONFIGURATION_NAME); Configuration projectRepository = project.getConfigurations().create(MAVEN_REPOSITORY_CONFIGURATION_NAME);
project.getArtifacts().add(projectRepository.getName(), repositoryLocation, project.getArtifacts()
(artifact) -> artifact.builtBy(publishTask)); .add(projectRepository.getName(), repositoryLocation, (artifact) -> artifact.builtBy(publishTask));
DependencySet target = projectRepository.getDependencies(); DependencySet target = projectRepository.getDependencies();
project.getPlugins().withType(JavaPlugin.class).all((javaPlugin) -> addMavenRepositoryDependencies(project, project.getPlugins()
JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, target)); .withType(JavaPlugin.class)
project.getPlugins().withType(JavaLibraryPlugin.class) .all((javaPlugin) -> addMavenRepositoryDependencies(project, JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME,
.all((javaLibraryPlugin) -> addMavenRepositoryDependencies(project, JavaPlugin.API_CONFIGURATION_NAME, target));
target)); project.getPlugins()
project.getPlugins().withType(JavaPlatformPlugin.class) .withType(JavaLibraryPlugin.class)
.all((javaPlugin) -> addMavenRepositoryDependencies(project, JavaPlatformPlugin.API_CONFIGURATION_NAME, .all((javaLibraryPlugin) -> addMavenRepositoryDependencies(project, JavaPlugin.API_CONFIGURATION_NAME,
target)); target));
project.getPlugins()
.withType(JavaPlatformPlugin.class)
.all((javaPlugin) -> addMavenRepositoryDependencies(project, JavaPlatformPlugin.API_CONFIGURATION_NAME,
target));
} }
private void addMavenRepositoryDependencies(Project project, String sourceConfigurationName, DependencySet target) { private void addMavenRepositoryDependencies(Project project, String sourceConfigurationName, DependencySet target) {
project.getConfigurations().getByName(sourceConfigurationName).getDependencies() project.getConfigurations()
.withType(ProjectDependency.class).all((dependency) -> { .getByName(sourceConfigurationName)
Map<String, String> dependencyDescriptor = new HashMap<>(); .getDependencies()
dependencyDescriptor.put("path", dependency.getDependencyProject().getPath()); .withType(ProjectDependency.class)
dependencyDescriptor.put("configuration", MAVEN_REPOSITORY_CONFIGURATION_NAME); .all((dependency) -> {
target.add(project.getDependencies().project(dependencyDescriptor)); Map<String, String> dependencyDescriptor = new HashMap<>();
}); dependencyDescriptor.put("path", dependency.getDependencyProject().getPath());
dependencyDescriptor.put("configuration", MAVEN_REPOSITORY_CONFIGURATION_NAME);
target.add(project.getDependencies().project(dependencyDescriptor));
});
} }
private static final class CleanAction implements Action<Task> { private static final class CleanAction implements Action<Task> {

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2021 the original author or authors. * Copyright 2021-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -44,7 +44,7 @@ public class SyncAppSource extends DefaultTask {
this.sourceDirectory = objects.directoryProperty(); this.sourceDirectory = objects.directoryProperty();
this.destinationDirectory = objects.directoryProperty(); this.destinationDirectory = objects.directoryProperty();
this.pluginVersion = objects.property(String.class) this.pluginVersion = objects.property(String.class)
.convention(getProject().provider(() -> getProject().getVersion().toString())); .convention(getProject().provider(() -> getProject().getVersion().toString()));
} }
@TaskAction @TaskAction

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -46,14 +46,14 @@ public class ArchitecturePlugin implements Plugin<Project> {
JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class); JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);
List<TaskProvider<PackageTangleCheck>> packageTangleChecks = new ArrayList<>(); List<TaskProvider<PackageTangleCheck>> packageTangleChecks = new ArrayList<>();
for (SourceSet sourceSet : javaPluginExtension.getSourceSets()) { for (SourceSet sourceSet : javaPluginExtension.getSourceSets()) {
TaskProvider<PackageTangleCheck> checkPackageTangles = project.getTasks().register( TaskProvider<PackageTangleCheck> checkPackageTangles = project.getTasks()
"checkForPackageTangles" + StringUtils.capitalize(sourceSet.getName()), PackageTangleCheck.class, .register("checkForPackageTangles" + StringUtils.capitalize(sourceSet.getName()),
(task) -> { PackageTangleCheck.class, (task) -> {
task.setClasses(sourceSet.getOutput().getClassesDirs()); task.setClasses(sourceSet.getOutput().getClassesDirs());
task.setDescription("Checks the classes of the " + sourceSet.getName() task.setDescription("Checks the classes of the " + sourceSet.getName()
+ " source set for package tangles."); + " source set for package tangles.");
task.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP); task.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
}); });
packageTangleChecks.add(checkPackageTangles); packageTangleChecks.add(checkPackageTangles);
} }
if (!packageTangleChecks.isEmpty()) { if (!packageTangleChecks.isEmpty()) {

@ -61,7 +61,7 @@ public abstract class PackageTangleCheck extends DefaultTask {
@TaskAction @TaskAction
void checkForPackageTangles() throws IOException { void checkForPackageTangles() throws IOException {
JavaClasses javaClasses = new ClassFileImporter() JavaClasses javaClasses = new ClassFileImporter()
.importPaths(this.classes.getFiles().stream().map(File::toPath).collect(Collectors.toList())); .importPaths(this.classes.getFiles().stream().map(File::toPath).collect(Collectors.toList()));
SliceRule freeOfCycles = SlicesRuleDefinition.slices().matching("(**)").should().beFreeOfCycles(); SliceRule freeOfCycles = SlicesRuleDefinition.slices().matching("(**)").should().beFreeOfCycles();
EvaluationResult result = freeOfCycles.evaluate(javaClasses); EvaluationResult result = freeOfCycles.evaluate(javaClasses);
File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile(); File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -58,14 +58,14 @@ public class AutoConfigurationMetadata extends DefaultTask {
public AutoConfigurationMetadata() { public AutoConfigurationMetadata() {
getInputs() getInputs()
.file((Callable<File>) () -> new File(this.sourceSet.getOutput().getResourcesDir(), .file((Callable<File>) () -> new File(this.sourceSet.getOutput().getResourcesDir(),
"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports")) "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports"))
.withPathSensitivity(PathSensitivity.RELATIVE) .withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("org.springframework.boot.autoconfigure.AutoConfiguration"); .withPropertyName("org.springframework.boot.autoconfigure.AutoConfiguration");
dependsOn((Callable<String>) () -> this.sourceSet.getProcessResourcesTaskName()); dependsOn((Callable<String>) () -> this.sourceSet.getProcessResourcesTaskName());
getProject().getConfigurations() getProject().getConfigurations()
.maybeCreate(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME); .maybeCreate(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME);
} }
public void setSourceSet(SourceSet sourceSet) { public void setSourceSet(SourceSet sourceSet) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -58,21 +58,27 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> { project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
project.getPlugins().apply(ConfigurationPropertiesPlugin.class); project.getPlugins().apply(ConfigurationPropertiesPlugin.class);
Configuration annotationProcessors = project.getConfigurations() Configuration annotationProcessors = project.getConfigurations()
.getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME); .getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME);
annotationProcessors.getDependencies() annotationProcessors.getDependencies()
.add(project.getDependencies().project(Collections.singletonMap("path", .add(project.getDependencies()
.project(Collections.singletonMap("path",
":spring-boot-project:spring-boot-tools:spring-boot-autoconfigure-processor"))); ":spring-boot-project:spring-boot-tools:spring-boot-autoconfigure-processor")));
annotationProcessors.getDependencies() annotationProcessors.getDependencies()
.add(project.getDependencies().project(Collections.singletonMap("path", .add(project.getDependencies()
.project(Collections.singletonMap("path",
":spring-boot-project:spring-boot-tools:spring-boot-configuration-processor"))); ":spring-boot-project:spring-boot-tools:spring-boot-configuration-processor")));
project.getTasks().create("autoConfigurationMetadata", AutoConfigurationMetadata.class, (task) -> { project.getTasks().create("autoConfigurationMetadata", AutoConfigurationMetadata.class, (task) -> {
SourceSet main = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets() SourceSet main = project.getExtensions()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME); .getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
task.setSourceSet(main); task.setSourceSet(main);
task.dependsOn(main.getClassesTaskName()); task.dependsOn(main.getClassesTaskName());
task.setOutputFile(new File(project.getBuildDir(), "auto-configuration-metadata.properties")); task.setOutputFile(new File(project.getBuildDir(), "auto-configuration-metadata.properties"));
project.getArtifacts().add(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME, project.getArtifacts()
project.provider((Callable<File>) task::getOutputFile), (artifact) -> artifact.builtBy(task)); .add(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME,
project.provider((Callable<File>) task::getOutputFile),
(artifact) -> artifact.builtBy(task));
}); });
}); });
} }

@ -125,39 +125,41 @@ public class BomExtension {
public void effectiveBomArtifact() { public void effectiveBomArtifact() {
Configuration effectiveBomConfiguration = this.project.getConfigurations().create("effectiveBom"); Configuration effectiveBomConfiguration = this.project.getConfigurations().create("effectiveBom");
this.project.getTasks().matching((task) -> task.getName().equals(DeployedPlugin.GENERATE_POM_TASK_NAME)) this.project.getTasks()
.all((task) -> { .matching((task) -> task.getName().equals(DeployedPlugin.GENERATE_POM_TASK_NAME))
Sync syncBom = this.project.getTasks().create("syncBom", Sync.class); .all((task) -> {
syncBom.dependsOn(task); Sync syncBom = this.project.getTasks().create("syncBom", Sync.class);
File generatedBomDir = new File(this.project.getBuildDir(), "generated/bom"); syncBom.dependsOn(task);
syncBom.setDestinationDir(generatedBomDir); File generatedBomDir = new File(this.project.getBuildDir(), "generated/bom");
syncBom.from(((GenerateMavenPom) task).getDestination(), (pom) -> pom.rename((name) -> "pom.xml")); syncBom.setDestinationDir(generatedBomDir);
try { syncBom.from(((GenerateMavenPom) task).getDestination(), (pom) -> pom.rename((name) -> "pom.xml"));
String settingsXmlContent = FileCopyUtils try {
.copyToString(new InputStreamReader( String settingsXmlContent = FileCopyUtils
getClass().getClassLoader().getResourceAsStream("effective-bom-settings.xml"), .copyToString(new InputStreamReader(
StandardCharsets.UTF_8)) getClass().getClassLoader().getResourceAsStream("effective-bom-settings.xml"),
.replace("localRepositoryPath", StandardCharsets.UTF_8))
new File(this.project.getBuildDir(), "local-m2-repository").getAbsolutePath()); .replace("localRepositoryPath",
syncBom.from(this.project.getResources().getText().fromString(settingsXmlContent), new File(this.project.getBuildDir(), "local-m2-repository").getAbsolutePath());
(settingsXml) -> settingsXml.rename((name) -> "settings.xml")); syncBom.from(this.project.getResources().getText().fromString(settingsXmlContent),
} (settingsXml) -> settingsXml.rename((name) -> "settings.xml"));
catch (IOException ex) { }
throw new GradleException("Failed to prepare settings.xml", ex); catch (IOException ex) {
} throw new GradleException("Failed to prepare settings.xml", ex);
MavenExec generateEffectiveBom = this.project.getTasks().create("generateEffectiveBom", }
MavenExec.class); MavenExec generateEffectiveBom = this.project.getTasks()
generateEffectiveBom.setProjectDir(generatedBomDir); .create("generateEffectiveBom", MavenExec.class);
File effectiveBom = new File(this.project.getBuildDir(), generateEffectiveBom.setProjectDir(generatedBomDir);
"generated/effective-bom/" + this.project.getName() + "-effective-bom.xml"); File effectiveBom = new File(this.project.getBuildDir(),
generateEffectiveBom.args("--settings", "settings.xml", "help:effective-pom", "generated/effective-bom/" + this.project.getName() + "-effective-bom.xml");
"-Doutput=" + effectiveBom); generateEffectiveBom.args("--settings", "settings.xml", "help:effective-pom",
generateEffectiveBom.dependsOn(syncBom); "-Doutput=" + effectiveBom);
generateEffectiveBom.getOutputs().file(effectiveBom); generateEffectiveBom.dependsOn(syncBom);
generateEffectiveBom.doLast(new StripUnrepeatableOutputAction(effectiveBom)); generateEffectiveBom.getOutputs().file(effectiveBom);
this.project.getArtifacts().add(effectiveBomConfiguration.getName(), effectiveBom, generateEffectiveBom.doLast(new StripUnrepeatableOutputAction(effectiveBom));
this.project.getArtifacts()
.add(effectiveBomConfiguration.getName(), effectiveBom,
(artifact) -> artifact.builtBy(generateEffectiveBom)); (artifact) -> artifact.builtBy(generateEffectiveBom));
}); });
} }
private String createDependencyNotation(String groupId, String artifactId, DependencyVersion version) { private String createDependencyNotation(String groupId, String artifactId, DependencyVersion version) {
@ -196,8 +198,9 @@ public class BomExtension {
for (Group group : library.getGroups()) { for (Group group : library.getGroups()) {
for (Module module : group.getModules()) { for (Module module : group.getModules()) {
putArtifactVersionProperty(group.getId(), module.getName(), module.getClassifier(), versionProperty); putArtifactVersionProperty(group.getId(), module.getName(), module.getClassifier(), versionProperty);
this.dependencyHandler.getConstraints().add(JavaPlatformPlugin.API_CONFIGURATION_NAME, this.dependencyHandler.getConstraints()
createDependencyNotation(group.getId(), module.getName(), library.getVersion().getVersion())); .add(JavaPlatformPlugin.API_CONFIGURATION_NAME, createDependencyNotation(group.getId(),
module.getName(), library.getVersion().getVersion()));
} }
for (String bomImport : group.getBoms()) { for (String bomImport : group.getBoms()) {
putArtifactVersionProperty(group.getId(), bomImport, versionProperty); putArtifactVersionProperty(group.getId(), bomImport, versionProperty);
@ -242,7 +245,7 @@ public class BomExtension {
GroupHandler groupHandler = new GroupHandler(id); GroupHandler groupHandler = new GroupHandler(id);
action.execute(groupHandler); action.execute(groupHandler);
this.groups this.groups
.add(new Group(groupHandler.id, groupHandler.modules, groupHandler.plugins, groupHandler.imports)); .add(new Group(groupHandler.id, groupHandler.modules, groupHandler.plugins, groupHandler.imports));
} }
public void prohibit(Action<ProhibitedHandler> action) { public void prohibit(Action<ProhibitedHandler> action) {
@ -254,7 +257,7 @@ public class BomExtension {
public void dependencyVersions(Action<DependencyVersionsHandler> action) { public void dependencyVersions(Action<DependencyVersionsHandler> action) {
DependencyVersionsHandler dependencyVersionsHandler = this.objectFactory DependencyVersionsHandler dependencyVersionsHandler = this.objectFactory
.newInstance(DependencyVersionsHandler.class, this.version); .newInstance(DependencyVersionsHandler.class, this.version);
action.execute(dependencyVersionsHandler); action.execute(dependencyVersionsHandler);
this.dependencyVersions = dependencyVersionsHandler.dependencyVersions; this.dependencyVersions = dependencyVersionsHandler.dependencyVersions;
} }
@ -336,8 +339,8 @@ public class BomExtension {
public void setModules(List<Object> modules) { public void setModules(List<Object> modules) {
this.modules = modules.stream() this.modules = modules.stream()
.map((input) -> (input instanceof Module module) ? module : new Module((String) input)) .map((input) -> (input instanceof Module module) ? module : new Module((String) input))
.toList(); .toList();
} }
public void setImports(List<String> imports) { public void setImports(List<String> imports) {
@ -530,8 +533,9 @@ public class BomExtension {
org.w3c.dom.Node reporting = (org.w3c.dom.Node) xpath.evaluate("/project/reporting", document, org.w3c.dom.Node reporting = (org.w3c.dom.Node) xpath.evaluate("/project/reporting", document,
XPathConstants.NODE); XPathConstants.NODE);
reporting.getParentNode().removeChild(reporting); reporting.getParentNode().removeChild(reporting);
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), TransformerFactory.newInstance()
new StreamResult(this.effectiveBom)); .newTransformer()
.transform(new DOMSource(document), new StreamResult(this.effectiveBom));
} }
catch (Exception ex) { catch (Exception ex) {
throw new TaskExecutionException(task, ex); throw new TaskExecutionException(task, ex);

@ -60,8 +60,8 @@ public class BomPlugin implements Plugin<Project> {
JavaPlatformExtension javaPlatform = project.getExtensions().getByType(JavaPlatformExtension.class); JavaPlatformExtension javaPlatform = project.getExtensions().getByType(JavaPlatformExtension.class);
javaPlatform.allowDependencies(); javaPlatform.allowDependencies();
createApiEnforcedConfiguration(project); createApiEnforcedConfiguration(project);
BomExtension bom = project.getExtensions().create("bom", BomExtension.class, project.getDependencies(), BomExtension bom = project.getExtensions()
project); .create("bom", BomExtension.class, project.getDependencies(), project);
project.getTasks().create("bomrCheck", CheckBom.class, bom); project.getTasks().create("bomrCheck", CheckBom.class, bom);
project.getTasks().create("bomrUpgrade", UpgradeBom.class, bom); project.getTasks().create("bomrUpgrade", UpgradeBom.class, bom);
project.getTasks().create("moveToSnapshots", MoveToSnapshots.class, bom); project.getTasks().create("moveToSnapshots", MoveToSnapshots.class, bom);
@ -70,16 +70,18 @@ public class BomPlugin implements Plugin<Project> {
} }
private void createApiEnforcedConfiguration(Project project) { private void createApiEnforcedConfiguration(Project project) {
Configuration apiEnforced = project.getConfigurations().create(API_ENFORCED_CONFIGURATION_NAME, Configuration apiEnforced = project.getConfigurations()
(configuration) -> { .create(API_ENFORCED_CONFIGURATION_NAME, (configuration) -> {
configuration.setCanBeConsumed(false); configuration.setCanBeConsumed(false);
configuration.setCanBeResolved(false); configuration.setCanBeResolved(false);
configuration.setVisible(false); configuration.setVisible(false);
}); });
project.getConfigurations().getByName(JavaPlatformPlugin.ENFORCED_API_ELEMENTS_CONFIGURATION_NAME) project.getConfigurations()
.extendsFrom(apiEnforced); .getByName(JavaPlatformPlugin.ENFORCED_API_ELEMENTS_CONFIGURATION_NAME)
project.getConfigurations().getByName(JavaPlatformPlugin.ENFORCED_RUNTIME_ELEMENTS_CONFIGURATION_NAME) .extendsFrom(apiEnforced);
.extendsFrom(apiEnforced); project.getConfigurations()
.getByName(JavaPlatformPlugin.ENFORCED_RUNTIME_ELEMENTS_CONFIGURATION_NAME)
.extendsFrom(apiEnforced);
} }
private static final class PublishingCustomizer { private static final class PublishingCustomizer {
@ -155,16 +157,19 @@ public class BomPlugin implements Plugin<Project> {
for (Node dependency : findChildren(dependencies, "dependency")) { for (Node dependency : findChildren(dependencies, "dependency")) {
String groupId = findChild(dependency, "groupId").text(); String groupId = findChild(dependency, "groupId").text();
String artifactId = findChild(dependency, "artifactId").text(); String artifactId = findChild(dependency, "artifactId").text();
this.bom.getLibraries().stream().flatMap((library) -> library.getGroups().stream()) this.bom.getLibraries()
.filter((group) -> group.getId().equals(groupId)) .stream()
.flatMap((group) -> group.getModules().stream()) .flatMap((library) -> library.getGroups().stream())
.filter((module) -> module.getName().equals(artifactId)) .filter((group) -> group.getId().equals(groupId))
.flatMap((module) -> module.getExclusions().stream()).forEach((exclusion) -> { .flatMap((group) -> group.getModules().stream())
Node exclusions = findOrCreateNode(dependency, "exclusions"); .filter((module) -> module.getName().equals(artifactId))
Node node = new Node(exclusions, "exclusion"); .flatMap((module) -> module.getExclusions().stream())
node.appendNode("groupId", exclusion.getGroupId()); .forEach((exclusion) -> {
node.appendNode("artifactId", exclusion.getArtifactId()); Node exclusions = findOrCreateNode(dependency, "exclusions");
}); Node node = new Node(exclusions, "exclusion");
node.appendNode("groupId", exclusion.getGroupId());
node.appendNode("artifactId", exclusion.getArtifactId());
});
} }
} }
} }
@ -175,12 +180,15 @@ public class BomPlugin implements Plugin<Project> {
for (Node dependency : findChildren(dependencies, "dependency")) { for (Node dependency : findChildren(dependencies, "dependency")) {
String groupId = findChild(dependency, "groupId").text(); String groupId = findChild(dependency, "groupId").text();
String artifactId = findChild(dependency, "artifactId").text(); String artifactId = findChild(dependency, "artifactId").text();
Set<String> types = this.bom.getLibraries().stream() Set<String> types = this.bom.getLibraries()
.flatMap((library) -> library.getGroups().stream()) .stream()
.filter((group) -> group.getId().equals(groupId)) .flatMap((library) -> library.getGroups().stream())
.flatMap((group) -> group.getModules().stream()) .filter((group) -> group.getId().equals(groupId))
.filter((module) -> module.getName().equals(artifactId)).map(Module::getType) .flatMap((group) -> group.getModules().stream())
.filter(Objects::nonNull).collect(Collectors.toSet()); .filter((module) -> module.getName().equals(artifactId))
.map(Module::getType)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
if (types.size() > 1) { if (types.size() > 1) {
throw new IllegalStateException( throw new IllegalStateException(
"Multiple types for " + groupId + ":" + artifactId + ": " + types); "Multiple types for " + groupId + ":" + artifactId + ": " + types);
@ -201,12 +209,15 @@ public class BomPlugin implements Plugin<Project> {
String groupId = findChild(dependency, "groupId").text(); String groupId = findChild(dependency, "groupId").text();
String artifactId = findChild(dependency, "artifactId").text(); String artifactId = findChild(dependency, "artifactId").text();
String version = findChild(dependency, "version").text(); String version = findChild(dependency, "version").text();
Set<String> classifiers = this.bom.getLibraries().stream() Set<String> classifiers = this.bom.getLibraries()
.flatMap((library) -> library.getGroups().stream()) .stream()
.filter((group) -> group.getId().equals(groupId)) .flatMap((library) -> library.getGroups().stream())
.flatMap((group) -> group.getModules().stream()) .filter((group) -> group.getId().equals(groupId))
.filter((module) -> module.getName().equals(artifactId)).map(Module::getClassifier) .flatMap((group) -> group.getModules().stream())
.filter(Objects::nonNull).collect(Collectors.toSet()); .filter((module) -> module.getName().equals(artifactId))
.map(Module::getClassifier)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Node target = dependency; Node target = dependency;
for (String classifier : classifiers) { for (String classifier : classifiers) {
if (classifier.length() > 0) { if (classifier.length() > 0) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -59,14 +59,18 @@ public class CheckBom extends DefaultTask {
private void checkExclusions(String groupId, Module module, DependencyVersion version) { private void checkExclusions(String groupId, Module module, DependencyVersion version) {
Set<String> resolved = getProject().getConfigurations() Set<String> resolved = getProject().getConfigurations()
.detachedConfiguration( .detachedConfiguration(
getProject().getDependencies().create(groupId + ":" + module.getName() + ":" + version)) getProject().getDependencies().create(groupId + ":" + module.getName() + ":" + version))
.getResolvedConfiguration().getResolvedArtifacts().stream() .getResolvedConfiguration()
.map((artifact) -> artifact.getModuleVersion().getId()) .getResolvedArtifacts()
.map((id) -> id.getGroup() + ":" + id.getModule().getName()).collect(Collectors.toSet()); .stream()
Set<String> exclusions = module.getExclusions().stream() .map((artifact) -> artifact.getModuleVersion().getId())
.map((exclusion) -> exclusion.getGroupId() + ":" + exclusion.getArtifactId()) .map((id) -> id.getGroup() + ":" + id.getModule().getName())
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Set<String> exclusions = module.getExclusions()
.stream()
.map((exclusion) -> exclusion.getGroupId() + ":" + exclusion.getArtifactId())
.collect(Collectors.toSet());
Set<String> unused = new TreeSet<>(); Set<String> unused = new TreeSet<>();
for (String exclusion : exclusions) { for (String exclusion : exclusions) {
if (!resolved.contains(exclusion)) { if (!resolved.contains(exclusion)) {

@ -322,7 +322,7 @@ public class Library {
if (!line.startsWith("#")) { if (!line.startsWith("#")) {
String[] components = line.split(":"); String[] components = line.split(":");
Map<String, String> groupDependencies = this.dependencyVersions Map<String, String> groupDependencies = this.dependencyVersions
.computeIfAbsent(components[0], (key) -> new HashMap<>()); .computeIfAbsent(components[0], (key) -> new HashMap<>());
groupDependencies.put(components[1], components[2]); groupDependencies.put(components[1], components[2]);
} }
} }
@ -372,7 +372,7 @@ public class Library {
Matcher matcher = CONSTRAINT_PATTERN.matcher(line.trim()); Matcher matcher = CONSTRAINT_PATTERN.matcher(line.trim());
if (matcher.matches()) { if (matcher.matches()) {
Map<String, String> groupDependencies = this.dependencyVersions Map<String, String> groupDependencies = this.dependencyVersions
.computeIfAbsent(matcher.group(1), (key) -> new HashMap<>()); .computeIfAbsent(matcher.group(1), (key) -> new HashMap<>());
groupDependencies.put(matcher.group(2), matcher.group(3)); groupDependencies.put(matcher.group(2), matcher.group(3));
} }
} }

@ -50,7 +50,7 @@ public final class InteractiveUpgradeResolver implements UpgradeResolver {
librariesByName.put(library.getName(), library); librariesByName.put(library.getName(), library);
} }
List<LibraryWithVersionOptions> libraryUpdates = this.libraryUpdateResolver List<LibraryWithVersionOptions> libraryUpdates = this.libraryUpdateResolver
.findLibraryUpdates(librariesToUpgrade, librariesByName); .findLibraryUpdates(librariesToUpgrade, librariesByName);
return libraryUpdates.stream().map(this::resolveUpgrade).filter(Objects::nonNull).toList(); return libraryUpdates.stream().map(this::resolveUpgrade).filter(Objects::nonNull).toList();
} }

@ -75,10 +75,12 @@ final class MavenMetadataVersionResolver implements VersionResolver {
URI url = repositoryUrl.resolve(groupId.replace('.', '/') + "/" + artifactId + "/maven-metadata.xml"); URI url = repositoryUrl.resolve(groupId.replace('.', '/') + "/" + artifactId + "/maven-metadata.xml");
try { try {
String metadata = this.rest.getForObject(url, String.class); String metadata = this.rest.getForObject(url, String.class);
Document metadataDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder() Document metadataDocument = DocumentBuilderFactory.newInstance()
.parse(new InputSource(new StringReader(metadata))); .newDocumentBuilder()
NodeList versionNodes = (NodeList) XPathFactory.newInstance().newXPath() .parse(new InputSource(new StringReader(metadata)));
.evaluate("/metadata/versioning/versions/version", metadataDocument, XPathConstants.NODESET); NodeList versionNodes = (NodeList) XPathFactory.newInstance()
.newXPath()
.evaluate("/metadata/versioning/versions/version", metadataDocument, XPathConstants.NODESET);
for (int i = 0; i < versionNodes.getLength(); i++) { for (int i = 0; i < versionNodes.getLength(); i++) {
versions.add(versionNodes.item(i).getTextContent()); versions.add(versionNodes.item(i).getTextContent());
} }

@ -106,14 +106,19 @@ class StandardLibraryUpdateResolver implements LibraryUpdateResolver {
getLaterVersionsForModule(group.getId(), plugin, libraryVersion)); getLaterVersionsForModule(group.getId(), plugin, libraryVersion));
} }
} }
List<DependencyVersion> allVersions = moduleVersions.values().stream().flatMap(SortedSet::stream).distinct() List<DependencyVersion> allVersions = moduleVersions.values()
.filter((dependencyVersion) -> isPermitted(dependencyVersion, library.getProhibitedVersions())) .stream()
.collect(Collectors.toList()); .flatMap(SortedSet::stream)
.distinct()
.filter((dependencyVersion) -> isPermitted(dependencyVersion, library.getProhibitedVersions()))
.collect(Collectors.toList());
if (allVersions.isEmpty()) { if (allVersions.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
return allVersions.stream().map((version) -> new VersionOption.ResolvedVersionOption(version, return allVersions.stream()
getMissingModules(moduleVersions, version))).collect(Collectors.toList()); .map((version) -> new VersionOption.ResolvedVersionOption(version,
getMissingModules(moduleVersions, version)))
.collect(Collectors.toList());
} }
private List<VersionOption> determineAlignedVersionOption(Library library, Map<String, Library> libraries) { private List<VersionOption> determineAlignedVersionOption(Library library, Map<String, Library> libraries) {
@ -165,7 +170,7 @@ class StandardLibraryUpdateResolver implements LibraryUpdateResolver {
for (ProhibitedVersion prohibitedVersion : prohibitedVersions) { for (ProhibitedVersion prohibitedVersion : prohibitedVersions) {
String dependencyVersionToString = dependencyVersion.toString(); String dependencyVersionToString = dependencyVersion.toString();
if (prohibitedVersion.getRange() != null && prohibitedVersion.getRange() if (prohibitedVersion.getRange() != null && prohibitedVersion.getRange()
.containsVersion(new DefaultArtifactVersion(dependencyVersionToString))) { .containsVersion(new DefaultArtifactVersion(dependencyVersionToString))) {
return false; return false;
} }
for (String startsWith : prohibitedVersion.getStartsWith()) { for (String startsWith : prohibitedVersion.getStartsWith()) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -43,12 +43,12 @@ class UpgradeApplicator {
Path apply(Upgrade upgrade) throws IOException { Path apply(Upgrade upgrade) throws IOException {
String buildFileContents = Files.readString(this.buildFile); String buildFileContents = Files.readString(this.buildFile);
Matcher matcher = Pattern.compile("library\\(\"" + upgrade.getLibrary().getName() + "\", \"(.+)\"\\)") Matcher matcher = Pattern.compile("library\\(\"" + upgrade.getLibrary().getName() + "\", \"(.+)\"\\)")
.matcher(buildFileContents); .matcher(buildFileContents);
if (!matcher.find()) { if (!matcher.find()) {
matcher = Pattern matcher = Pattern
.compile("library\\(\"" + upgrade.getLibrary().getName() + "\"\\) \\{\\s+version\\(\"(.+)\"\\)", .compile("library\\(\"" + upgrade.getLibrary().getName() + "\"\\) \\{\\s+version\\(\"(.+)\"\\)",
Pattern.MULTILINE) Pattern.MULTILINE)
.matcher(buildFileContents); .matcher(buildFileContents);
if (!matcher.find()) { if (!matcher.find()) {
throw new IllegalStateException("Failed to find definition for library '" throw new IllegalStateException("Failed to find definition for library '"
+ upgrade.getLibrary().getName() + "' in bom '" + this.buildFile + "'"); + upgrade.getLibrary().getName() + "' in bom '" + this.buildFile + "'");

@ -129,12 +129,14 @@ public abstract class UpgradeDependencies extends DefaultTask {
existingUpgradeIssue.label(Arrays.asList("type: task", "status: superseded")); existingUpgradeIssue.label(Arrays.asList("type: task", "status: superseded"));
} }
} }
if (new ProcessBuilder().command("git", "add", modified.toFile().getAbsolutePath()).start() if (new ProcessBuilder().command("git", "add", modified.toFile().getAbsolutePath())
.waitFor() != 0) { .start()
.waitFor() != 0) {
throw new IllegalStateException("git add failed"); throw new IllegalStateException("git add failed");
} }
if (new ProcessBuilder().command("git", "commit", "-m", commitMessage(upgrade, issueNumber)).start() if (new ProcessBuilder().command("git", "commit", "-m", commitMessage(upgrade, issueNumber))
.waitFor() != 0) { .start()
.waitFor() != 0) {
throw new IllegalStateException("git commit failed"); throw new IllegalStateException("git commit failed");
} }
} }
@ -175,7 +177,8 @@ public abstract class UpgradeDependencies extends DefaultTask {
private Milestone determineMilestone(GitHubRepository repository) { private Milestone determineMilestone(GitHubRepository repository) {
List<Milestone> milestones = repository.getMilestones(); List<Milestone> milestones = repository.getMilestones();
java.util.Optional<Milestone> matchingMilestone = milestones.stream() java.util.Optional<Milestone> matchingMilestone = milestones.stream()
.filter((milestone) -> milestone.getName().equals(getMilestone().get())).findFirst(); .filter((milestone) -> milestone.getName().equals(getMilestone().get()))
.findFirst();
if (!matchingMilestone.isPresent()) { if (!matchingMilestone.isPresent()) {
throw new InvalidUserDataException("Unknown milestone: " + getMilestone().get()); throw new InvalidUserDataException("Unknown milestone: " + getMilestone().get());
} }
@ -185,8 +188,9 @@ public abstract class UpgradeDependencies extends DefaultTask {
private Issue findExistingUpgradeIssue(List<Issue> existingUpgradeIssues, Upgrade upgrade) { private Issue findExistingUpgradeIssue(List<Issue> existingUpgradeIssues, Upgrade upgrade) {
String toMatch = "Upgrade to " + upgrade.getLibrary().getName(); String toMatch = "Upgrade to " + upgrade.getLibrary().getName();
for (Issue existingUpgradeIssue : existingUpgradeIssues) { for (Issue existingUpgradeIssue : existingUpgradeIssues) {
if (existingUpgradeIssue.getTitle().substring(0, existingUpgradeIssue.getTitle().lastIndexOf(' ')) if (existingUpgradeIssue.getTitle()
.equals(toMatch)) { .substring(0, existingUpgradeIssue.getTitle().lastIndexOf(' '))
.equals(toMatch)) {
return existingUpgradeIssue; return existingUpgradeIssue;
} }
} }
@ -197,8 +201,8 @@ public abstract class UpgradeDependencies extends DefaultTask {
private List<Upgrade> resolveUpgrades() { private List<Upgrade> resolveUpgrades() {
List<Upgrade> upgrades = new InteractiveUpgradeResolver(getServices().get(UserInputHandler.class), List<Upgrade> upgrades = new InteractiveUpgradeResolver(getServices().get(UserInputHandler.class),
new MultithreadedLibraryUpdateResolver(new MavenMetadataVersionResolver(getRepositoryUris().get()), new MultithreadedLibraryUpdateResolver(new MavenMetadataVersionResolver(getRepositoryUris().get()),
this.bom.getUpgrade().getPolicy(), getThreads().get())).resolveUpgrades( this.bom.getUpgrade().getPolicy(), getThreads().get()))
matchingLibraries(getLibraries().getOrNull()), this.bom.getLibraries()); .resolveUpgrades(matchingLibraries(getLibraries().getOrNull()), this.bom.getLibraries());
return upgrades; return upgrades;
} }
@ -207,8 +211,10 @@ public abstract class UpgradeDependencies extends DefaultTask {
return this.bom.getLibraries(); return this.bom.getLibraries();
} }
Predicate<String> libraryPredicate = Pattern.compile(pattern).asPredicate(); Predicate<String> libraryPredicate = Pattern.compile(pattern).asPredicate();
List<Library> matchingLibraries = this.bom.getLibraries().stream() List<Library> matchingLibraries = this.bom.getLibraries()
.filter((library) -> libraryPredicate.test(library.getName())).toList(); .stream()
.filter((library) -> libraryPredicate.test(library.getName()))
.toList();
if (matchingLibraries.isEmpty()) { if (matchingLibraries.isEmpty()) {
throw new InvalidUserDataException("No libraries matched '" + pattern + "'"); throw new InvalidUserDataException("No libraries matched '" + pattern + "'");
} }

@ -49,7 +49,8 @@ final class StandardGitHub implements GitHub {
Collections.singletonList(new MappingJackson2HttpMessageConverter(new ObjectMapper()))); Collections.singletonList(new MappingJackson2HttpMessageConverter(new ObjectMapper())));
restTemplate.getInterceptors().add((request, body, execution) -> { restTemplate.getInterceptors().add((request, body, execution) -> {
request.getHeaders().add("User-Agent", StandardGitHub.this.username); request.getHeaders().add("User-Agent", StandardGitHub.this.username);
request.getHeaders().add("Authorization", "Basic " + Base64.getEncoder() request.getHeaders()
.add("Authorization", "Basic " + Base64.getEncoder()
.encodeToString((StandardGitHub.this.username + ":" + StandardGitHub.this.password).getBytes())); .encodeToString((StandardGitHub.this.username + ":" + StandardGitHub.this.password).getBytes()));
request.getHeaders().add("Accept", MediaType.APPLICATION_JSON_VALUE); request.getHeaders().add("Accept", MediaType.APPLICATION_JSON_VALUE);
return execution.execute(request, body); return execution.execute(request, body);

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -70,8 +70,8 @@ public class CheckClasspathForConflicts extends DefaultTask {
if (file.isDirectory()) { if (file.isDirectory()) {
Path root = file.toPath(); Path root = file.toPath();
try (Stream<Path> pathStream = Files.walk(root)) { try (Stream<Path> pathStream = Files.walk(root)) {
pathStream.filter(Files::isRegularFile).forEach( pathStream.filter(Files::isRegularFile)
(entry) -> classpathContents.add(root.relativize(entry).toString(), root.toString())); .forEach((entry) -> classpathContents.add(root.relativize(entry).toString(), root.toString()));
} }
} }
else { else {
@ -111,9 +111,11 @@ public class CheckClasspathForConflicts extends DefaultTask {
} }
private Map<String, List<String>> getConflicts(List<Predicate<String>> ignores) { private Map<String, List<String>> getConflicts(List<Predicate<String>> ignores) {
return this.classpathContents.entrySet().stream().filter((entry) -> entry.getValue().size() > 1) return this.classpathContents.entrySet()
.filter((entry) -> canConflict(entry.getKey(), ignores)) .stream()
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1, v2) -> v1, TreeMap::new)); .filter((entry) -> entry.getValue().size() > 1)
.filter((entry) -> canConflict(entry.getKey(), ignores))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1, v2) -> v1, TreeMap::new));
} }
private boolean canConflict(String name, List<Predicate<String>> ignores) { private boolean canConflict(String name, List<Predicate<String>> ignores) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -52,9 +52,13 @@ public class CheckClasspathForProhibitedDependencies extends DefaultTask {
@TaskAction @TaskAction
public void checkForProhibitedDependencies() { public void checkForProhibitedDependencies() {
TreeSet<String> prohibited = this.classpath.getResolvedConfiguration().getResolvedArtifacts().stream() TreeSet<String> prohibited = this.classpath.getResolvedConfiguration()
.map((artifact) -> artifact.getModuleVersion().getId()).filter(this::prohibited) .getResolvedArtifacts()
.map((id) -> id.getGroup() + ":" + id.getName()).collect(Collectors.toCollection(TreeSet::new)); .stream()
.map((artifact) -> artifact.getModuleVersion().getId())
.filter(this::prohibited)
.map((id) -> id.getGroup() + ":" + id.getName())
.collect(Collectors.toCollection(TreeSet::new));
if (!prohibited.isEmpty()) { if (!prohibited.isEmpty()) {
StringBuilder message = new StringBuilder(String.format("Found prohibited dependencies:%n")); StringBuilder message = new StringBuilder(String.format("Found prohibited dependencies:%n"));
for (String dependency : prohibited) { for (String dependency : prohibited) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -67,8 +67,8 @@ public class CheckClasspathForUnnecessaryExclusions extends DefaultTask {
ConfigurationContainer configurations) { ConfigurationContainer configurations) {
this.dependencyHandler = getProject().getDependencies(); this.dependencyHandler = getProject().getDependencies();
this.configurations = getProject().getConfigurations(); this.configurations = getProject().getConfigurations();
this.platform = this.dependencyHandler.create( this.platform = this.dependencyHandler
this.dependencyHandler.platform(this.dependencyHandler.project(SPRING_BOOT_DEPENDENCIES_PROJECT))); .create(this.dependencyHandler.platform(this.dependencyHandler.project(SPRING_BOOT_DEPENDENCIES_PROJECT)));
getOutputs().upToDateWhen((task) -> true); getOutputs().upToDateWhen((task) -> true);
} }
@ -86,8 +86,10 @@ public class CheckClasspathForUnnecessaryExclusions extends DefaultTask {
private void processDependency(ModuleDependency dependency) { private void processDependency(ModuleDependency dependency) {
String dependencyId = getId(dependency); String dependencyId = getId(dependency);
TreeSet<String> exclusions = dependency.getExcludeRules().stream().map(this::getId) TreeSet<String> exclusions = dependency.getExcludeRules()
.collect(Collectors.toCollection(TreeSet::new)); .stream()
.map(this::getId)
.collect(Collectors.toCollection(TreeSet::new));
this.exclusionsByDependencyId.put(dependencyId, exclusions); this.exclusionsByDependencyId.put(dependencyId, exclusions);
if (!exclusions.isEmpty()) { if (!exclusions.isEmpty()) {
this.dependencyById.put(dependencyId, getProject().getDependencies().create(dependencyId)); this.dependencyById.put(dependencyId, getProject().getDependencies().create(dependencyId));
@ -106,7 +108,12 @@ public class CheckClasspathForUnnecessaryExclusions extends DefaultTask {
if (!exclusions.isEmpty()) { if (!exclusions.isEmpty()) {
Dependency toCheck = this.dependencyById.get(dependencyId); Dependency toCheck = this.dependencyById.get(dependencyId);
List<String> dependencies = this.configurations.detachedConfiguration(toCheck, this.platform) List<String> dependencies = this.configurations.detachedConfiguration(toCheck, this.platform)
.getIncoming().getArtifacts().getArtifacts().stream().map(this::getId).toList(); .getIncoming()
.getArtifacts()
.getArtifacts()
.stream()
.map(this::getId)
.toList();
exclusions.removeAll(dependencies); exclusions.removeAll(dependencies);
removeProfileExclusions(dependencyId, exclusions); removeProfileExclusions(dependencyId, exclusions);
if (!exclusions.isEmpty()) { if (!exclusions.isEmpty()) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,8 +64,10 @@ public class ExtractVersionConstraints extends DefaultTask {
} }
public void enforcedPlatform(String projectPath) { public void enforcedPlatform(String projectPath) {
this.configuration.getDependencies().add(getProject().getDependencies().enforcedPlatform( this.configuration.getDependencies()
getProject().getDependencies().project(Collections.singletonMap("path", projectPath)))); .add(getProject().getDependencies()
.enforcedPlatform(
getProject().getDependencies().project(Collections.singletonMap("path", projectPath))));
this.projectPaths.add(projectPath); this.projectPaths.add(projectPath);
} }
@ -89,8 +91,10 @@ public class ExtractVersionConstraints extends DefaultTask {
this.configuration.resolve(); this.configuration.resolve();
for (String projectPath : this.projectPaths) { for (String projectPath : this.projectPaths) {
extractVersionProperties(projectPath); extractVersionProperties(projectPath);
for (DependencyConstraint constraint : getProject().project(projectPath).getConfigurations() for (DependencyConstraint constraint : getProject().project(projectPath)
.getByName("apiElements").getAllDependencyConstraints()) { .getConfigurations()
.getByName("apiElements")
.getAllDependencyConstraints()) {
this.versionConstraints.put(constraint.getGroup() + ":" + constraint.getName(), this.versionConstraints.put(constraint.getGroup() + ":" + constraint.getName(),
constraint.getVersionConstraint().toString()); constraint.getVersionConstraint().toString());
this.constrainedVersions.add(new ConstrainedVersion(constraint.getGroup(), constraint.getName(), this.constrainedVersions.add(new ConstrainedVersion(constraint.getGroup(), constraint.getName(),

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -87,75 +87,102 @@ public class ConfigurationPropertiesPlugin implements Plugin<Project> {
private void configureConfigurationPropertiesAnnotationProcessor(Project project) { private void configureConfigurationPropertiesAnnotationProcessor(Project project) {
Configuration annotationProcessors = project.getConfigurations() Configuration annotationProcessors = project.getConfigurations()
.getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME); .getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME);
annotationProcessors.getDependencies().add(project.getDependencies().project(Collections.singletonMap("path", annotationProcessors.getDependencies()
":spring-boot-project:spring-boot-tools:spring-boot-configuration-processor"))); .add(project.getDependencies()
.project(Collections.singletonMap("path",
":spring-boot-project:spring-boot-tools:spring-boot-configuration-processor")));
project.getPlugins().apply(ProcessedAnnotationsPlugin.class); project.getPlugins().apply(ProcessedAnnotationsPlugin.class);
} }
private void disableIncrementalCompilation(Project project) { private void disableIncrementalCompilation(Project project) {
SourceSet mainSourceSet = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets() SourceSet mainSourceSet = project.getExtensions()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME); .getByType(JavaPluginExtension.class)
project.getTasks().named(mainSourceSet.getCompileJavaTaskName(), JavaCompile.class) .getSourceSets()
.configure((compileJava) -> compileJava.getOptions().setIncremental(false)); .getByName(SourceSet.MAIN_SOURCE_SET_NAME);
project.getTasks()
.named(mainSourceSet.getCompileJavaTaskName(), JavaCompile.class)
.configure((compileJava) -> compileJava.getOptions().setIncremental(false));
} }
private void addMetadataArtifact(Project project) { private void addMetadataArtifact(Project project) {
SourceSet mainSourceSet = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets() SourceSet mainSourceSet = project.getExtensions()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME); .getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
project.getConfigurations().maybeCreate(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME); project.getConfigurations().maybeCreate(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME);
project.afterEvaluate((evaluatedProject) -> evaluatedProject.getArtifacts().add( project.afterEvaluate((evaluatedProject) -> evaluatedProject.getArtifacts()
CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME, .add(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME,
mainSourceSet.getJava().getDestinationDirectory().dir("META-INF/spring-configuration-metadata.json"), mainSourceSet.getJava()
(artifact) -> artifact .getDestinationDirectory()
.dir("META-INF/spring-configuration-metadata.json"),
(artifact) -> artifact
.builtBy(evaluatedProject.getTasks().getByName(mainSourceSet.getClassesTaskName())))); .builtBy(evaluatedProject.getTasks().getByName(mainSourceSet.getClassesTaskName()))));
} }
private void configureAdditionalMetadataLocationsCompilerArgument(Project project) { private void configureAdditionalMetadataLocationsCompilerArgument(Project project) {
JavaCompile compileJava = project.getTasks().withType(JavaCompile.class) JavaCompile compileJava = project.getTasks()
.getByName(JavaPlugin.COMPILE_JAVA_TASK_NAME); .withType(JavaCompile.class)
((Task) compileJava).getInputs().files(project.getTasks().getByName(JavaPlugin.PROCESS_RESOURCES_TASK_NAME)) .getByName(JavaPlugin.COMPILE_JAVA_TASK_NAME);
.withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName("processed resources"); ((Task) compileJava).getInputs()
SourceSet mainSourceSet = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets() .files(project.getTasks().getByName(JavaPlugin.PROCESS_RESOURCES_TASK_NAME))
.getByName(SourceSet.MAIN_SOURCE_SET_NAME); .withPathSensitivity(PathSensitivity.RELATIVE)
compileJava.getOptions().getCompilerArgs() .withPropertyName("processed resources");
.add("-Aorg.springframework.boot.configurationprocessor.additionalMetadataLocations=" + StringUtils SourceSet mainSourceSet = project.getExtensions()
.collectionToCommaDelimitedString(mainSourceSet.getResources().getSourceDirectories().getFiles() .getByType(JavaPluginExtension.class)
.stream().map(project.getRootProject()::relativePath).collect(Collectors.toSet()))); .getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
compileJava.getOptions()
.getCompilerArgs()
.add("-Aorg.springframework.boot.configurationprocessor.additionalMetadataLocations="
+ StringUtils.collectionToCommaDelimitedString(mainSourceSet.getResources()
.getSourceDirectories()
.getFiles()
.stream()
.map(project.getRootProject()::relativePath)
.collect(Collectors.toSet())));
} }
private void registerCheckAdditionalMetadataTask(Project project) { private void registerCheckAdditionalMetadataTask(Project project) {
TaskProvider<CheckAdditionalSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks() TaskProvider<CheckAdditionalSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks()
.register(CHECK_ADDITIONAL_SPRING_CONFIGURATION_METADATA_TASK_NAME, .register(CHECK_ADDITIONAL_SPRING_CONFIGURATION_METADATA_TASK_NAME,
CheckAdditionalSpringConfigurationMetadata.class); CheckAdditionalSpringConfigurationMetadata.class);
checkConfigurationMetadata.configure((check) -> { checkConfigurationMetadata.configure((check) -> {
SourceSet mainSourceSet = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets() SourceSet mainSourceSet = project.getExtensions()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME); .getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
check.setSource(mainSourceSet.getResources()); check.setSource(mainSourceSet.getResources());
check.include("META-INF/additional-spring-configuration-metadata.json"); check.include("META-INF/additional-spring-configuration-metadata.json");
check.getReportLocation().set(project.getLayout().getBuildDirectory() check.getReportLocation()
.set(project.getLayout()
.getBuildDirectory()
.file("reports/additional-spring-configuration-metadata/check.txt")); .file("reports/additional-spring-configuration-metadata/check.txt"));
}); });
project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME) project.getTasks()
.configure((check) -> check.dependsOn(checkConfigurationMetadata)); .named(LifecycleBasePlugin.CHECK_TASK_NAME)
.configure((check) -> check.dependsOn(checkConfigurationMetadata));
} }
private void registerCheckMetadataTask(Project project) { private void registerCheckMetadataTask(Project project) {
TaskProvider<CheckSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks() TaskProvider<CheckSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks()
.register(CHECK_SPRING_CONFIGURATION_METADATA_TASK_NAME, CheckSpringConfigurationMetadata.class); .register(CHECK_SPRING_CONFIGURATION_METADATA_TASK_NAME, CheckSpringConfigurationMetadata.class);
checkConfigurationMetadata.configure((check) -> { checkConfigurationMetadata.configure((check) -> {
SourceSet mainSourceSet = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets() SourceSet mainSourceSet = project.getExtensions()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME); .getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
Provider<RegularFile> metadataLocation = project.getTasks() Provider<RegularFile> metadataLocation = project.getTasks()
.named(mainSourceSet.getCompileJavaTaskName(), JavaCompile.class) .named(mainSourceSet.getCompileJavaTaskName(), JavaCompile.class)
.flatMap((javaCompile) -> javaCompile.getDestinationDirectory() .flatMap((javaCompile) -> javaCompile.getDestinationDirectory()
.file("META-INF/spring-configuration-metadata.json")); .file("META-INF/spring-configuration-metadata.json"));
check.getMetadataLocation().set(metadataLocation); check.getMetadataLocation().set(metadataLocation);
check.getReportLocation().set( check.getReportLocation()
project.getLayout().getBuildDirectory().file("reports/spring-configuration-metadata/check.txt")); .set(project.getLayout().getBuildDirectory().file("reports/spring-configuration-metadata/check.txt"));
}); });
project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME) project.getTasks()
.configure((check) -> check.dependsOn(checkConfigurationMetadata)); .named(LifecycleBasePlugin.CHECK_TASK_NAME)
.configure((check) -> check.dependsOn(checkConfigurationMetadata));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -45,8 +45,9 @@ class SingleRow extends Row {
return null; return null;
} }
if (defaultValue.getClass().isArray()) { if (defaultValue.getClass().isArray()) {
return Arrays.stream((Object[]) defaultValue).map(Object::toString) return Arrays.stream((Object[]) defaultValue)
.collect(Collectors.joining("," + System.lineSeparator())); .map(Object::toString)
.collect(Collectors.joining("," + System.lineSeparator()));
} }
return defaultValue.toString(); return defaultValue.toString();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -52,8 +52,10 @@ class Snippets {
void writeTo(Path outputDirectory) throws IOException { void writeTo(Path outputDirectory) throws IOException {
createDirectory(outputDirectory); createDirectory(outputDirectory);
Set<String> remaining = this.properties.stream().filter((property) -> !property.isDeprecated()) Set<String> remaining = this.properties.stream()
.map(ConfigurationProperty::getName).collect(Collectors.toSet()); .filter((property) -> !property.isDeprecated())
.map(ConfigurationProperty::getName)
.collect(Collectors.toSet());
for (Snippet snippet : this.snippets) { for (Snippet snippet : this.snippets) {
Set<String> written = writeSnippet(outputDirectory, snippet, remaining); Set<String> written = writeSnippet(outputDirectory, snippet, remaining);
remaining.removeAll(written); remaining.removeAll(written);

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -48,8 +48,9 @@ public class DocumentDevtoolsPropertyDefaults extends DefaultTask {
public DocumentDevtoolsPropertyDefaults() { public DocumentDevtoolsPropertyDefaults() {
this.devtools = getProject().getConfigurations().create("devtools"); this.devtools = getProject().getConfigurations().create("devtools");
this.outputFile = getProject().getObjects().fileProperty(); this.outputFile = getProject().getObjects().fileProperty();
this.outputFile.convention(getProject().getLayout().getBuildDirectory() this.outputFile.convention(getProject().getLayout()
.file("docs/generated/using/devtools-property-defaults.adoc")); .getBuildDirectory()
.file("docs/generated/using/devtools-property-defaults.adoc"));
Map<String, String> dependency = new HashMap<>(); Map<String, String> dependency = new HashMap<>();
dependency.put("path", ":spring-boot-project:spring-boot-devtools"); dependency.put("path", ":spring-boot-project:spring-boot-devtools");
dependency.put("configuration", "propertyDefaults"); dependency.put("configuration", "propertyDefaults");

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -57,8 +57,9 @@ public class ApplicationRunner extends DefaultTask {
private final Property<String> expectedLogging = getProject().getObjects().property(String.class); private final Property<String> expectedLogging = getProject().getObjects().property(String.class);
private final Property<String> applicationJar = getProject().getObjects().property(String.class) private final Property<String> applicationJar = getProject().getObjects()
.convention("/opt/apps/myapp.jar"); .property(String.class)
.convention("/opt/apps/myapp.jar");
private final Map<String, String> normalizations = new HashMap<>(); private final Map<String, String> normalizations = new HashMap<>();
@ -118,13 +119,17 @@ public class ApplicationRunner extends DefaultTask {
File executable = Jvm.current().getExecutable("java"); File executable = Jvm.current().getExecutable("java");
command.add(executable.getAbsolutePath()); command.add(executable.getAbsolutePath());
command.add("-cp"); command.add("-cp");
command.add(this.classpath.getFiles().stream().map(File::getAbsolutePath) command.add(this.classpath.getFiles()
.collect(Collectors.joining(File.pathSeparator))); .stream()
.map(File::getAbsolutePath)
.collect(Collectors.joining(File.pathSeparator)));
command.add(this.mainClass.get()); command.add(this.mainClass.get());
command.addAll(this.args.get()); command.addAll(this.args.get());
File outputFile = this.output.getAsFile().get(); File outputFile = this.output.getAsFile().get();
Process process = new ProcessBuilder().redirectOutput(outputFile).redirectError(outputFile).command(command) Process process = new ProcessBuilder().redirectOutput(outputFile)
.start(); .redirectError(outputFile)
.command(command)
.start();
awaitLogging(process); awaitLogging(process);
process.destroy(); process.destroy();
normalizeLogging(); normalizeLogging();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -108,8 +108,9 @@ public class DocumentPluginGoals extends DefaultTask {
writer.println("== Required parameters"); writer.println("== Required parameters");
writeParametersTable(writer, detailsSectionId, requiredParameters); writeParametersTable(writer, detailsSectionId, requiredParameters);
} }
List<Parameter> optionalParameters = parameters.stream().filter((parameter) -> !parameter.isRequired()) List<Parameter> optionalParameters = parameters.stream()
.toList(); .filter((parameter) -> !parameter.isRequired())
.toList();
if (!optionalParameters.isEmpty()) { if (!optionalParameters.isEmpty()) {
writer.println(); writer.println();
writer.println(); writer.println();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -51,8 +51,9 @@ public class MavenExec extends JavaExec {
public void setProjectDir(File projectDir) { public void setProjectDir(File projectDir) {
this.projectDir = projectDir; this.projectDir = projectDir;
getInputs().file(new File(projectDir, "pom.xml")).withPathSensitivity(PathSensitivity.RELATIVE) getInputs().file(new File(projectDir, "pom.xml"))
.withPropertyName("pom"); .withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("pom");
} }
@Override @Override
@ -88,10 +89,11 @@ public class MavenExec extends JavaExec {
maven.getDependencies().add(project.getDependencies().create("org.apache.maven:maven-embedder:3.6.2")); maven.getDependencies().add(project.getDependencies().create("org.apache.maven:maven-embedder:3.6.2"));
maven.getDependencies().add(project.getDependencies().create("org.apache.maven:maven-compat:3.6.2")); maven.getDependencies().add(project.getDependencies().create("org.apache.maven:maven-compat:3.6.2"));
maven.getDependencies().add(project.getDependencies().create("org.slf4j:slf4j-simple:1.7.5")); maven.getDependencies().add(project.getDependencies().create("org.slf4j:slf4j-simple:1.7.5"));
maven.getDependencies().add( maven.getDependencies()
project.getDependencies().create("org.apache.maven.resolver:maven-resolver-connector-basic:1.4.1")); .add(project.getDependencies()
maven.getDependencies().add( .create("org.apache.maven.resolver:maven-resolver-connector-basic:1.4.1"));
project.getDependencies().create("org.apache.maven.resolver:maven-resolver-transport-http:1.4.1")); maven.getDependencies()
.add(project.getDependencies().create("org.apache.maven.resolver:maven-resolver-transport-http:1.4.1"));
}); });
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -128,15 +128,15 @@ public class MavenPluginPlugin implements Plugin<Project> {
private void addPopulateIntTestMavenRepositoryTask(Project project) { private void addPopulateIntTestMavenRepositoryTask(Project project) {
Configuration runtimeClasspathWithMetadata = project.getConfigurations().create("runtimeClasspathWithMetadata"); Configuration runtimeClasspathWithMetadata = project.getConfigurations().create("runtimeClasspathWithMetadata");
runtimeClasspathWithMetadata runtimeClasspathWithMetadata
.extendsFrom(project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)); .extendsFrom(project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME));
runtimeClasspathWithMetadata.attributes((attributes) -> attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE, runtimeClasspathWithMetadata.attributes((attributes) -> attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE,
project.getObjects().named(DocsType.class, "maven-repository"))); project.getObjects().named(DocsType.class, "maven-repository")));
RuntimeClasspathMavenRepository runtimeClasspathMavenRepository = project.getTasks() RuntimeClasspathMavenRepository runtimeClasspathMavenRepository = project.getTasks()
.create("runtimeClasspathMavenRepository", RuntimeClasspathMavenRepository.class); .create("runtimeClasspathMavenRepository", RuntimeClasspathMavenRepository.class);
runtimeClasspathMavenRepository.getOutputDirectory() runtimeClasspathMavenRepository.getOutputDirectory()
.set(new File(project.getBuildDir(), "runtime-classpath-repository")); .set(new File(project.getBuildDir(), "runtime-classpath-repository"));
project.getDependencies() project.getDependencies()
.components((components) -> components.all(MavenRepositoryComponentMetadataRule.class)); .components((components) -> components.all(MavenRepositoryComponentMetadataRule.class));
Sync task = project.getTasks().create("populateIntTestMavenRepository", Sync.class); Sync task = project.getTasks().create("populateIntTestMavenRepository", Sync.class);
task.setDestinationDir(new File(project.getBuildDir(), "int-test-maven-repository")); task.setDestinationDir(new File(project.getBuildDir(), "int-test-maven-repository"));
task.with(copyIntTestMavenRepositoryFiles(project, runtimeClasspathMavenRepository)); task.with(copyIntTestMavenRepositoryFiles(project, runtimeClasspathMavenRepository));
@ -219,8 +219,8 @@ public class MavenPluginPlugin implements Plugin<Project> {
private FormatHelpMojoSource createFormatHelpMojoSource(Project project, MavenExec generateHelpMojoTask, private FormatHelpMojoSource createFormatHelpMojoSource(Project project, MavenExec generateHelpMojoTask,
File generatedHelpMojoDir) { File generatedHelpMojoDir) {
FormatHelpMojoSource formatHelpMojoSource = project.getTasks().create("formatHelpMojoSource", FormatHelpMojoSource formatHelpMojoSource = project.getTasks()
FormatHelpMojoSource.class); .create("formatHelpMojoSource", FormatHelpMojoSource.class);
formatHelpMojoSource.setGenerator(generateHelpMojoTask); formatHelpMojoSource.setGenerator(generateHelpMojoTask);
formatHelpMojoSource.setOutputDir(generatedHelpMojoDir); formatHelpMojoSource.setOutputDir(generatedHelpMojoDir);
return formatHelpMojoSource; return formatHelpMojoSource;
@ -241,8 +241,10 @@ public class MavenPluginPlugin implements Plugin<Project> {
MavenExec generatePluginDescriptor = project.getTasks().create("generatePluginDescriptor", MavenExec.class); MavenExec generatePluginDescriptor = project.getTasks().create("generatePluginDescriptor", MavenExec.class);
generatePluginDescriptor.args("org.apache.maven.plugins:maven-plugin-plugin:3.6.1:descriptor"); generatePluginDescriptor.args("org.apache.maven.plugins:maven-plugin-plugin:3.6.1:descriptor");
generatePluginDescriptor.getOutputs().dir(new File(mavenDir, "target/classes/META-INF/maven")); generatePluginDescriptor.getOutputs().dir(new File(mavenDir, "target/classes/META-INF/maven"));
generatePluginDescriptor.getInputs().dir(new File(mavenDir, "target/classes/org")) generatePluginDescriptor.getInputs()
.withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName("plugin classes"); .dir(new File(mavenDir, "target/classes/org"))
.withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("plugin classes");
generatePluginDescriptor.setProjectDir(mavenDir); generatePluginDescriptor.setProjectDir(mavenDir);
return generatePluginDescriptor; return generatePluginDescriptor;
} }
@ -267,10 +269,13 @@ public class MavenPluginPlugin implements Plugin<Project> {
} }
private void addExtractVersionPropertiesTask(Project project) { private void addExtractVersionPropertiesTask(Project project) {
ExtractVersionProperties extractVersionProperties = project.getTasks().create("extractVersionProperties", ExtractVersionProperties extractVersionProperties = project.getTasks()
ExtractVersionProperties.class); .create("extractVersionProperties", ExtractVersionProperties.class);
extractVersionProperties.setEffectiveBoms(project.getConfigurations().create("versionProperties")); extractVersionProperties.setEffectiveBoms(project.getConfigurations().create("versionProperties"));
extractVersionProperties.getDestination().set(project.getLayout().getBuildDirectory().dir("generated-resources") extractVersionProperties.getDestination()
.set(project.getLayout()
.getBuildDirectory()
.dir("generated-resources")
.map((dir) -> dir.file("extracted-versions.properties"))); .map((dir) -> dir.file("extracted-versions.properties")));
} }
@ -282,8 +287,9 @@ public class MavenPluginPlugin implements Plugin<Project> {
void setGenerator(Task generator) { void setGenerator(Task generator) {
this.generator = generator; this.generator = generator;
getInputs().files(this.generator).withPathSensitivity(PathSensitivity.RELATIVE) getInputs().files(this.generator)
.withPropertyName("generated source"); .withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("generated source");
} }
@OutputDirectory @OutputDirectory
@ -300,7 +306,7 @@ public class MavenPluginPlugin implements Plugin<Project> {
FileFormatter formatter = new FileFormatter(); FileFormatter formatter = new FileFormatter();
for (File output : this.generator.getOutputs().getFiles()) { for (File output : this.generator.getOutputs().getFiles()) {
formatter.formatFiles(getProject().fileTree(output), StandardCharsets.UTF_8) formatter.formatFiles(getProject().fileTree(output), StandardCharsets.UTF_8)
.forEach((edit) -> save(output, edit)); .forEach((edit) -> save(output, edit));
} }
} }
@ -329,10 +335,11 @@ public class MavenPluginPlugin implements Plugin<Project> {
@Override @Override
public void execute(ComponentMetadataContext context) { public void execute(ComponentMetadataContext context) {
context.getDetails().maybeAddVariant("compileWithMetadata", "compile", context.getDetails()
(variant) -> configureVariant(context, variant)); .maybeAddVariant("compileWithMetadata", "compile", (variant) -> configureVariant(context, variant));
context.getDetails().maybeAddVariant("apiElementsWithMetadata", "apiElements", context.getDetails()
(variant) -> configureVariant(context, variant)); .maybeAddVariant("apiElementsWithMetadata", "apiElements",
(variant) -> configureVariant(context, variant));
} }
private void configureVariant(ComponentMetadataContext context, VariantMetadata variant) { private void configureVariant(ComponentMetadataContext context, VariantMetadata variant) {
@ -374,11 +381,14 @@ public class MavenPluginPlugin implements Plugin<Project> {
public void createRepository() { public void createRepository() {
for (ResolvedArtifactResult result : this.runtimeClasspath.getIncoming().getArtifacts()) { for (ResolvedArtifactResult result : this.runtimeClasspath.getIncoming().getArtifacts()) {
if (result.getId().getComponentIdentifier() instanceof ModuleComponentIdentifier identifier) { if (result.getId().getComponentIdentifier() instanceof ModuleComponentIdentifier identifier) {
String fileName = result.getFile().getName() String fileName = result.getFile()
.replace(identifier.getVersion() + "-" + identifier.getVersion(), identifier.getVersion()); .getName()
File repositoryLocation = this.outputDirectory.dir(identifier.getGroup().replace('.', '/') + "/" .replace(identifier.getVersion() + "-" + identifier.getVersion(), identifier.getVersion());
+ identifier.getModule() + "/" + identifier.getVersion() + "/" + fileName).get() File repositoryLocation = this.outputDirectory
.getAsFile(); .dir(identifier.getGroup().replace('.', '/') + "/" + identifier.getModule() + "/"
+ identifier.getVersion() + "/" + fileName)
.get()
.getAsFile();
repositoryLocation.getParentFile().mkdirs(); repositoryLocation.getParentFile().mkdirs();
try { try {
Files.copy(result.getFile().toPath(), repositoryLocation.toPath(), Files.copy(result.getFile().toPath(), repositoryLocation.toPath(),
@ -487,8 +497,8 @@ public class MavenPluginPlugin implements Plugin<Project> {
private String get(String expression) { private String get(String expression) {
try { try {
Node node = (Node) this.xpath.compile("/project/" + expression).evaluate(this.document, Node node = (Node) this.xpath.compile("/project/" + expression)
XPathConstants.NODE); .evaluate(this.document, XPathConstants.NODE);
String text = (node != null) ? node.getTextContent() : null; String text = (node != null) ? node.getTextContent() : null;
Assert.hasLength(text, () -> "No result for expression " + expression); Assert.hasLength(text, () -> "No result for expression " + expression);
return text; return text;

@ -111,10 +111,17 @@ class PluginXmlParser {
} }
private String format(String input) { private String format(String input) {
return input.replace("<code>", "`").replace("</code>", "`").replace("&lt;", "<").replace("&gt;", ">") return input.replace("<code>", "`")
.replace("<br>", " ").replace("\n", " ").replace("&quot;", "\"").replaceAll("\\{@code (.*?)}", "`$1`") .replace("</code>", "`")
.replaceAll("\\{@link (.*?)}", "`$1`").replaceAll("\\{@literal (.*?)}", "`$1`") .replace("&lt;", "<")
.replaceAll("<a href=.\"(.*?)\".>(.*?)</a>", "$1[$2]"); .replace("&gt;", ">")
.replace("<br>", " ")
.replace("\n", " ")
.replace("&quot;", "\"")
.replaceAll("\\{@code (.*?)}", "`$1`")
.replaceAll("\\{@link (.*?)}", "`$1`")
.replaceAll("\\{@literal (.*?)}", "`$1`")
.replaceAll("<a href=.\"(.*?)\".>(.*?)</a>", "$1[$2]");
} }
private static final class IterableNodeList implements Iterable<Node> { private static final class IterableNodeList implements Iterable<Node> {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -60,10 +60,11 @@ public class PrepareMavenBinaries extends DefaultTask {
@TaskAction @TaskAction
public void prepareBinaries() { public void prepareBinaries() {
for (String version : this.versions) { for (String version : this.versions) {
Configuration configuration = getProject().getConfigurations().detachedConfiguration( Configuration configuration = getProject().getConfigurations()
getProject().getDependencies().create("org.apache.maven:apache-maven:" + version + ":bin@zip")); .detachedConfiguration(
getProject().copy( getProject().getDependencies().create("org.apache.maven:apache-maven:" + version + ":bin@zip"));
(copy) -> copy.into(this.outputDir).from(getProject().zipTree(configuration.getSingleFile()))); getProject()
.copy((copy) -> copy.into(this.outputDir).from(getProject().zipTree(configuration.getSingleFile())));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -44,13 +44,16 @@ public class OptionalDependenciesPlugin implements Plugin<Project> {
optional.setCanBeConsumed(false); optional.setCanBeConsumed(false);
optional.setCanBeResolved(false); optional.setCanBeResolved(false);
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> { project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
SourceSetContainer sourceSets = project.getExtensions().getByType(JavaPluginExtension.class) SourceSetContainer sourceSets = project.getExtensions()
.getSourceSets(); .getByType(JavaPluginExtension.class)
.getSourceSets();
sourceSets.all((sourceSet) -> { sourceSets.all((sourceSet) -> {
project.getConfigurations().getByName(sourceSet.getCompileClasspathConfigurationName()) project.getConfigurations()
.extendsFrom(optional); .getByName(sourceSet.getCompileClasspathConfigurationName())
project.getConfigurations().getByName(sourceSet.getRuntimeClasspathConfigurationName()) .extendsFrom(optional);
.extendsFrom(optional); project.getConfigurations()
.getByName(sourceSet.getRuntimeClasspathConfigurationName())
.extendsFrom(optional);
}); });
}); });
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2022 the original author or authors. * Copyright 2022-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,8 +31,9 @@ public class ProcessedAnnotationsPlugin implements Plugin<Project> {
@Override @Override
public void apply(Project project) { public void apply(Project project) {
project.getPlugins().apply(AptEclipsePlugin.class); project.getPlugins().apply(AptEclipsePlugin.class);
project.getExtensions().getByType(EclipseModel.class).synchronizationTasks("eclipseJdtApt", "eclipseJdt", project.getExtensions()
"eclipseFactorypath"); .getByType(EclipseModel.class)
.synchronizationTasks("eclipseJdtApt", "eclipseJdt", "eclipseFactorypath");
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -84,8 +84,10 @@ public class DocumentStarters extends DefaultTask {
@TaskAction @TaskAction
void documentStarters() { void documentStarters() {
Set<Starter> starters = this.starters.getFiles().stream().map(this::loadStarter) Set<Starter> starters = this.starters.getFiles()
.collect(Collectors.toCollection(TreeSet::new)); .stream()
.map(this::loadStarter)
.collect(Collectors.toCollection(TreeSet::new));
writeTable("application-starters", starters.stream().filter(Starter::isApplication)); writeTable("application-starters", starters.stream().filter(Starter::isApplication));
writeTable("production-starters", starters.stream().filter(Starter::isProduction)); writeTable("production-starters", starters.stream().filter(Starter::isProduction));
writeTable("technical-starters", starters.stream().filter(Starter::isTechnical)); writeTable("technical-starters", starters.stream().filter(Starter::isTechnical));

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -73,8 +73,13 @@ public class StarterMetadata extends DefaultTask {
Properties properties = CollectionFactory.createSortedProperties(true); Properties properties = CollectionFactory.createSortedProperties(true);
properties.setProperty("name", getProject().getName()); properties.setProperty("name", getProject().getName());
properties.setProperty("description", getProject().getDescription()); properties.setProperty("description", getProject().getDescription());
properties.setProperty("dependencies", String.join(",", this.dependencies.getResolvedConfiguration() properties.setProperty("dependencies",
.getResolvedArtifacts().stream().map(ResolvedArtifact::getName).collect(Collectors.toSet()))); String.join(",",
this.dependencies.getResolvedConfiguration()
.getResolvedArtifacts()
.stream()
.map(ResolvedArtifact::getName)
.collect(Collectors.toSet())));
this.destination.getParentFile().mkdirs(); this.destination.getParentFile().mkdirs();
try (FileWriter writer = new FileWriter(this.destination)) { try (FileWriter writer = new FileWriter(this.destination)) {
properties.store(writer, null); properties.store(writer, null);

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -58,25 +58,26 @@ public class StarterPlugin implements Plugin<Project> {
File destination = new File(project.getBuildDir(), "starter-metadata.properties"); File destination = new File(project.getBuildDir(), "starter-metadata.properties");
starterMetadata.setDestination(destination); starterMetadata.setDestination(destination);
configurations.create("starterMetadata"); configurations.create("starterMetadata");
project.getArtifacts().add("starterMetadata", project.provider(starterMetadata::getDestination), project.getArtifacts()
(artifact) -> artifact.builtBy(starterMetadata)); .add("starterMetadata", project.provider(starterMetadata::getDestination),
(artifact) -> artifact.builtBy(starterMetadata));
createClasspathConflictsCheck(runtimeClasspath, project); createClasspathConflictsCheck(runtimeClasspath, project);
createUnnecessaryExclusionsCheck(runtimeClasspath, project); createUnnecessaryExclusionsCheck(runtimeClasspath, project);
configureJarManifest(project); configureJarManifest(project);
} }
private void createClasspathConflictsCheck(Configuration classpath, Project project) { private void createClasspathConflictsCheck(Configuration classpath, Project project) {
CheckClasspathForConflicts checkClasspathForConflicts = project.getTasks().create( CheckClasspathForConflicts checkClasspathForConflicts = project.getTasks()
"check" + StringUtils.capitalize(classpath.getName() + "ForConflicts"), .create("check" + StringUtils.capitalize(classpath.getName() + "ForConflicts"),
CheckClasspathForConflicts.class); CheckClasspathForConflicts.class);
checkClasspathForConflicts.setClasspath(classpath); checkClasspathForConflicts.setClasspath(classpath);
project.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkClasspathForConflicts); project.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkClasspathForConflicts);
} }
private void createUnnecessaryExclusionsCheck(Configuration classpath, Project project) { private void createUnnecessaryExclusionsCheck(Configuration classpath, Project project) {
CheckClasspathForUnnecessaryExclusions checkClasspathForUnnecessaryExclusions = project.getTasks().create( CheckClasspathForUnnecessaryExclusions checkClasspathForUnnecessaryExclusions = project.getTasks()
"check" + StringUtils.capitalize(classpath.getName() + "ForUnnecessaryExclusions"), .create("check" + StringUtils.capitalize(classpath.getName() + "ForUnnecessaryExclusions"),
CheckClasspathForUnnecessaryExclusions.class); CheckClasspathForUnnecessaryExclusions.class);
checkClasspathForUnnecessaryExclusions.setClasspath(classpath); checkClasspathForUnnecessaryExclusions.setClasspath(classpath);
project.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkClasspathForUnnecessaryExclusions); project.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkClasspathForUnnecessaryExclusions);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -55,8 +55,8 @@ public class IntegrationTestPlugin implements Plugin<Project> {
project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(intTest); project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(intTest);
project.getPlugins().withType(EclipsePlugin.class, (eclipsePlugin) -> { project.getPlugins().withType(EclipsePlugin.class, (eclipsePlugin) -> {
EclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class); EclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class);
eclipse.classpath((classpath) -> classpath.getPlusConfigurations().add( eclipse.classpath((classpath) -> classpath.getPlusConfigurations()
project.getConfigurations().getByName(intTestSourceSet.getRuntimeClasspathConfigurationName()))); .add(project.getConfigurations().getByName(intTestSourceSet.getRuntimeClasspathConfigurationName())));
}); });
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -59,8 +59,9 @@ public class SystemTestPlugin implements Plugin<Project> {
createTestTask(project, systemTestSourceSet); createTestTask(project, systemTestSourceSet);
project.getPlugins().withType(EclipsePlugin.class, (eclipsePlugin) -> { project.getPlugins().withType(EclipsePlugin.class, (eclipsePlugin) -> {
EclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class); EclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class);
eclipse.classpath((classpath) -> classpath.getPlusConfigurations().add( eclipse.classpath((classpath) -> classpath.getPlusConfigurations()
project.getConfigurations().getByName(systemTestSourceSet.getRuntimeClasspathConfigurationName()))); .add(project.getConfigurations()
.getByName(systemTestSourceSet.getRuntimeClasspathConfigurationName())));
}); });
} }
@ -69,9 +70,9 @@ public class SystemTestPlugin implements Plugin<Project> {
SourceSet systemTestSourceSet = sourceSets.create(SYSTEM_TEST_SOURCE_SET_NAME); SourceSet systemTestSourceSet = sourceSets.create(SYSTEM_TEST_SOURCE_SET_NAME);
SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
systemTestSourceSet systemTestSourceSet
.setCompileClasspath(systemTestSourceSet.getCompileClasspath().plus(mainSourceSet.getOutput())); .setCompileClasspath(systemTestSourceSet.getCompileClasspath().plus(mainSourceSet.getOutput()));
systemTestSourceSet systemTestSourceSet
.setRuntimeClasspath(systemTestSourceSet.getRuntimeClasspath().plus(mainSourceSet.getOutput())); .setRuntimeClasspath(systemTestSourceSet.getRuntimeClasspath().plus(mainSourceSet.getOutput()));
return systemTestSourceSet; return systemTestSourceSet;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -67,9 +67,11 @@ public class TestSliceMetadata extends DefaultTask {
public TestSliceMetadata() { public TestSliceMetadata() {
getInputs().dir((Callable<File>) () -> this.sourceSet.getOutput().getResourcesDir()) getInputs().dir((Callable<File>) () -> this.sourceSet.getOutput().getResourcesDir())
.withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName("resources"); .withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("resources");
getInputs().files((Callable<FileCollection>) () -> this.sourceSet.getOutput().getClassesDirs()) getInputs().files((Callable<FileCollection>) () -> this.sourceSet.getOutput().getClassesDirs())
.withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName("classes"); .withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("classes");
} }
public void setSourceSet(SourceSet sourceSet) { public void setSourceSet(SourceSet sourceSet) {
@ -84,8 +86,9 @@ public class TestSliceMetadata extends DefaultTask {
public void setOutputFile(File outputFile) { public void setOutputFile(File outputFile) {
this.outputFile = outputFile; this.outputFile = outputFile;
Configuration testSliceMetadata = getProject().getConfigurations().maybeCreate("testSliceMetadata"); Configuration testSliceMetadata = getProject().getConfigurations().maybeCreate("testSliceMetadata");
getProject().getArtifacts().add(testSliceMetadata.getName(), getProject().getArtifacts()
getProject().provider((Callable<File>) this::getOutputFile), (artifact) -> artifact.builtBy(this)); .add(testSliceMetadata.getName(), getProject().provider((Callable<File>) this::getOutputFile),
(artifact) -> artifact.builtBy(this));
} }
@TaskAction @TaskAction
@ -100,8 +103,9 @@ public class TestSliceMetadata extends DefaultTask {
private Properties readTestSlices() throws IOException { private Properties readTestSlices() throws IOException {
Properties testSlices = CollectionFactory.createSortedProperties(true); Properties testSlices = CollectionFactory.createSortedProperties(true);
try (URLClassLoader classLoader = new URLClassLoader( try (URLClassLoader classLoader = new URLClassLoader(
StreamSupport.stream(this.sourceSet.getRuntimeClasspath().spliterator(), false).map(this::toURL) StreamSupport.stream(this.sourceSet.getRuntimeClasspath().spliterator(), false)
.toArray(URL[]::new))) { .map(this::toURL)
.toArray(URL[]::new))) {
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(classLoader); MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(classLoader);
Properties springFactories = readSpringFactories( Properties springFactories = readSpringFactories(
new File(this.sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories")); new File(this.sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories"));
@ -129,8 +133,8 @@ public class TestSliceMetadata extends DefaultTask {
for (File file : files) { for (File file : files) {
try { try {
List<String> lines = removeComments(Files.readAllLines(file.toPath())); List<String> lines = removeComments(Files.readAllLines(file.toPath()));
String fileNameWithoutExtension = file.getName().substring(0, String fileNameWithoutExtension = file.getName()
file.getName().length() - ".imports".length()); .substring(0, file.getName().length() - ".imports".length());
springFactories.setProperty(fileNameWithoutExtension, springFactories.setProperty(fileNameWithoutExtension,
StringUtils.collectionToCommaDelimitedString(lines)); StringUtils.collectionToCommaDelimitedString(lines));
} }
@ -176,9 +180,9 @@ public class TestSliceMetadata extends DefaultTask {
Properties springFactories) throws IOException { Properties springFactories) throws IOException {
try (Stream<Path> classes = Files.walk(classesDir.toPath())) { try (Stream<Path> classes = Files.walk(classesDir.toPath())) {
classes.filter((path) -> path.toString().endsWith("Test.class")) classes.filter((path) -> path.toString().endsWith("Test.class"))
.map((path) -> getMetadataReader(path, metadataReaderFactory)) .map((path) -> getMetadataReader(path, metadataReaderFactory))
.filter((metadataReader) -> metadataReader.getClassMetadata().isAnnotation()) .filter((metadataReader) -> metadataReader.getClassMetadata().isAnnotation())
.forEach((metadataReader) -> addTestSlice(testSlices, springFactories, metadataReader)); .forEach((metadataReader) -> addTestSlice(testSlices, springFactories, metadataReader));
} }
} }
@ -204,19 +208,20 @@ public class TestSliceMetadata extends DefaultTask {
if (annotationMetadata.isAnnotated("org.springframework.boot.autoconfigure.ImportAutoConfiguration")) { if (annotationMetadata.isAnnotated("org.springframework.boot.autoconfigure.ImportAutoConfiguration")) {
importers = Stream.concat(importers, Stream.of(annotationMetadata.getClassName())); importers = Stream.concat(importers, Stream.of(annotationMetadata.getClassName()));
} }
return importers.flatMap( return importers
(importer) -> StringUtils.commaDelimitedListToSet(springFactories.getProperty(importer)).stream()) .flatMap((importer) -> StringUtils.commaDelimitedListToSet(springFactories.getProperty(importer)).stream())
.collect(Collectors.toCollection(TreeSet::new)); .collect(Collectors.toCollection(TreeSet::new));
} }
private Stream<String> findMetaImporters(AnnotationMetadata annotationMetadata) { private Stream<String> findMetaImporters(AnnotationMetadata annotationMetadata) {
return annotationMetadata.getAnnotationTypes().stream() return annotationMetadata.getAnnotationTypes()
.filter((annotationType) -> isAutoConfigurationImporter(annotationType, annotationMetadata)); .stream()
.filter((annotationType) -> isAutoConfigurationImporter(annotationType, annotationMetadata));
} }
private boolean isAutoConfigurationImporter(String annotationType, AnnotationMetadata metadata) { private boolean isAutoConfigurationImporter(String annotationType, AnnotationMetadata metadata) {
return metadata.getMetaAnnotationTypes(annotationType) return metadata.getMetaAnnotationTypes(annotationType)
.contains("org.springframework.boot.autoconfigure.ImportAutoConfiguration"); .contains("org.springframework.boot.autoconfigure.ImportAutoConfiguration");
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,11 +36,13 @@ public class TestFailuresPlugin implements Plugin<Project> {
@Override @Override
public void apply(Project project) { public void apply(Project project) {
Provider<TestResultsOverview> testResultsOverview = project.getGradle().getSharedServices() Provider<TestResultsOverview> testResultsOverview = project.getGradle()
.registerIfAbsent("testResultsOverview", TestResultsOverview.class, (spec) -> { .getSharedServices()
}); .registerIfAbsent("testResultsOverview", TestResultsOverview.class, (spec) -> {
project.getTasks().withType(Test.class, });
(test) -> test.addTestListener(new FailureRecordingTestListener(testResultsOverview, test))); project.getTasks()
.withType(Test.class,
(test) -> test.addTestListener(new FailureRecordingTestListener(testResultsOverview, test)));
} }
private final class FailureRecordingTestListener implements TestListener { private final class FailureRecordingTestListener implements TestListener {

@ -66,7 +66,7 @@ public abstract class TestResultsOverview
System.err.println(); System.err.println();
System.err.println(task.getPath()); System.err.println(task.getPath());
failures.forEach((failure) -> System.err failures.forEach((failure) -> System.err
.println(" " + failure.descriptor.getClassName() + " > " + failure.descriptor.getName())); .println(" " + failure.descriptor.getClassName() + " > " + failure.descriptor.getName()));
}); });
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -52,16 +52,18 @@ public class ToolchainPlugin implements Plugin<Project> {
disableToolchainTasks(project); disableToolchainTasks(project);
} }
else { else {
JavaToolchainSpec toolchainSpec = project.getExtensions().getByType(JavaPluginExtension.class) JavaToolchainSpec toolchainSpec = project.getExtensions()
.getToolchain(); .getByType(JavaPluginExtension.class)
.getToolchain();
toolchainSpec.getLanguageVersion().set(toolchain.getJavaVersion()); toolchainSpec.getLanguageVersion().set(toolchain.getJavaVersion());
configureTestToolchain(project, toolchain); configureTestToolchain(project, toolchain);
} }
} }
private boolean isJavaVersionSupported(ToolchainExtension toolchain, JavaLanguageVersion toolchainVersion) { private boolean isJavaVersionSupported(ToolchainExtension toolchain, JavaLanguageVersion toolchainVersion) {
return toolchain.getMaximumCompatibleJavaVersion().map((version) -> version.canCompileOrRun(toolchainVersion)) return toolchain.getMaximumCompatibleJavaVersion()
.getOrElse(true); .map((version) -> version.canCompileOrRun(toolchainVersion))
.getOrElse(true);
} }
private void disableToolchainTasks(Project project) { private void disableToolchainTasks(Project project) {

@ -88,9 +88,9 @@ class ConventionsPluginTests {
assertThatNoticeIsPresent(jar); assertThatNoticeIsPresent(jar);
Attributes mainAttributes = jar.getManifest().getMainAttributes(); Attributes mainAttributes = jar.getManifest().getMainAttributes();
assertThat(mainAttributes.getValue("Implementation-Title")) assertThat(mainAttributes.getValue("Implementation-Title"))
.isEqualTo("Test project for manifest customization"); .isEqualTo("Test project for manifest customization");
assertThat(mainAttributes.getValue("Automatic-Module-Name")) assertThat(mainAttributes.getValue("Automatic-Module-Name"))
.isEqualTo(this.projectDir.getName().replace("-", ".")); .isEqualTo(this.projectDir.getName().replace("-", "."));
assertThat(mainAttributes.getValue("Implementation-Version")).isEqualTo("1.2.3"); assertThat(mainAttributes.getValue("Implementation-Version")).isEqualTo("1.2.3");
assertThat(mainAttributes.getValue("Built-By")).isEqualTo("Spring"); assertThat(mainAttributes.getValue("Built-By")).isEqualTo("Spring");
assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("17"); assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("17");
@ -117,9 +117,9 @@ class ConventionsPluginTests {
assertThatNoticeIsPresent(jar); assertThatNoticeIsPresent(jar);
Attributes mainAttributes = jar.getManifest().getMainAttributes(); Attributes mainAttributes = jar.getManifest().getMainAttributes();
assertThat(mainAttributes.getValue("Implementation-Title")) assertThat(mainAttributes.getValue("Implementation-Title"))
.isEqualTo("Source for " + this.projectDir.getName()); .isEqualTo("Source for " + this.projectDir.getName());
assertThat(mainAttributes.getValue("Automatic-Module-Name")) assertThat(mainAttributes.getValue("Automatic-Module-Name"))
.isEqualTo(this.projectDir.getName().replace("-", ".")); .isEqualTo(this.projectDir.getName().replace("-", "."));
assertThat(mainAttributes.getValue("Implementation-Version")).isEqualTo("1.2.3"); assertThat(mainAttributes.getValue("Implementation-Version")).isEqualTo("1.2.3");
assertThat(mainAttributes.getValue("Built-By")).isEqualTo("Spring"); assertThat(mainAttributes.getValue("Built-By")).isEqualTo("Spring");
assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("17"); assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("17");
@ -146,9 +146,9 @@ class ConventionsPluginTests {
assertThatNoticeIsPresent(jar); assertThatNoticeIsPresent(jar);
Attributes mainAttributes = jar.getManifest().getMainAttributes(); Attributes mainAttributes = jar.getManifest().getMainAttributes();
assertThat(mainAttributes.getValue("Implementation-Title")) assertThat(mainAttributes.getValue("Implementation-Title"))
.isEqualTo("Javadoc for " + this.projectDir.getName()); .isEqualTo("Javadoc for " + this.projectDir.getName());
assertThat(mainAttributes.getValue("Automatic-Module-Name")) assertThat(mainAttributes.getValue("Automatic-Module-Name"))
.isEqualTo(this.projectDir.getName().replace("-", ".")); .isEqualTo(this.projectDir.getName().replace("-", "."));
assertThat(mainAttributes.getValue("Implementation-Version")).isEqualTo("1.2.3"); assertThat(mainAttributes.getValue("Implementation-Version")).isEqualTo("1.2.3");
assertThat(mainAttributes.getValue("Built-By")).isEqualTo("Spring"); assertThat(mainAttributes.getValue("Built-By")).isEqualTo("Spring");
assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("17"); assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("17");
@ -186,7 +186,8 @@ class ConventionsPluginTests {
out.println("}"); out.println("}");
} }
assertThat(runGradle(Collections.singletonMap("CI", "true"), "retryConfig", "--stacktrace").getOutput()) assertThat(runGradle(Collections.singletonMap("CI", "true"), "retryConfig", "--stacktrace").getOutput())
.contains("maxRetries: 3").contains("failOnPassedAfterRetry: true"); .contains("maxRetries: 3")
.contains("failOnPassedAfterRetry: true");
} }
@Test @Test
@ -207,7 +208,8 @@ class ConventionsPluginTests {
out.println("}"); out.println("}");
} }
assertThat(runGradle(Collections.singletonMap("CI", "local"), "retryConfig", "--stacktrace").getOutput()) assertThat(runGradle(Collections.singletonMap("CI", "local"), "retryConfig", "--stacktrace").getOutput())
.contains("maxRetries: 0").contains("failOnPassedAfterRetry: true"); .contains("maxRetries: 0")
.contains("failOnPassedAfterRetry: true");
} }
private BuildResult runGradle(String... args) { private BuildResult runGradle(String... args) {
@ -215,8 +217,12 @@ class ConventionsPluginTests {
} }
private BuildResult runGradle(Map<String, String> environment, String... args) { private BuildResult runGradle(Map<String, String> environment, String... args) {
return GradleRunner.create().withProjectDir(this.projectDir).withEnvironment(environment).withArguments(args) return GradleRunner.create()
.withPluginClasspath().build(); .withProjectDir(this.projectDir)
.withEnvironment(environment)
.withArguments(args)
.withPluginClasspath()
.build();
} }
} }

@ -48,7 +48,8 @@ class PackageTangleCheckTests {
assertThatExceptionOfType(GradleException.class).isThrownBy(packageTangleCheck::checkForPackageTangles); assertThatExceptionOfType(GradleException.class).isThrownBy(packageTangleCheck::checkForPackageTangles);
assertThat( assertThat(
new File(packageTangleCheck.getProject().getBuildDir(), "checkForPackageTangles/failure-report.txt") new File(packageTangleCheck.getProject().getBuildDir(), "checkForPackageTangles/failure-report.txt")
.length()).isGreaterThan(0); .length())
.isGreaterThan(0);
}); });
} }
@ -58,7 +59,8 @@ class PackageTangleCheckTests {
packageTangleCheck.checkForPackageTangles(); packageTangleCheck.checkForPackageTangles();
assertThat( assertThat(
new File(packageTangleCheck.getProject().getBuildDir(), "checkForPackageTangles/failure-report.txt") new File(packageTangleCheck.getProject().getBuildDir(), "checkForPackageTangles/failure-report.txt")
.length()).isEqualTo(0); .length())
.isEqualTo(0);
}); });
} }
@ -67,8 +69,9 @@ class PackageTangleCheckTests {
projectDir.mkdirs(); projectDir.mkdirs();
copyClasses(classes, projectDir); copyClasses(classes, projectDir);
Project project = ProjectBuilder.builder().withProjectDir(projectDir).build(); Project project = ProjectBuilder.builder().withProjectDir(projectDir).build();
PackageTangleCheck packageTangleCheck = project.getTasks().create("checkForPackageTangles", PackageTangleCheck packageTangleCheck = project.getTasks()
PackageTangleCheck.class, (task) -> task.setClasses(project.files("classes"))); .create("checkForPackageTangles", PackageTangleCheck.class,
(task) -> task.setClasses(project.files("classes")));
callback.accept(packageTangleCheck); callback.accept(packageTangleCheck);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -84,7 +84,7 @@ class ArtifactReleaseTests {
Project project = ProjectBuilder.builder().build(); Project project = ProjectBuilder.builder().build();
project.setVersion("1.2.3"); project.setVersion("1.2.3");
assertThat(ArtifactRelease.forProject(project).getDownloadRepo()) assertThat(ArtifactRelease.forProject(project).getDownloadRepo())
.contains("https://repo.maven.apache.org/maven2"); .contains("https://repo.maven.apache.org/maven2");
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -319,8 +319,12 @@ class BomPluginIntegrationTests {
// } // }
private BuildResult runGradle(String... args) { private BuildResult runGradle(String... args) {
return GradleRunner.create().withDebug(true).withProjectDir(this.projectDir).withArguments(args) return GradleRunner.create()
.withPluginClasspath().build(); .withDebug(true)
.withProjectDir(this.projectDir)
.withArguments(args)
.withPluginClasspath()
.build();
} }
private void generatePom(Consumer<NodeAssert> consumer) { private void generatePom(Consumer<NodeAssert> consumer) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,7 +33,7 @@ class ConfigurationPropertiesTests {
@Test @Test
void whenJsonHasAnIntegerDefaultValueThenItRemainsAnIntegerWhenRead() { void whenJsonHasAnIntegerDefaultValueThenItRemainsAnIntegerWhenRead() {
ConfigurationProperties properties = ConfigurationProperties ConfigurationProperties properties = ConfigurationProperties
.fromFiles(Arrays.asList(new File("src/test/resources/spring-configuration-metadata.json"))); .fromFiles(Arrays.asList(new File("src/test/resources/spring-configuration-metadata.json")));
assertThat(properties.get("example.counter").getDefaultValue()).isEqualTo(0); assertThat(properties.get("example.counter").getDefaultValue()).isEqualTo(0);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -50,7 +50,8 @@ class PluginXmlParserTests {
@Test @Test
void parseNonExistingFileThrowException() { void parseNonExistingFileThrowException() {
assertThatThrownBy(() -> this.parser.parse(new File("src/test/resources/nonexistent.xml"))) assertThatThrownBy(() -> this.parser.parse(new File("src/test/resources/nonexistent.xml")))
.isInstanceOf(RuntimeException.class).hasCauseInstanceOf(FileNotFoundException.class); .isInstanceOf(RuntimeException.class)
.hasCauseInstanceOf(FileNotFoundException.class);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -50,8 +50,12 @@ class TestFailuresPluginIntegrationTests {
@Test @Test
void singleProject() { void singleProject() {
createProject(this.projectDir); createProject(this.projectDir);
BuildResult result = GradleRunner.create().withDebug(true).withProjectDir(this.projectDir) BuildResult result = GradleRunner.create()
.withArguments("build").withPluginClasspath().buildAndFail(); .withDebug(true)
.withProjectDir(this.projectDir)
.withArguments("build")
.withPluginClasspath()
.buildAndFail();
assertThat(readLines(result.getOutput())).containsSequence("Found test failures in 1 test task:", "", ":test", assertThat(readLines(result.getOutput())).containsSequence("Found test failures in 1 test task:", "", ":test",
" example.ExampleTests > bad()", " example.ExampleTests > fail()", " example.ExampleTests > bad()", " example.ExampleTests > fail()",
" example.MoreTests > bad()", " example.MoreTests > fail()", ""); " example.MoreTests > bad()", " example.MoreTests > fail()", "");
@ -60,8 +64,12 @@ class TestFailuresPluginIntegrationTests {
@Test @Test
void multiProject() { void multiProject() {
createMultiProjectBuild(); createMultiProjectBuild();
BuildResult result = GradleRunner.create().withDebug(true).withProjectDir(this.projectDir) BuildResult result = GradleRunner.create()
.withArguments("build").withPluginClasspath().buildAndFail(); .withDebug(true)
.withProjectDir(this.projectDir)
.withArguments("build")
.withPluginClasspath()
.buildAndFail();
assertThat(readLines(result.getOutput())).containsSequence("Found test failures in 1 test task:", "", assertThat(readLines(result.getOutput())).containsSequence("Found test failures in 1 test task:", "",
":project-one:test", " example.ExampleTests > bad()", " example.ExampleTests > fail()", ":project-one:test", " example.ExampleTests > bad()", " example.ExampleTests > fail()",
" example.MoreTests > bad()", " example.MoreTests > fail()", ""); " example.MoreTests > bad()", " example.MoreTests > fail()", "");
@ -70,8 +78,12 @@ class TestFailuresPluginIntegrationTests {
@Test @Test
void multiProjectContinue() { void multiProjectContinue() {
createMultiProjectBuild(); createMultiProjectBuild();
BuildResult result = GradleRunner.create().withDebug(true).withProjectDir(this.projectDir) BuildResult result = GradleRunner.create()
.withArguments("build", "--continue").withPluginClasspath().buildAndFail(); .withDebug(true)
.withProjectDir(this.projectDir)
.withArguments("build", "--continue")
.withPluginClasspath()
.buildAndFail();
assertThat(readLines(result.getOutput())).containsSequence("Found test failures in 2 test tasks:", "", assertThat(readLines(result.getOutput())).containsSequence("Found test failures in 2 test tasks:", "",
":project-one:test", " example.ExampleTests > bad()", " example.ExampleTests > fail()", ":project-one:test", " example.ExampleTests > bad()", " example.ExampleTests > fail()",
" example.MoreTests > bad()", " example.MoreTests > fail()", "", ":project-two:test", " example.MoreTests > bad()", " example.MoreTests > fail()", "", ":project-two:test",
@ -82,8 +94,12 @@ class TestFailuresPluginIntegrationTests {
@Test @Test
void multiProjectParallel() { void multiProjectParallel() {
createMultiProjectBuild(); createMultiProjectBuild();
BuildResult result = GradleRunner.create().withDebug(true).withProjectDir(this.projectDir) BuildResult result = GradleRunner.create()
.withArguments("build", "--parallel", "--stacktrace").withPluginClasspath().buildAndFail(); .withDebug(true)
.withProjectDir(this.projectDir)
.withArguments("build", "--parallel", "--stacktrace")
.withPluginClasspath()
.buildAndFail();
assertThat(readLines(result.getOutput())).containsSequence("Found test failures in 2 test tasks:", "", assertThat(readLines(result.getOutput())).containsSequence("Found test failures in 2 test tasks:", "",
":project-one:test", " example.ExampleTests > bad()", " example.ExampleTests > fail()", ":project-one:test", " example.ExampleTests > bad()", " example.ExampleTests > fail()",
" example.MoreTests > bad()", " example.MoreTests > fail()", "", ":project-two:test", " example.MoreTests > bad()", " example.MoreTests > fail()", "", ":project-two:test",

@ -48,7 +48,7 @@ public abstract class OnEndpointElementCondition extends SpringBootCondition {
@Override @Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotationAttributes annotationAttributes = AnnotationAttributes AnnotationAttributes annotationAttributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(this.annotationType.getName())); .fromMap(metadata.getAnnotationAttributes(this.annotationType.getName()));
String endpointName = annotationAttributes.getString("value"); String endpointName = annotationAttributes.getString("value");
ConditionOutcome outcome = getEndpointOutcome(context, endpointName); ConditionOutcome outcome = getEndpointOutcome(context, endpointName);
if (outcome != null) { if (outcome != null) {
@ -63,7 +63,7 @@ public abstract class OnEndpointElementCondition extends SpringBootCondition {
if (environment.containsProperty(enabledProperty)) { if (environment.containsProperty(enabledProperty)) {
boolean match = environment.getProperty(enabledProperty, Boolean.class, true); boolean match = environment.getProperty(enabledProperty, Boolean.class, true);
return new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType) return new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType)
.because(this.prefix + endpointName + ".enabled is " + match)); .because(this.prefix + endpointName + ".enabled is " + match));
} }
return null; return null;
} }
@ -79,9 +79,9 @@ public abstract class OnEndpointElementCondition extends SpringBootCondition {
*/ */
protected ConditionOutcome getDefaultOutcome(ConditionContext context, AnnotationAttributes annotationAttributes) { protected ConditionOutcome getDefaultOutcome(ConditionContext context, AnnotationAttributes annotationAttributes) {
boolean match = Boolean boolean match = Boolean
.parseBoolean(context.getEnvironment().getProperty(this.prefix + "defaults.enabled", "true")); .parseBoolean(context.getEnvironment().getProperty(this.prefix + "defaults.enabled", "true"));
return new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType) return new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType)
.because(this.prefix + "defaults.enabled is considered " + match)); .because(this.prefix + "defaults.enabled is considered " + match));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,7 +36,7 @@ class AvailabilityProbesHealthEndpointGroupsPostProcessor implements HealthEndpo
AvailabilityProbesHealthEndpointGroupsPostProcessor(Environment environment) { AvailabilityProbesHealthEndpointGroupsPostProcessor(Environment environment) {
this.addAdditionalPaths = "true" this.addAdditionalPaths = "true"
.equalsIgnoreCase(environment.getProperty("management.endpoint.health.probes.add-additional-paths")); .equalsIgnoreCase(environment.getProperty("management.endpoint.health.probes.add-additional-paths"));
} }
@Override @Override

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -73,8 +73,11 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
} }
private boolean isHealthEndpointExtension(Class<?> extensionBeanType) { private boolean isHealthEndpointExtension(Class<?> extensionBeanType) {
return MergedAnnotations.from(extensionBeanType).get(EndpointWebExtension.class) return MergedAnnotations.from(extensionBeanType)
.getValue("endpoint", Class.class).map(HealthEndpoint.class::isAssignableFrom).orElse(false); .get(EndpointWebExtension.class)
.getValue("endpoint", Class.class)
.map(HealthEndpoint.class::isAssignableFrom)
.orElse(false);
} }
private boolean isCloudFoundryHealthEndpointExtension(Class<?> extensionBeanType) { private boolean isCloudFoundryHealthEndpointExtension(Class<?> extensionBeanType) {
@ -85,8 +88,8 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
@Override @Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) { public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(CloudFoundryEndpointFilter.class, hints.reflection()
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); .registerType(CloudFoundryEndpointFilter.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -80,12 +80,12 @@ class CloudFoundrySecurityInterceptor {
try { try {
Token token = getToken(exchange.getRequest()); Token token = getToken(exchange.getRequest());
return this.tokenValidator.validate(token) return this.tokenValidator.validate(token)
.then(this.cloudFoundrySecurityService.getAccessLevel(token.toString(), this.applicationId)) .then(this.cloudFoundrySecurityService.getAccessLevel(token.toString(), this.applicationId))
.filter((accessLevel) -> accessLevel.isAccessAllowed(id)) .filter((accessLevel) -> accessLevel.isAccessAllowed(id))
.switchIfEmpty( .switchIfEmpty(
Mono.error(new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, "Access denied"))) Mono.error(new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, "Access denied")))
.doOnSuccess((accessLevel) -> exchange.getAttributes().put("cloudFoundryAccessLevel", accessLevel)) .doOnSuccess((accessLevel) -> exchange.getAttributes().put("cloudFoundryAccessLevel", accessLevel))
.then(); .then();
} }
catch (CloudFoundryAuthorizationException ex) { catch (CloudFoundryAuthorizationException ex) {
return Mono.error(ex); return Mono.error(ex);

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -91,26 +91,26 @@ class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointH
public Publisher<ResponseEntity<Object>> links(ServerWebExchange exchange) { public Publisher<ResponseEntity<Object>> links(ServerWebExchange exchange) {
ServerHttpRequest request = exchange.getRequest(); ServerHttpRequest request = exchange.getRequest();
return CloudFoundryWebFluxEndpointHandlerMapping.this.securityInterceptor.preHandle(exchange, "") return CloudFoundryWebFluxEndpointHandlerMapping.this.securityInterceptor.preHandle(exchange, "")
.map((securityResponse) -> { .map((securityResponse) -> {
if (!securityResponse.getStatus().equals(HttpStatus.OK)) { if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
return new ResponseEntity<>(securityResponse.getStatus()); return new ResponseEntity<>(securityResponse.getStatus());
} }
AccessLevel accessLevel = exchange.getAttribute(AccessLevel.REQUEST_ATTRIBUTE); AccessLevel accessLevel = exchange.getAttribute(AccessLevel.REQUEST_ATTRIBUTE);
Map<String, Link> links = CloudFoundryWebFluxEndpointHandlerMapping.this.linksResolver Map<String, Link> links = CloudFoundryWebFluxEndpointHandlerMapping.this.linksResolver
.resolveLinks(request.getURI().toString()); .resolveLinks(request.getURI().toString());
return new ResponseEntity<>( return new ResponseEntity<>(
Collections.singletonMap("_links", getAccessibleLinks(accessLevel, links)), Collections.singletonMap("_links", getAccessibleLinks(accessLevel, links)), HttpStatus.OK);
HttpStatus.OK); });
});
} }
private Map<String, Link> getAccessibleLinks(AccessLevel accessLevel, Map<String, Link> links) { private Map<String, Link> getAccessibleLinks(AccessLevel accessLevel, Map<String, Link> links) {
if (accessLevel == null) { if (accessLevel == null) {
return new LinkedHashMap<>(); return new LinkedHashMap<>();
} }
return links.entrySet().stream() return links.entrySet()
.filter((entry) -> entry.getKey().equals("self") || accessLevel.isAccessAllowed(entry.getKey())) .stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .filter((entry) -> entry.getKey().equals("self") || accessLevel.isAccessAllowed(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
} }
@Override @Override
@ -141,7 +141,7 @@ class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointH
@Override @Override
public Mono<ResponseEntity<Object>> handle(ServerWebExchange exchange, Map<String, String> body) { public Mono<ResponseEntity<Object>> handle(ServerWebExchange exchange, Map<String, String> body) {
return this.securityInterceptor.preHandle(exchange, this.endpointId.toLowerCaseString()) return this.securityInterceptor.preHandle(exchange, this.endpointId.toLowerCaseString())
.flatMap((securityResponse) -> flatMapResponse(exchange, body, securityResponse)); .flatMap((securityResponse) -> flatMapResponse(exchange, body, securityResponse));
} }
private Mono<ResponseEntity<Object>> flatMapResponse(ServerWebExchange exchange, Map<String, String> body, private Mono<ResponseEntity<Object>> flatMapResponse(ServerWebExchange exchange, Map<String, String> body,

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -96,9 +96,9 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension(GitProperties properties, public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension(GitProperties properties,
ObjectProvider<InfoContributor> infoContributors) { ObjectProvider<InfoContributor> infoContributors) {
List<InfoContributor> contributors = infoContributors.orderedStream() List<InfoContributor> contributors = infoContributors.orderedStream()
.map((infoContributor) -> (infoContributor instanceof GitInfoContributor) .map((infoContributor) -> (infoContributor instanceof GitInfoContributor)
? new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL) : infoContributor) ? new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL) : infoContributor)
.toList(); .toList();
return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors)); return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors));
} }
@ -143,8 +143,8 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
CorsConfiguration corsConfiguration = new CorsConfiguration(); CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL); corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
corsConfiguration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name())); corsConfiguration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));
corsConfiguration.setAllowedHeaders( corsConfiguration
Arrays.asList(HttpHeaders.AUTHORIZATION, "X-Cf-App-Instance", HttpHeaders.CONTENT_TYPE)); .setAllowedHeaders(Arrays.asList(HttpHeaders.AUTHORIZATION, "X-Cf-App-Instance", HttpHeaders.CONTENT_TYPE));
return corsConfiguration; return corsConfiguration;
} }
@ -171,7 +171,7 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
private WebFilterChainProxy postProcess(WebFilterChainProxy existing) { private WebFilterChainProxy postProcess(WebFilterChainProxy existing) {
ServerWebExchangeMatcher cloudFoundryRequestMatcher = ServerWebExchangeMatchers ServerWebExchangeMatcher cloudFoundryRequestMatcher = ServerWebExchangeMatchers
.pathMatchers("/cloudfoundryapplication/**"); .pathMatchers("/cloudfoundryapplication/**");
WebFilter noOpFilter = (exchange, chain) -> chain.filter(exchange); WebFilter noOpFilter = (exchange, chain) -> chain.filter(exchange);
MatcherSecurityWebFilterChain ignoredRequestFilterChain = new MatcherSecurityWebFilterChain( MatcherSecurityWebFilterChain ignoredRequestFilterChain = new MatcherSecurityWebFilterChain(
cloudFoundryRequestMatcher, Collections.singletonList(noOpFilter)); cloudFoundryRequestMatcher, Collections.singletonList(noOpFilter));

@ -72,8 +72,9 @@ class ReactiveCloudFoundrySecurityService {
} }
private Http11SslContextSpec createSslContextSpec() { private Http11SslContextSpec createSslContextSpec() {
return Http11SslContextSpec.forClient().configure( return Http11SslContextSpec.forClient()
(builder) -> builder.sslProvider(SslProvider.JDK).trustManager(InsecureTrustManagerFactory.INSTANCE)); .configure((builder) -> builder.sslProvider(SslProvider.JDK)
.trustManager(InsecureTrustManagerFactory.INSTANCE));
} }
/** /**
@ -85,8 +86,13 @@ class ReactiveCloudFoundrySecurityService {
*/ */
Mono<AccessLevel> getAccessLevel(String token, String applicationId) throws CloudFoundryAuthorizationException { Mono<AccessLevel> getAccessLevel(String token, String applicationId) throws CloudFoundryAuthorizationException {
String uri = getPermissionsUri(applicationId); String uri = getPermissionsUri(applicationId);
return this.webClient.get().uri(uri).header("Authorization", "bearer " + token).retrieve().bodyToMono(Map.class) return this.webClient.get()
.map(this::getAccessLevel).onErrorMap(this::mapError); .uri(uri)
.header("Authorization", "bearer " + token)
.retrieve()
.bodyToMono(Map.class)
.map(this::getAccessLevel)
.onErrorMap(this::mapError);
} }
private Throwable mapError(Throwable throwable) { private Throwable mapError(Throwable throwable) {
@ -123,8 +129,10 @@ class ReactiveCloudFoundrySecurityService {
private Mono<? extends Map<String, String>> fetchTokenKeys(String url) { private Mono<? extends Map<String, String>> fetchTokenKeys(String url) {
RequestHeadersSpec<?> uri = this.webClient.get().uri(url + "/token_keys"); RequestHeadersSpec<?> uri = this.webClient.get().uri(url + "/token_keys");
return uri.retrieve().bodyToMono(STRING_OBJECT_MAP).map(this::extractTokenKeys).onErrorMap( return uri.retrieve()
((ex) -> new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, ex.getMessage()))); .bodyToMono(STRING_OBJECT_MAP)
.map(this::extractTokenKeys)
.onErrorMap(((ex) -> new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, ex.getMessage())));
} }
private Map<String, String> extractTokenKeys(Map<String, Object> response) { private Map<String, String> extractTokenKeys(Map<String, Object> response) {
@ -141,10 +149,14 @@ class ReactiveCloudFoundrySecurityService {
* @return the UAA url Mono * @return the UAA url Mono
*/ */
Mono<String> getUaaUrl() { Mono<String> getUaaUrl() {
this.uaaUrl = this.webClient.get().uri(this.cloudControllerUrl + "/info").retrieve().bodyToMono(Map.class) this.uaaUrl = this.webClient.get()
.map((response) -> (String) response.get("token_endpoint")).cache() .uri(this.cloudControllerUrl + "/info")
.onErrorMap((ex) -> new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, .retrieve()
"Unable to fetch token keys from UAA.")); .bodyToMono(Map.class)
.map((response) -> (String) response.get("token_endpoint"))
.cache()
.onErrorMap((ex) -> new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
"Unable to fetch token keys from UAA."));
return this.uaaUrl; return this.uaaUrl;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -51,8 +51,10 @@ class ReactiveTokenValidator {
} }
Mono<Void> validate(Token token) { Mono<Void> validate(Token token) {
return validateAlgorithm(token).then(validateKeyIdAndSignature(token)).then(validateExpiry(token)) return validateAlgorithm(token).then(validateKeyIdAndSignature(token))
.then(validateIssuer(token)).then(validateAudience(token)); .then(validateExpiry(token))
.then(validateIssuer(token))
.then(validateAudience(token));
} }
private Mono<Void> validateAlgorithm(Token token) { private Mono<Void> validateAlgorithm(Token token) {
@ -70,9 +72,9 @@ class ReactiveTokenValidator {
private Mono<Void> validateKeyIdAndSignature(Token token) { private Mono<Void> validateKeyIdAndSignature(Token token) {
return getTokenKey(token).filter((tokenKey) -> hasValidSignature(token, tokenKey)) return getTokenKey(token).filter((tokenKey) -> hasValidSignature(token, tokenKey))
.switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE, .switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE,
"RSA Signature did not match content"))) "RSA Signature did not match content")))
.then(); .then();
} }
private Mono<String> getTokenKey(Token token) { private Mono<String> getTokenKey(Token token) {
@ -81,10 +83,12 @@ class ReactiveTokenValidator {
if (cached != null) { if (cached != null) {
return Mono.just(cached); return Mono.just(cached);
} }
return this.securityService.fetchTokenKeys().doOnSuccess(this::cacheTokenKeys) return this.securityService.fetchTokenKeys()
.filter((tokenKeys) -> tokenKeys.containsKey(keyId)).map((tokenKeys) -> tokenKeys.get(keyId)) .doOnSuccess(this::cacheTokenKeys)
.switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_KEY_ID, .filter((tokenKeys) -> tokenKeys.containsKey(keyId))
"Key Id present in token header does not match"))); .map((tokenKeys) -> tokenKeys.get(keyId))
.switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_KEY_ID,
"Key Id present in token header does not match")));
} }
private void cacheTokenKeys(Map<String, String> tokenKeys) { private void cacheTokenKeys(Map<String, String> tokenKeys) {
@ -122,11 +126,12 @@ class ReactiveTokenValidator {
} }
private Mono<Void> validateIssuer(Token token) { private Mono<Void> validateIssuer(Token token) {
return this.securityService.getUaaUrl().map((uaaUrl) -> String.format("%s/oauth/token", uaaUrl)) return this.securityService.getUaaUrl()
.filter((issuerUri) -> issuerUri.equals(token.getIssuer())) .map((uaaUrl) -> String.format("%s/oauth/token", uaaUrl))
.switchIfEmpty(Mono.error( .filter((issuerUri) -> issuerUri.equals(token.getIssuer()))
new CloudFoundryAuthorizationException(Reason.INVALID_ISSUER, "Token issuer does not match"))) .switchIfEmpty(Mono
.then(); .error(new CloudFoundryAuthorizationException(Reason.INVALID_ISSUER, "Token issuer does not match")))
.then();
} }
private Mono<Void> validateAudience(Token token) { private Mono<Void> validateAudience(Token token) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -100,9 +100,9 @@ public class CloudFoundryActuatorAutoConfiguration {
public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension(GitProperties properties, public CloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension(GitProperties properties,
ObjectProvider<InfoContributor> infoContributors) { ObjectProvider<InfoContributor> infoContributors) {
List<InfoContributor> contributors = infoContributors.orderedStream() List<InfoContributor> contributors = infoContributors.orderedStream()
.map((infoContributor) -> (infoContributor instanceof GitInfoContributor) .map((infoContributor) -> (infoContributor instanceof GitInfoContributor)
? new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL) : infoContributor) ? new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL) : infoContributor)
.toList(); .toList();
return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors)); return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors));
} }
@ -147,8 +147,8 @@ public class CloudFoundryActuatorAutoConfiguration {
CorsConfiguration corsConfiguration = new CorsConfiguration(); CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL); corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
corsConfiguration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name())); corsConfiguration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));
corsConfiguration.setAllowedHeaders( corsConfiguration
Arrays.asList(HttpHeaders.AUTHORIZATION, "X-Cf-App-Instance", HttpHeaders.CONTENT_TYPE)); .setAllowedHeaders(Arrays.asList(HttpHeaders.AUTHORIZATION, "X-Cf-App-Instance", HttpHeaders.CONTENT_TYPE));
return corsConfiguration; return corsConfiguration;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -94,7 +94,7 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpoin
@Reflective @Reflective
public Map<String, Map<String, Link>> links(HttpServletRequest request, HttpServletResponse response) { public Map<String, Map<String, Link>> links(HttpServletRequest request, HttpServletResponse response) {
SecurityResponse securityResponse = CloudFoundryWebEndpointServletHandlerMapping.this.securityInterceptor SecurityResponse securityResponse = CloudFoundryWebEndpointServletHandlerMapping.this.securityInterceptor
.preHandle(request, null); .preHandle(request, null);
if (!securityResponse.getStatus().equals(HttpStatus.OK)) { if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
sendFailureResponse(response, securityResponse); sendFailureResponse(response, securityResponse);
} }
@ -104,10 +104,11 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpoin
return Collections.singletonMap("_links", filteredLinks); return Collections.singletonMap("_links", filteredLinks);
} }
Map<String, Link> links = CloudFoundryWebEndpointServletHandlerMapping.this.linksResolver Map<String, Link> links = CloudFoundryWebEndpointServletHandlerMapping.this.linksResolver
.resolveLinks(request.getRequestURL().toString()); .resolveLinks(request.getRequestURL().toString());
filteredLinks = links.entrySet().stream() filteredLinks = links.entrySet()
.filter((e) -> e.getKey().equals("self") || accessLevel.isAccessAllowed(e.getKey())) .stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .filter((e) -> e.getKey().equals("self") || accessLevel.isAccessAllowed(e.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return Collections.singletonMap("_links", filteredLinks); return Collections.singletonMap("_links", filteredLinks);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -68,7 +68,7 @@ class OnAvailableEndpointCondition extends SpringBootCondition {
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment(); Environment environment = context.getEnvironment();
MergedAnnotation<ConditionalOnAvailableEndpoint> conditionAnnotation = metadata.getAnnotations() MergedAnnotation<ConditionalOnAvailableEndpoint> conditionAnnotation = metadata.getAnnotations()
.get(ConditionalOnAvailableEndpoint.class); .get(ConditionalOnAvailableEndpoint.class);
Class<?> target = getTarget(context, metadata, conditionAnnotation); Class<?> target = getTarget(context, metadata, conditionAnnotation);
MergedAnnotation<Endpoint> endpointAnnotation = getEndpointAnnotation(target); MergedAnnotation<Endpoint> endpointAnnotation = getEndpointAnnotation(target);
return getMatchOutcome(environment, conditionAnnotation, endpointAnnotation); return getMatchOutcome(environment, conditionAnnotation, endpointAnnotation);
@ -134,8 +134,8 @@ class OnAvailableEndpointCondition extends SpringBootCondition {
} }
Boolean userDefinedDefault = isEnabledByDefault(environment); Boolean userDefinedDefault = isEnabledByDefault(environment);
if (userDefinedDefault != null) { if (userDefinedDefault != null) {
return new ConditionOutcome(userDefinedDefault, message.because( return new ConditionOutcome(userDefinedDefault, message
"no property " + key + " found so using user defined default from " + ENABLED_BY_DEFAULT_KEY)); .because("no property " + key + " found so using user defined default from " + ENABLED_BY_DEFAULT_KEY));
} }
boolean endpointDefault = endpointAnnotation.getBoolean("enableByDefault"); boolean endpointDefault = endpointAnnotation.getBoolean("enableByDefault");
return new ConditionOutcome(endpointDefault, return new ConditionOutcome(endpointDefault,

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -45,9 +45,10 @@ public class JacksonEndpointAutoConfiguration {
@ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class }) @ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class })
public EndpointObjectMapper endpointObjectMapper() { public EndpointObjectMapper endpointObjectMapper() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json() ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS) SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)
.serializationInclusion(Include.NON_NULL).build(); .serializationInclusion(Include.NON_NULL)
.build();
return () -> objectMapper; return () -> objectMapper;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -89,7 +89,7 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {
} }
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
this.properties.getStaticNames() this.properties.getStaticNames()
.forEach((name, value) -> builder.append(",").append(name).append("=").append(value)); .forEach((name, value) -> builder.append(",").append(name).append("=").append(value));
return builder.toString(); return builder.toString();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -101,7 +101,9 @@ class JerseyWebEndpointManagementContextConfiguration {
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups healthEndpointGroups) { WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups healthEndpointGroups) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints(); Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
ExposableWebEndpoint health = webEndpoints.stream() ExposableWebEndpoint health = webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HEALTH_ENDPOINT_ID)).findFirst().get(); .filter((endpoint) -> endpoint.getEndpointId().equals(HEALTH_ENDPOINT_ID))
.findFirst()
.get();
return new JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(health, healthEndpointGroups); return new JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(health, healthEndpointGroups);
} }
@ -195,8 +197,10 @@ class JerseyWebEndpointManagementContextConfiguration {
JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory( JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(
WebServerNamespace.MANAGEMENT, this.groups); WebServerNamespace.MANAGEMENT, this.groups);
Collection<Resource> endpointResources = resourceFactory Collection<Resource> endpointResources = resourceFactory
.createEndpointResources(mapping, Collections.singletonList(this.endpoint), null, null, false) .createEndpointResources(mapping, Collections.singletonList(this.endpoint), null, null, false)
.stream().filter(Objects::nonNull).toList(); .stream()
.filter(Objects::nonNull)
.toList();
register(endpointResources, config); register(endpointResources, config);
} }

@ -118,7 +118,9 @@ public class WebFluxEndpointManagementContextConfiguration {
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) { WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints(); Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
ExposableWebEndpoint health = webEndpoints.stream() ExposableWebEndpoint health = webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID)).findFirst().get(); .filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
.findFirst()
.get();
return new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(""), health, return new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(""), health,
groups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT)); groups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT));
} }
@ -149,7 +151,7 @@ public class WebFluxEndpointManagementContextConfiguration {
static class ServerCodecConfigurerEndpointObjectMapperBeanPostProcessor implements BeanPostProcessor { static class ServerCodecConfigurerEndpointObjectMapperBeanPostProcessor implements BeanPostProcessor {
private static final List<MediaType> MEDIA_TYPES = Collections private static final List<MediaType> MEDIA_TYPES = Collections
.unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType("application", "*+json"))); .unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType("application", "*+json")));
private final Supplier<EndpointObjectMapper> endpointObjectMapper; private final Supplier<EndpointObjectMapper> endpointObjectMapper;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -113,7 +113,9 @@ public class WebMvcEndpointManagementContextConfiguration {
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) { WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints(); Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
ExposableWebEndpoint health = webEndpoints.stream() ExposableWebEndpoint health = webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID)).findFirst().get(); .filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
.findFirst()
.get();
return new AdditionalHealthEndpointPathsWebMvcHandlerMapping(health, return new AdditionalHealthEndpointPathsWebMvcHandlerMapping(health,
groups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT)); groups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT));
} }
@ -144,7 +146,7 @@ public class WebMvcEndpointManagementContextConfiguration {
static class EndpointObjectMapperWebMvcConfigurer implements WebMvcConfigurer { static class EndpointObjectMapperWebMvcConfigurer implements WebMvcConfigurer {
private static final List<MediaType> MEDIA_TYPES = Collections private static final List<MediaType> MEDIA_TYPES = Collections
.unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType("application", "*+json"))); .unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType("application", "*+json")));
private final EndpointObjectMapper endpointObjectMapper; private final EndpointObjectMapper endpointObjectMapper;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -93,7 +93,7 @@ public abstract class AbstractCompositeHealthContributorConfiguration<C, I exten
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException("Unable to create health indicator %s for bean type %s" throw new IllegalStateException("Unable to create health indicator %s for bean type %s"
.formatted(this.indicatorType, this.beanType), ex); .formatted(this.indicatorType, this.beanType), ex);
} }
} }

@ -120,7 +120,7 @@ class HealthEndpointConfiguration {
private Object applyPostProcessors(HealthEndpointGroups bean) { private Object applyPostProcessors(HealthEndpointGroups bean) {
for (HealthEndpointGroupsPostProcessor postProcessor : this.postProcessors.orderedStream() for (HealthEndpointGroupsPostProcessor postProcessor : this.postProcessors.orderedStream()
.toArray(HealthEndpointGroupsPostProcessor[]::new)) { .toArray(HealthEndpointGroupsPostProcessor[]::new)) {
bean = postProcessor.postProcessHealthEndpointGroups(bean); bean = postProcessor.postProcessHealthEndpointGroups(bean);
} }
return bean; return bean;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -68,7 +68,9 @@ class HealthEndpointReactiveWebExtensionConfiguration {
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) { WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints(); Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
ExposableWebEndpoint health = webEndpoints.stream() ExposableWebEndpoint health = webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID)).findFirst().get(); .filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
.findFirst()
.get();
return new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(""), health, return new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(""), health,
groups.getAllWithAdditionalPath(WebServerNamespace.SERVER)); groups.getAllWithAdditionalPath(WebServerNamespace.SERVER));
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -78,8 +78,10 @@ class HealthEndpointWebExtensionConfiguration {
private static ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) { private static ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints(); Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
return webEndpoints.stream().filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID)) return webEndpoints.stream()
.findFirst().get(); .filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
.findFirst()
.get();
} }
@ConditionalOnBean(DispatcherServlet.class) @ConditionalOnBean(DispatcherServlet.class)
@ -160,8 +162,10 @@ class HealthEndpointWebExtensionConfiguration {
JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory( JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(
WebServerNamespace.SERVER, this.groups); WebServerNamespace.SERVER, this.groups);
Collection<Resource> endpointResources = resourceFactory Collection<Resource> endpointResources = resourceFactory
.createEndpointResources(mapping, Collections.singletonList(this.endpoint), null, null, false) .createEndpointResources(mapping, Collections.singletonList(this.endpoint), null, null, false)
.stream().filter(Objects::nonNull).toList(); .stream()
.filter(Objects::nonNull)
.toList();
register(endpointResources, config); register(endpointResources, config);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -39,7 +39,7 @@ class OnEnabledInfoContributorCondition extends OnEndpointElementCondition {
InfoContributorFallback fallback = annotationAttributes.getEnum("fallback"); InfoContributorFallback fallback = annotationAttributes.getEnum("fallback");
if (fallback == InfoContributorFallback.DISABLE) { if (fallback == InfoContributorFallback.DISABLE) {
return new ConditionOutcome(false, ConditionMessage.forCondition(ConditionalOnEnabledInfoContributor.class) return new ConditionOutcome(false, ConditionMessage.forCondition(ConditionalOnEnabledInfoContributor.class)
.because("management.info." + annotationAttributes.getString("value") + ".enabled is not true")); .because("management.info." + annotationAttributes.getString("value") + ".enabled is not true"));
} }
return super.getDefaultOutcome(context, annotationAttributes); return super.getDefaultOutcome(context, annotationAttributes);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -86,9 +86,10 @@ public class DataSourceHealthContributorAutoConfiguration implements Initializin
public HealthContributor dbHealthContributor(Map<String, DataSource> dataSources, public HealthContributor dbHealthContributor(Map<String, DataSource> dataSources,
DataSourceHealthIndicatorProperties dataSourceHealthIndicatorProperties) { DataSourceHealthIndicatorProperties dataSourceHealthIndicatorProperties) {
if (dataSourceHealthIndicatorProperties.isIgnoreRoutingDataSources()) { if (dataSourceHealthIndicatorProperties.isIgnoreRoutingDataSources()) {
Map<String, DataSource> filteredDatasources = dataSources.entrySet().stream() Map<String, DataSource> filteredDatasources = dataSources.entrySet()
.filter((e) -> !(e.getValue() instanceof AbstractRoutingDataSource)) .stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .filter((e) -> !(e.getValue() instanceof AbstractRoutingDataSource))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return createContributor(filteredDatasources); return createContributor(filteredDatasources);
} }
return createContributor(dataSources); return createContributor(dataSources);
@ -127,9 +128,11 @@ public class DataSourceHealthContributorAutoConfiguration implements Initializin
RoutingDataSourceHealthContributor(AbstractRoutingDataSource routingDataSource, RoutingDataSourceHealthContributor(AbstractRoutingDataSource routingDataSource,
Function<DataSource, HealthContributor> contributorFunction) { Function<DataSource, HealthContributor> contributorFunction) {
Map<String, DataSource> routedDataSources = routingDataSource.getResolvedDataSources().entrySet().stream() Map<String, DataSource> routedDataSources = routingDataSource.getResolvedDataSources()
.collect(Collectors.toMap((e) -> Objects.toString(e.getKey(), UNNAMED_DATASOURCE_KEY), .entrySet()
Map.Entry::getValue)); .stream()
.collect(Collectors.toMap((e) -> Objects.toString(e.getKey(), UNNAMED_DATASOURCE_KEY),
Map.Entry::getValue));
this.delegate = CompositeHealthContributor.fromMap(routedDataSources, contributorFunction); this.delegate = CompositeHealthContributor.fromMap(routedDataSources, contributorFunction);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -59,8 +59,8 @@ public class LoggersEndpointAutoConfiguration {
ConditionMessage.Builder message = ConditionMessage.forCondition("Logging System"); ConditionMessage.Builder message = ConditionMessage.forCondition("Logging System");
String loggingSystem = System.getProperty(LoggingSystem.SYSTEM_PROPERTY); String loggingSystem = System.getProperty(LoggingSystem.SYSTEM_PROPERTY);
if (LoggingSystem.NONE.equals(loggingSystem)) { if (LoggingSystem.NONE.equals(loggingSystem)) {
return ConditionOutcome.noMatch( return ConditionOutcome
message.because("system property " + LoggingSystem.SYSTEM_PROPERTY + " is set to none")); .noMatch(message.because("system property " + LoggingSystem.SYSTEM_PROPERTY + " is set to none"));
} }
return ConditionOutcome.match(message.because("enabled")); return ConditionOutcome.match(message.because("enabled"));
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -60,14 +60,14 @@ public class Log4J2MetricsAutoConfiguration {
try { try {
if (Class.forName("org.apache.logging.log4j.core.LoggerContext").isInstance(loggerContext)) { if (Class.forName("org.apache.logging.log4j.core.LoggerContext").isInstance(loggerContext)) {
return ConditionOutcome return ConditionOutcome
.match("LoggerContext was an instance of org.apache.logging.log4j.core.LoggerContext"); .match("LoggerContext was an instance of org.apache.logging.log4j.core.LoggerContext");
} }
} }
catch (Throwable ex) { catch (Throwable ex) {
// Continue with no match // Continue with no match
} }
return ConditionOutcome return ConditionOutcome
.noMatch("Logger context was not an instance of org.apache.logging.log4j.core.LoggerContext"); .noMatch("Logger context was not an instance of org.apache.logging.log4j.core.LoggerContext");
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -108,8 +108,8 @@ class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializing
private void applyCustomizers(MeterRegistry meterRegistry) { private void applyCustomizers(MeterRegistry meterRegistry) {
List<MeterRegistryCustomizer<?>> customizers = this.customizers.orderedStream().toList(); List<MeterRegistryCustomizer<?>> customizers = this.customizers.orderedStream().toList();
LambdaSafe.callbacks(MeterRegistryCustomizer.class, customizers, meterRegistry) LambdaSafe.callbacks(MeterRegistryCustomizer.class, customizers, meterRegistry)
.withLogger(MeterRegistryPostProcessor.class) .withLogger(MeterRegistryPostProcessor.class)
.invoke((customizer) -> customizer.customize(meterRegistry)); .invoke((customizer) -> customizer.customize(meterRegistry));
} }
private void applyFilters(MeterRegistry meterRegistry) { private void applyFilters(MeterRegistry meterRegistry) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -42,7 +42,7 @@ public class PropertiesAutoTimer implements AutoTimer {
@Override @Override
public void apply(Builder builder) { public void apply(Builder builder) {
builder.publishPercentileHistogram(this.properties.isPercentilesHistogram()) builder.publishPercentileHistogram(this.properties.isPercentilesHistogram())
.publishPercentiles(this.properties.getPercentiles()); .publishPercentiles(this.properties.getPercentiles());
} }
@Override @Override

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -84,24 +84,29 @@ public class PropertiesMeterFilter implements MeterFilter {
public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
Distribution distribution = this.properties.getDistribution(); Distribution distribution = this.properties.getDistribution();
return DistributionStatisticConfig.builder() return DistributionStatisticConfig.builder()
.percentilesHistogram(lookupWithFallbackToAll(distribution.getPercentilesHistogram(), id, null)) .percentilesHistogram(lookupWithFallbackToAll(distribution.getPercentilesHistogram(), id, null))
.percentiles(lookupWithFallbackToAll(distribution.getPercentiles(), id, null)) .percentiles(lookupWithFallbackToAll(distribution.getPercentiles(), id, null))
.serviceLevelObjectives( .serviceLevelObjectives(
convertServiceLevelObjectives(id.getType(), lookup(distribution.getSlo(), id, null))) convertServiceLevelObjectives(id.getType(), lookup(distribution.getSlo(), id, null)))
.minimumExpectedValue( .minimumExpectedValue(
convertMeterValue(id.getType(), lookup(distribution.getMinimumExpectedValue(), id, null))) convertMeterValue(id.getType(), lookup(distribution.getMinimumExpectedValue(), id, null)))
.maximumExpectedValue( .maximumExpectedValue(
convertMeterValue(id.getType(), lookup(distribution.getMaximumExpectedValue(), id, null))) convertMeterValue(id.getType(), lookup(distribution.getMaximumExpectedValue(), id, null)))
.expiry(lookupWithFallbackToAll(distribution.getExpiry(), id, null)) .expiry(lookupWithFallbackToAll(distribution.getExpiry(), id, null))
.bufferLength(lookupWithFallbackToAll(distribution.getBufferLength(), id, null)).build().merge(config); .bufferLength(lookupWithFallbackToAll(distribution.getBufferLength(), id, null))
.build()
.merge(config);
} }
private double[] convertServiceLevelObjectives(Meter.Type meterType, ServiceLevelObjectiveBoundary[] slo) { private double[] convertServiceLevelObjectives(Meter.Type meterType, ServiceLevelObjectiveBoundary[] slo) {
if (slo == null) { if (slo == null) {
return null; return null;
} }
double[] converted = Arrays.stream(slo).map((candidate) -> candidate.getValue(meterType)) double[] converted = Arrays.stream(slo)
.filter(Objects::nonNull).mapToDouble(Double::doubleValue).toArray(); .map((candidate) -> candidate.getValue(meterType))
.filter(Objects::nonNull)
.mapToDouble(Double::doubleValue)
.toArray();
return (converted.length != 0) ? converted : null; return (converted.length != 0) ? converted : null;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -68,7 +68,7 @@ class CacheMetricsRegistrarConfiguration {
private void bindCacheManagerToRegistry(String beanName, CacheManager cacheManager) { private void bindCacheManagerToRegistry(String beanName, CacheManager cacheManager) {
cacheManager.getCacheNames() cacheManager.getCacheNames()
.forEach((cacheName) -> bindCacheToRegistry(beanName, cacheManager.getCache(cacheName))); .forEach((cacheName) -> bindCacheToRegistry(beanName, cacheManager.getCache(cacheName)));
} }
private void bindCacheToRegistry(String beanName, Cache cache) { private void bindCacheToRegistry(String beanName, Cache cache) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -40,7 +40,7 @@ class OnMetricsExportEnabledCondition extends SpringBootCondition {
@Override @Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotationAttributes annotationAttributes = AnnotationAttributes AnnotationAttributes annotationAttributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(ConditionalOnEnabledMetricsExport.class.getName())); .fromMap(metadata.getAnnotationAttributes(ConditionalOnEnabledMetricsExport.class.getName()));
String endpointName = annotationAttributes.getString("value"); String endpointName = annotationAttributes.getString("value");
ConditionOutcome outcome = getProductOutcome(context, endpointName); ConditionOutcome outcome = getProductOutcome(context, endpointName);
if (outcome != null) { if (outcome != null) {
@ -55,7 +55,7 @@ class OnMetricsExportEnabledCondition extends SpringBootCondition {
if (environment.containsProperty(enabledProperty)) { if (environment.containsProperty(enabledProperty)) {
boolean match = environment.getProperty(enabledProperty, Boolean.class, true); boolean match = environment.getProperty(enabledProperty, Boolean.class, true);
return new ConditionOutcome(match, ConditionMessage.forCondition(ConditionalOnEnabledMetricsExport.class) return new ConditionOutcome(match, ConditionMessage.forCondition(ConditionalOnEnabledMetricsExport.class)
.because(enabledProperty + " is " + match)); .because(enabledProperty + " is " + match));
} }
return null; return null;
} }
@ -70,7 +70,7 @@ class OnMetricsExportEnabledCondition extends SpringBootCondition {
private ConditionOutcome getDefaultOutcome(ConditionContext context) { private ConditionOutcome getDefaultOutcome(ConditionContext context) {
boolean match = Boolean.parseBoolean(context.getEnvironment().getProperty(DEFAULT_PROPERTY_NAME, "true")); boolean match = Boolean.parseBoolean(context.getEnvironment().getProperty(DEFAULT_PROPERTY_NAME, "true"));
return new ConditionOutcome(match, ConditionMessage.forCondition(ConditionalOnEnabledMetricsExport.class) return new ConditionOutcome(match, ConditionMessage.forCondition(ConditionalOnEnabledMetricsExport.class)
.because(DEFAULT_PROPERTY_NAME + " is considered " + match)); .because(DEFAULT_PROPERTY_NAME + " is considered " + match));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,9 +64,11 @@ public class AppOpticsMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public AppOpticsMeterRegistry appOpticsMeterRegistry(AppOpticsConfig config, Clock clock) { public AppOpticsMeterRegistry appOpticsMeterRegistry(AppOpticsConfig config, Clock clock) {
return AppOpticsMeterRegistry.builder(config).clock(clock).httpClient( return AppOpticsMeterRegistry.builder(config)
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout())) .clock(clock)
.build(); .httpClient(
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))
.build();
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,9 +64,11 @@ public class DatadogMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DatadogMeterRegistry datadogMeterRegistry(DatadogConfig datadogConfig, Clock clock) { public DatadogMeterRegistry datadogMeterRegistry(DatadogConfig datadogConfig, Clock clock) {
return DatadogMeterRegistry.builder(datadogConfig).clock(clock).httpClient( return DatadogMeterRegistry.builder(datadogConfig)
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout())) .clock(clock)
.build(); .httpClient(
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))
.build();
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,9 +64,11 @@ public class DynatraceMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DynatraceMeterRegistry dynatraceMeterRegistry(DynatraceConfig dynatraceConfig, Clock clock) { public DynatraceMeterRegistry dynatraceMeterRegistry(DynatraceConfig dynatraceConfig, Clock clock) {
return DynatraceMeterRegistry.builder(dynatraceConfig).clock(clock).httpClient( return DynatraceMeterRegistry.builder(dynatraceConfig)
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout())) .clock(clock)
.build(); .httpClient(
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))
.build();
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -73,9 +73,11 @@ public class ElasticMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ElasticMeterRegistry elasticMeterRegistry(ElasticConfig elasticConfig, Clock clock) { public ElasticMeterRegistry elasticMeterRegistry(ElasticConfig elasticConfig, Clock clock) {
return ElasticMeterRegistry.builder(elasticConfig).clock(clock).httpClient( return ElasticMeterRegistry.builder(elasticConfig)
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout())) .clock(clock)
.build(); .httpClient(
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))
.build();
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,9 +64,11 @@ public class HumioMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public HumioMeterRegistry humioMeterRegistry(HumioConfig humioConfig, Clock clock) { public HumioMeterRegistry humioMeterRegistry(HumioConfig humioConfig, Clock clock) {
return HumioMeterRegistry.builder(humioConfig).clock(clock).httpClient( return HumioMeterRegistry.builder(humioConfig)
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout())) .clock(clock)
.build(); .httpClient(
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))
.build();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,9 +64,11 @@ public class InfluxMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public InfluxMeterRegistry influxMeterRegistry(InfluxConfig influxConfig, Clock clock) { public InfluxMeterRegistry influxMeterRegistry(InfluxConfig influxConfig, Clock clock) {
return InfluxMeterRegistry.builder(influxConfig).clock(clock).httpClient( return InfluxMeterRegistry.builder(influxConfig)
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout())) .clock(clock)
.build(); .httpClient(
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))
.build();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -64,9 +64,11 @@ public class KairosMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public KairosMeterRegistry kairosMeterRegistry(KairosConfig kairosConfig, Clock clock) { public KairosMeterRegistry kairosMeterRegistry(KairosConfig kairosConfig, Clock clock) {
return KairosMeterRegistry.builder(kairosConfig).clock(clock).httpClient( return KairosMeterRegistry.builder(kairosConfig)
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout())) .clock(clock)
.build(); .httpClient(
new HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))
.build();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -81,8 +81,10 @@ public class NewRelicMetricsExportAutoConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
public NewRelicMeterRegistry newRelicMeterRegistry(NewRelicConfig newRelicConfig, Clock clock, public NewRelicMeterRegistry newRelicMeterRegistry(NewRelicConfig newRelicConfig, Clock clock,
NewRelicClientProvider newRelicClientProvider) { NewRelicClientProvider newRelicClientProvider) {
return NewRelicMeterRegistry.builder(newRelicConfig).clock(clock).clientProvider(newRelicClientProvider) return NewRelicMeterRegistry.builder(newRelicConfig)
.build(); .clock(clock)
.clientProvider(newRelicClientProvider)
.build();
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -95,7 +95,7 @@ public class DataSourcePoolMetricsAutoConfiguration {
Collection<DataSourcePoolMetadataProvider> metadataProviders, MeterRegistry registry) { Collection<DataSourcePoolMetadataProvider> metadataProviders, MeterRegistry registry) {
String dataSourceName = getDataSourceName(beanName); String dataSourceName = getDataSourceName(beanName);
new DataSourcePoolMetrics(dataSource, metadataProviders, dataSourceName, Collections.emptyList()) new DataSourcePoolMetrics(dataSource, metadataProviders, dataSourceName, Collections.emptyList())
.bindTo(registry); .bindTo(registry);
} }
/** /**

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -98,8 +98,8 @@ public class MongoMetricsAutoConfiguration {
MongoClientSettingsBuilderCustomizer mongoMetricsConnectionPoolListenerClientSettingsBuilderCustomizer( MongoClientSettingsBuilderCustomizer mongoMetricsConnectionPoolListenerClientSettingsBuilderCustomizer(
MongoMetricsConnectionPoolListener mongoMetricsConnectionPoolListener) { MongoMetricsConnectionPoolListener mongoMetricsConnectionPoolListener) {
return (clientSettingsBuilder) -> clientSettingsBuilder return (clientSettingsBuilder) -> clientSettingsBuilder
.applyToConnectionPoolSettings((connectionPoolSettingsBuilder) -> connectionPoolSettingsBuilder .applyToConnectionPoolSettings((connectionPoolSettingsBuilder) -> connectionPoolSettingsBuilder
.addConnectionPoolListener(mongoMetricsConnectionPoolListener)); .addConnectionPoolListener(mongoMetricsConnectionPoolListener));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -78,7 +78,8 @@ public class HibernateMetricsAutoConfiguration implements SmartInitializingSingl
String entityManagerFactoryName = getEntityManagerFactoryName(beanName); String entityManagerFactoryName = getEntityManagerFactoryName(beanName);
try { try {
new HibernateMetrics(entityManagerFactory.unwrap(SessionFactory.class), entityManagerFactoryName, new HibernateMetrics(entityManagerFactory.unwrap(SessionFactory.class), entityManagerFactoryName,
Collections.emptyList()).bindTo(registry); Collections.emptyList())
.bindTo(registry);
} }
catch (PersistenceException ex) { catch (PersistenceException ex) {
// Continue // Continue

@ -93,7 +93,8 @@ class ObservationRegistryConfigurer {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void customize(ObservationRegistry registry) { private void customize(ObservationRegistry registry) {
LambdaSafe.callbacks(ObservationRegistryCustomizer.class, asOrderedList(this.customizers), registry) LambdaSafe.callbacks(ObservationRegistryCustomizer.class, asOrderedList(this.customizers), registry)
.withLogger(ObservationRegistryConfigurer.class).invoke((customizer) -> customizer.customize(registry)); .withLogger(ObservationRegistryConfigurer.class)
.invoke((customizer) -> customizer.customize(registry));
} }
private <T> List<T> asOrderedList(ObjectProvider<T> provider) { private <T> List<T> asOrderedList(ObjectProvider<T> provider) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -74,7 +74,7 @@ public class HttpClientObservationsAutoConfiguration {
String name = (observationName != null) ? observationName : metricName; String name = (observationName != null) ? observationName : metricName;
MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter( MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter(
() -> "Reached the maximum number of URI tags for '%s'. Are you using 'uriVariables'?" () -> "Reached the maximum number of URI tags for '%s'. Are you using 'uriVariables'?"
.formatted(name)); .formatted(name));
return MeterFilter.maximumAllowableTags(name, "uri", clientProperties.getMaxUriTags(), denyFilter); return MeterFilter.maximumAllowableTags(name, "uri", clientProperties.getMaxUriTags(), denyFilter);
} }

@ -246,8 +246,10 @@ public final class EndpointRequest {
} }
private String toString(List<Object> endpoints, String emptyValue) { private String toString(List<Object> endpoints, String emptyValue) {
return (!endpoints.isEmpty()) ? endpoints.stream().map(this::getEndpointId).map(Object::toString) return (!endpoints.isEmpty()) ? endpoints.stream()
.collect(Collectors.joining(", ", "[", "]")) : emptyValue; .map(this::getEndpointId)
.map(Object::toString)
.collect(Collectors.joining(", ", "[", "]")) : emptyValue;
} }
private EndpointId getEndpointId(Object source) { private EndpointId getEndpointId(Object source) {

@ -250,8 +250,9 @@ public final class EndpointRequest {
private List<RequestMatcher> getDelegateMatchers(RequestMatcherFactory requestMatcherFactory, private List<RequestMatcher> getDelegateMatchers(RequestMatcherFactory requestMatcherFactory,
RequestMatcherProvider matcherProvider, Set<String> paths) { RequestMatcherProvider matcherProvider, Set<String> paths) {
return paths.stream().map((path) -> requestMatcherFactory.antPath(matcherProvider, path, "/**")) return paths.stream()
.collect(Collectors.toCollection(ArrayList::new)); .map((path) -> requestMatcherFactory.antPath(matcherProvider, path, "/**"))
.collect(Collectors.toCollection(ArrayList::new));
} }
@Override @Override
@ -261,8 +262,10 @@ public final class EndpointRequest {
} }
private String toString(List<Object> endpoints, String emptyValue) { private String toString(List<Object> endpoints, String emptyValue) {
return (!endpoints.isEmpty()) ? endpoints.stream().map(this::getEndpointId).map(Object::toString) return (!endpoints.isEmpty()) ? endpoints.stream()
.collect(Collectors.joining(", ", "[", "]")) : emptyValue; .map(this::getEndpointId)
.map(Object::toString)
.collect(Collectors.joining(", ", "[", "]")) : emptyValue;
} }
private EndpointId getEndpointId(Object source) { private EndpointId getEndpointId(Object source) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -62,8 +62,8 @@ public class StartupEndpointAutoConfiguration {
ConditionMessage.Builder message = ConditionMessage.forCondition("ApplicationStartup"); ConditionMessage.Builder message = ConditionMessage.forCondition("ApplicationStartup");
ApplicationStartup applicationStartup = context.getBeanFactory().getApplicationStartup(); ApplicationStartup applicationStartup = context.getBeanFactory().getApplicationStartup();
if (applicationStartup instanceof BufferingApplicationStartup) { if (applicationStartup instanceof BufferingApplicationStartup) {
return ConditionOutcome.match( return ConditionOutcome
message.because("configured applicationStartup is of type BufferingApplicationStartup.")); .match(message.because("configured applicationStartup is of type BufferingApplicationStartup."));
} }
return ConditionOutcome.noMatch(message.because("configured applicationStartup is of type " return ConditionOutcome.noMatch(message.because("configured applicationStartup is of type "
+ applicationStartup.getClass() + ", expected BufferingApplicationStartup.")); + applicationStartup.getClass() + ", expected BufferingApplicationStartup."));

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -101,9 +101,13 @@ public class BraveAutoConfiguration {
List<TracingCustomizer> tracingCustomizers, CurrentTraceContext currentTraceContext, List<TracingCustomizer> tracingCustomizers, CurrentTraceContext currentTraceContext,
Factory propagationFactory, Sampler sampler) { Factory propagationFactory, Sampler sampler) {
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME); String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
Builder builder = Tracing.newBuilder().currentTraceContext(currentTraceContext).traceId128Bit(true) Builder builder = Tracing.newBuilder()
.supportsJoin(false).propagationFactory(propagationFactory).sampler(sampler) .currentTraceContext(currentTraceContext)
.localServiceName(applicationName); .traceId128Bit(true)
.supportsJoin(false)
.propagationFactory(propagationFactory)
.sampler(sampler)
.localServiceName(applicationName);
spanHandlers.forEach(builder::addSpanHandler); spanHandlers.forEach(builder::addSpanHandler);
for (TracingCustomizer tracingCustomizer : tracingCustomizers) { for (TracingCustomizer tracingCustomizer : tracingCustomizers) {
tracingCustomizer.customize(builder); tracingCustomizer.customize(builder);
@ -234,7 +238,8 @@ public class BraveAutoConfiguration {
List<String> correlationFields = this.tracingProperties.getBaggage().getCorrelation().getFields(); List<String> correlationFields = this.tracingProperties.getBaggage().getCorrelation().getFields();
for (String field : correlationFields) { for (String field : correlationFields) {
builder.add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(BaggageField.create(field)) builder.add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(BaggageField.create(field))
.flushOnUpdate().build()); .flushOnUpdate()
.build());
} }
}; };
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -92,8 +92,10 @@ public class OpenTelemetryAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider, ContextPropagators contextPropagators) { OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider, ContextPropagators contextPropagators) {
return OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).setPropagators(contextPropagators) return OpenTelemetrySdk.builder()
.build(); .setTracerProvider(sdkTracerProvider)
.setPropagators(contextPropagators)
.build();
} }
@Bean @Bean
@ -101,8 +103,9 @@ public class OpenTelemetryAutoConfiguration {
SdkTracerProvider otelSdkTracerProvider(Environment environment, ObjectProvider<SpanProcessor> spanProcessors, SdkTracerProvider otelSdkTracerProvider(Environment environment, ObjectProvider<SpanProcessor> spanProcessors,
Sampler sampler) { Sampler sampler) {
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME); String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
SdkTracerProviderBuilder builder = SdkTracerProvider.builder().setSampler(sampler) SdkTracerProviderBuilder builder = SdkTracerProvider.builder()
.setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName))); .setSampler(sampler)
.setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName)));
spanProcessors.orderedStream().forEach(builder::addSpanProcessor); spanProcessors.orderedStream().forEach(builder::addSpanProcessor);
return builder.build(); return builder.build();
} }
@ -124,9 +127,11 @@ public class OpenTelemetryAutoConfiguration {
SpanProcessor otelSpanProcessor(ObjectProvider<SpanExporter> spanExporters, SpanProcessor otelSpanProcessor(ObjectProvider<SpanExporter> spanExporters,
ObjectProvider<SpanExportingPredicate> spanExportingPredicates, ObjectProvider<SpanReporter> spanReporters, ObjectProvider<SpanExportingPredicate> spanExportingPredicates, ObjectProvider<SpanReporter> spanReporters,
ObjectProvider<SpanFilter> spanFilters) { ObjectProvider<SpanFilter> spanFilters) {
return BatchSpanProcessor.builder(new CompositeSpanExporter(spanExporters.orderedStream().toList(), return BatchSpanProcessor
spanExportingPredicates.orderedStream().toList(), spanReporters.orderedStream().toList(), .builder(new CompositeSpanExporter(spanExporters.orderedStream().toList(),
spanFilters.orderedStream().toList())).build(); spanExportingPredicates.orderedStream().toList(), spanReporters.orderedStream().toList(),
spanFilters.orderedStream().toList()))
.build();
} }
@Bean @Bean

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save